我看不到以下宏在做什么?如果有人可以帮助我看到它,将不胜感激。

#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的数据块,属于C的数据块以及特定于A的数据。由于至少一个基数的数据的地址不能为与整个类实例的地址相同,传递给不同方法的this指针的数值需要变化。宏检索差值。

编辑:按照惯例,指向vtable的指针是具有虚函数的任何类中的第一个数据成员。因此,通过查找基础数据的地址,可以找到其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/

10-09 05:57