COM_INTERFACE_ENTRY 的 offsetofclass

hyifeng 2004-03-24 12:32:19
有看过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运算,而直接得到地址。
...全文
49 19 打赏 收藏 转发到动态 举报
写回复
用AI写文章
19 条回复
切换为时间正序
请发表友善的回复…
发表回复
hyifeng 2004-03-25
  • 打赏
  • 举报
回复
分数又丢失了,csdn怎么了!!
hyifeng 2004-03-25
  • 打赏
  • 举报
回复
有没有人再说一下,没有就结贴啦。

谢谢 XXandOO(麦猪) 和 ViaSant(ViaSant) 的热情帮助。
hyifeng 2004-03-25
  • 打赏
  • 举报
回复
哦,我明白 XXandOO(麦猪) 的意思,谢谢。
XXandOO 2004-03-25
  • 打赏
  • 举报
回复
这个问题有什么可较真儿的呢,addressofclass和offsetofclass的性能有差异吗,可以想象addressofclass就是把继承类指针加上了offsetofclass得到的一个偏移量,或使用类似的算法,这好比有人喜欢x += y,有人喜欢x = x + y。这只是ATL给出的多继承的一个默认实现,你觉得不好的话,接口映射表给你足够的灵活性实现你的实现(addressofclass)。
hyifeng 2004-03-25
  • 打赏
  • 举报
回复
其实 const 只能说明他是保持常量语义,并不一定是编译时静态值。

你可以试一下是不是。

hyifeng 2004-03-25
  • 打赏
  • 举报
回复
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条,第四条怎么也发不出。而一次全发也不行。只好这样了!
hyifeng 2004-03-25
  • 打赏
  • 举报
回复
谢谢 ViaSant(ViaSant),


这些已经想过了。
hyifeng 2004-03-24
  • 打赏
  • 举报
回复
#define addressofclass(base) ((DWORD)(static_cast<base*>(this))
ViaSant 2004-03-24
  • 打赏
  • 举报
回复
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指针;.... ....
ViaSant 2004-03-24
  • 打赏
  • 举报
回复
2. QueryInterface()实际调用的是AtlInternalQueryInterface();
由上面的代码可以知道pUnk是由pThis+偏移得到。注意,这里的偏移pEntries->dw和由offsetofclass实现填充的数据是相等的。
ViaSant 2004-03-24
  • 打赏
  • 举报
回复
AtlInternalQueryInterface()
{
..........
IUnknown* pUnk = (IUnknown*)((int)pThis+pEntries->dw);
..........
}
首先,offsetofclass目的是填充静态表格,供QueryInterface()用;
hyifeng 2004-03-24
  • 打赏
  • 举报
回复
不奇怪吗??我说的那个办法不是有缺陷的话,不会不用。

“不能说比你的方法差”,给个理由。
XXandOO 2004-03-24
  • 打赏
  • 举报
回复
我说有点儿道理,是说你的方法也是可以的,但不能说ATL的做法是错的,甚至不能说比你的方法差。
hyifeng 2004-03-24
  • 打赏
  • 举报
回复
毕竟这些东西都是经过高手考虑的,不会那么容易出错。
hyifeng 2004-03-24
  • 打赏
  • 举报
回复
我还是愿意我是考虑少了一些东西,
有没有人证明我是错的,
谢谢。
XXandOO 2004-03-24
  • 打赏
  • 举报
回复
看来还是有点儿道理的,不过也无大碍,对性能无甚影响
hyifeng 2004-03-24
  • 打赏
  • 举报
回复
我现在就是感觉疑惑,认为这个“查询接口时才和this指针一起算出基类地址”这一步可以通过直接写入地址而免去。
hyifeng 2004-03-24
  • 打赏
  • 举报
回复
这个接口映射表不是类成员,而是一个成员函数的静态数组。
看:
#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()时以对象构造完成了。
XXandOO 2004-03-24
  • 打赏
  • 举报
回复
在填充静态接口映射表时,人家只是在需要填充一个偏移量,在CoCreateInstance后查询接口时才和this指针一起算出基类地址,你这样用怎么使用静态的接口映射表?实例都没有,哪来的this呀?

3,245

社区成员

发帖
与我相关
我的任务
社区描述
ATL,Active Template Library活动(动态)模板库,是一种微软程序库,支持利用C++语言编写ASP代码以及其它ActiveX程序。
社区管理员
  • ATL/ActiveX/COM社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧