有看过COM的表格驱动查找Interface的代码的朋友吗?
我有一个疑问,
#define offsetofclass(base, derived) ((DWORD)(static_cast<base*>((derived*)_ATL_PACKING))-_ATL_PACKING)
为什么不改为
#define addressofclass(base, derived) ((DWORD)(static_cast<base*>(this)) 这样不是不用做(char*)this + offsetofclass运算,而直接得到地址。

解决方案 »

  1.   

    #define addressofclass(base) ((DWORD)(static_cast<base*>(this))
      

  2.   

    在填充静态接口映射表时,人家只是在需要填充一个偏移量,在CoCreateInstance后查询接口时才和this指针一起算出基类地址,你这样用怎么使用静态的接口映射表?实例都没有,哪来的this呀?
      

  3.   

    这个接口映射表不是类成员,而是一个成员函数的静态数组。
    看:
    #define BEGIN_COM_MAP(x) public:  ... ...
    HRESULT _InternalQueryInterface(REFIID iid, void** ppvObject)  { return InternalQueryInterface(this, _GetEntries(), iid, ppvObject); }  const static _ATL_INTMAP_ENTRY* WINAPI _GetEntries() {  static const _ATL_INTMAP_ENTRY _entries[] = { DEBUG_QI_ENTRY(x)
    #define END_COM_MAP() {NULL, 0, 0}}; return &_entries[1];}  virtual ULONG STDMETHODCALLTYPE AddRef( void) = 0;  virtual ULONG STDMETHODCALLTYPE Release( void) = 0;  STDMETHOD(QueryInterface)(REFIID, void**) = 0;
    调用_GetEntries()时以对象构造完成了。
      

  4.   

    我现在就是感觉疑惑,认为这个“查询接口时才和this指针一起算出基类地址”这一步可以通过直接写入地址而免去。
      

  5.   

    我说有点儿道理,是说你的方法也是可以的,但不能说ATL的做法是错的,甚至不能说比你的方法差。
      

  6.   

    AtlInternalQueryInterface()
    {
       ..........
       IUnknown* pUnk = (IUnknown*)((int)pThis+pEntries->dw);
       ..........
    }
    首先,offsetofclass目的是填充静态表格,供QueryInterface()用;
      

  7.   

    2. QueryInterface()实际调用的是AtlInternalQueryInterface();
       由上面的代码可以知道pUnk是由pThis+偏移得到。注意,这里的偏移pEntries->dw和由offsetofclass实现填充的数据是相等的。
      

  8.   

    3. 分析offsetofclass:
      #define _ATL_PACKING 8//注意_ATL_PACKING 是一个常量。
      
      ((DWORD)(static_cast<base*>((derived*)_ATL_PACKING))-_ATL_PACKING)//
    这句语义是先将_ATL_PACKING强制转换为derived指针在转换为base指针,这时
    static_cast<base*>((derived*)_ATL_PACKING))就等于vptr的值了;然后减去_ATL_PACKING
    得到的是该vptr的偏移值,应为4的整数倍。4表示是第一个Interface指针;8表示是第2个Interface指针;....   ....
      

  9.   

    谢谢 ViaSant(ViaSant),
    这些已经想过了。
      

  10.   

    ViaSant(ViaSant) 说:
    在上面,对比一下虚拟函数表,就比较容易得到这个结论。虚拟函数表画起来不方便,自己看书吧。4. 用addressofclass,,它是在运行时刻产生的。宏展开后,结构的赋值为
        static const INTERFACE_ENTRY table[]={
        ... ...
        {IID_IXxxx,_SIMPLE/*有点记不清了*/,((DWORD)(static_cast<base*>(this))}
        ... ...
        {0,0,0}};
    注意到table为一个const指针,const要求table指向的对象为常量;而this为变量,与const语义冲突第一次来,不知道为什么只能发3条,第四条怎么也发不出。而一次全发也不行。只好这样了!
      

  11.   

    其实 const 只能说明他是保持常量语义,并不一定是编译时静态值。你可以试一下是不是。
      

  12.   

    这个问题有什么可较真儿的呢,addressofclass和offsetofclass的性能有差异吗,可以想象addressofclass就是把继承类指针加上了offsetofclass得到的一个偏移量,或使用类似的算法,这好比有人喜欢x += y,有人喜欢x = x + y。这只是ATL给出的多继承的一个默认实现,你觉得不好的话,接口映射表给你足够的灵活性实现你的实现(addressofclass)。
      

  13.   

    哦,我明白 XXandOO(麦猪) 的意思,谢谢。
      

  14.   

    有没有人再说一下,没有就结贴啦。谢谢 XXandOO(麦猪) 和 ViaSant(ViaSant) 的热情帮助。
      

  15.   

    分数又丢失了,csdn怎么了!!