c++ - 这个c++宏在做什么?

标签 c++ macros

我没看到下面的宏在做什么?如果有人能帮我看看,我将不胜感激。

#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/

相关文章:

java - 我可以从经验丰富的 C++ 开发人员转为 Java 应用程序开发人员吗?

c++ - 为什么 CERT 标准 PRE00-CPP 说 "Avoid defining macros"

C++ Visual Studio "Disgusting Macro Hack"编译问题

c++ - 什么时候调用析构函数?

c++ - 我的 makefile 不工作

c++ - 对话框窗口中的 MFC 消息循环

c++ - 为什么大型本地数组会使我的程序崩溃,而全局数组却不会?

C - 参数化宏

c - 什么时候在 C 中发生宏替换

c - 通过将函数定义为空宏来在编译期间删除函数