随笔-14  评论-8  文章-0  trackbacks-0

      这几个 offset 是:

      c 中的 offsetof 宏;

      《COM本质论》: "inttable.h" 中的 BASE_OFFSET

      和 This() (它用到了 offsetof,权且当做是一个 packaged offset 吧)。

      先定义一些辅助类:

struct IX {
    virtual void fx() = 0;
};
struct IY {
    virtual void fy() = 0;
};
class CA : public IX,
           public IY {
public:
    virtual void fx() { cout << "CA::fx()" << endl; };
    virtual void fy() { cout << "CA::fy()" << endl; };

    struct Inner {
        CA* This() { return (CA*)((char*)this - offsetof(CA, m_inner)); }
    };
    Inner m_inner;
};

      先看 offsetof :

#define offsetof(s,m)   (size_t)&reinterpret_cast<const volatile char&>((((s *)0)->m))
    工作原理大体同下图所示,其值就是 a – 0 = a ,即 m 被映射后的地址。所以一个 –> 操作就可以搞定。
offset 
    再看 BASE_OFFSET :
#define BASE_OFFSET(ClassName, BaseName) \
    (DWORD(static_cast<BaseName*>(reinterpret_cast<ClassName*>(0x10000000))) - 0x10000000)

    对于先前的定义,有:

DWORD disX = BASE_OFFSET(CA, IX);
DWORD disY = BASE_OFFSET(CA, IY);
cout << disX << endl    // 0
      
<< disY << endl;   // 4

    这个宏主要利用了派生类指针到基类指针的转换,这一切由语言内置的转换符完成。在 ATL 中相应的定义是:

#define offsetofclass(base, derived) ((DWORD_PTR)(static_cast<base*>((derived*)_ATL_PACKING))-_ATL_PACKING)

    其中 _ATL_PACKING 的值为 8 。为什么使用这两个值呢,我不知道。网上有说是为了避免 NULL 指针和负值,我暂时不能够理解。

    最后来看 This() :

CA* This() { return (CA*)((BYTE*)this - offsetof(CA, Inner)); }
    This() 返回的即是指向 CA 的指针,如: ca.m_inner.This()->fx(); 有了上面两个 offset ,这个就不难理解了。
    整理完毕。
posted on 2009-12-12 15:16 崇文 阅读(405) 评论(0)  编辑 收藏 引用

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理