我没看到下面的宏在做什么?如果有人能帮我看看,我将不胜感激。
#define BASE_OFFSET(ClassName,BaseName)\
(DWORD(static_cast < BaseName* >( reinterpret_cast\
< ClassName* >(Ox10000000)))-Ox10000000)
如果有人想知道它的来源,它来自 Don Box Book Essential COM 的第 3 章,他正在使用接口(interface)表构建一个 QueryInterface 函数,并且上面的宏以某种方式用于查找指向的指针类的接口(interface) vtable,其中 class 是实现 BaseName 的 ClassName,尽管我不知道它是如何做到的。
最佳答案
它告诉编译器:“假设在 0x10000000 处有一个 ClassName
对象。相对于 0x10000000,BaseName
数据将从该对象的何处开始”?
想一想具有多个基类的类对象的内存布局:
class A: B, C{};
在构成A对象的内存块中,既有属于B的数据 block ,也有属于C的数据 block ,以及A特有的数据。由于至少有一个基地址data 不能与类实例整体的地址相同,传递给不同方法的 this
指针的数值需要不同。宏检索差值。
编辑:按照惯例,指向虚表的指针是任何具有虚函数的类中的第一个数据成员。因此,通过查找基础数据的地址,可以找到其 vtable 指针的地址。
现在,关于类型转换。通常,当您对指针进行类型转换时,操作在内部是微不足道的——地址的数值不依赖于它指向的类型;数据类型的概念只存在于 C 级别。但是有一个重要的异常(exception) - 当您使用多重继承强制转换对象指针时。正如我们刚刚讨论的那样,您需要传递给基类方法的 this
指针在数值上可能与派生对象的指针不同。
所以 static_cast 和 reinterpret_cast 之间的区别巧妙地捕捉到了这种差异。当您使用 reinterpret_cast 时,您是在告诉编译器:“我知道得更多。取这个数值并将其解释为指向我所说内容的指针”。这是对类型系统的蓄意颠覆,危险,但偶尔是必要的。根据定义,这种类型的转换是微不足道的 - 因为你这么说。
我的意思是“微不足道”——指针的数值不会改变。
static_cast 是一个更高级别的结构。在这种特殊情况下,您将在一个对象及其基础之间进行转换。在 C++ 类规则下,这是一个合理、安全的转换——但它在数值上可能是不平凡的。这就是宏使用两种不同类型转换的原因。 static_cast 不违反类型系统。
回顾一下:
reinterpret_cast<ClassName* >(OxlOOOOOOO)
是不安全的操作。它返回一个指向虚假对象的虚假指针,但没关系,因为我们从不取消引用它。
static_cast<BaseName*>(...)
是安全操作(具有不安全指针,具有讽刺意味)。这是发生非平凡指针类型转换的部分。
(DWORD(...)-OxlOOOOOOO)
是纯算术。这就是不安全性加倍的地方:我们没有将指针用作指针,而是将其转换回整数并忘记它曾经是一个指针。
最后一个阶段可以等效地改写为:
((char*)(...)-(char*)OxlOOOOOOO)
如果这样更有意义。
关于c++ - 这个c++宏在做什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11637970/