C++ 这是什么c++;宏在做什么?

C++ 这是什么c++;宏在做什么?,c++,macros,C++,Macros,我看不出下面的宏在做什么?如果有人能帮我看一下,我将不胜感激 #define BASE_OFFSET(ClassName,BaseName)\ (DWORD(static_cast < BaseName* >( reinterpret_cast\ < ClassName* >(Ox10000000)))-Ox10000000) #定义基本偏移量(类名称、基本名称)\ (DWORD(静态播放(重新解释播放)\ (OX1000000))-OX1000000) 如果有人想知

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

#define BASE_OFFSET(ClassName,BaseName)\
(DWORD(static_cast < BaseName* >( reinterpret_cast\
< ClassName* >(Ox10000000)))-Ox10000000)
#定义基本偏移量(类名称、基本名称)\
(DWORD(静态播放<基本名称*>(重新解释播放)\
(OX1000000))-OX1000000)
如果有人想知道它是从哪里来的,它来自Don Box Book Essential COM的第三章,他正在使用接口表构建一个QueryInterface函数,而上面的宏不知何故用于查找指向类的接口vtable的指针,其中class是实现BaseName的类名,虽然我不知道它是怎么做到的

它告诉编译器:“假设在0x10000000处有一个
ClassName
对象。相对于0x10000000,
BaseName
数据在该对象中从何处开始?”

设想一个具有多个基的类对象的内存布局:

class A: B, C{};
在构成A对象的内存块中,有属于B的数据块,也有属于C的数据块,以及特定于A的数据块。由于至少一个基数据的地址不能与类实例的地址作为一个整体相同,传递给不同方法的
指针的数值需要不同。宏检索差异的值

编辑:根据惯例,指向vtable的指针是任何具有虚拟函数的类中的第一个数据成员。因此,通过查找基本数据的地址,就可以找到其vtable指针的地址

现在,关于类型转换。通常,当您对指针进行类型转换时,操作在内部是微不足道的——地址的数值并不取决于它所指向的类型;数据类型的概念只存在于C级别。不过有一个重要的例外——当您使用多重继承强制转换对象指针时。正如我们刚才讨论的,您需要传递给基类方法的
这个
指针可能在数值上与派生对象的指针不同

因此,静态_cast和重新解释_cast之间的区别巧妙地抓住了这一差异。当您使用reinterpret_cast时,您告诉编译器:“我知道得更清楚。把这个数值解释为指向我所说内容的指针。”。这是一个蓄意颠覆的类型系统,危险,但偶尔必要。根据定义,这种演员阵容是微不足道的——因为你这么说

我所说的“平凡”是指指针的数值不会改变

静态_cast是一种更高级的构造。在这种特殊情况下,您将在对象与其基础之间进行强制转换。在C++类规则下,这是一个合理的、安全的转换,但是它可能在数值上是非平凡的。这就是宏使用两种不同类型转换的原因。静态_cast不违反类型系统

重述:

reinterpret_cast<ClassName* >(OxlOOOOOOO)
这是纯粹的算术。这就是不安全性的双重作用:我们没有将指针用作指针,而是将其转换回整数,而忘记了它曾经是指针

最后一个阶段可以等效地重新表述为:

((char*)(...)-(char*)OxlOOOOOOO)
如果这更有意义的话。

它告诉编译器:“假设在0x10000000处有一个
ClassName
对象。相对于0x10000000,
BaseName
数据从该对象的哪里开始?”

设想一个具有多个基的类对象的内存布局:

class A: B, C{};
在构成A对象的内存块中,有属于B的数据块,也有属于C的数据块,以及特定于A的数据块。由于至少一个基数据的地址不能与类实例的地址作为一个整体相同,传递给不同方法的
指针的数值需要不同。宏检索差异的值

编辑:根据惯例,指向vtable的指针是任何具有虚拟函数的类中的第一个数据成员。因此,通过查找基本数据的地址,就可以找到其vtable指针的地址

现在,关于类型转换。通常,当您对指针进行类型转换时,操作在内部是微不足道的——地址的数值并不取决于它所指向的类型;数据类型的概念只存在于C级别。不过有一个重要的例外——当您使用多重继承强制转换对象指针时。正如我们刚才讨论的,您需要传递给基类方法的
这个
指针可能在数值上与派生对象的指针不同

因此,静态_cast和重新解释_cast之间的区别巧妙地抓住了这一差异。当您使用reinterpret_cast时,您告诉编译器:“我知道得更清楚。把这个数值解释为指向我所说内容的指针。”。这是一个蓄意颠覆的类型系统,危险,但偶尔必要。根据定义,这种演员阵容是微不足道的——因为你这么说

我所说的“平凡”是指指针的数值不会改变

静态_cast是一种更高级的构造。在这种特殊情况下,您将在对象与其基础之间进行强制转换。在C++类规则下,这是一个合理的、安全的转换,但是它可能在数值上是非平凡的。这就是宏使用两种不同类型转换的原因。静态_cast不违反类型系统

重述:

reinterpret_cast<ClassName* >(OxlOOOOOOO)
这是纯粹的算术。这就是不安全性的双重作用:我们没有将指针用作指针,而是将其转换回整数,而忘记了它曾经是指针

最后一个阶段可以等效地重新表述为:

((char*)(...)-(char*)OxlOOOOOOO)

如果这更有意义的话。

请注意神奇的0x10000000常量


如果该常量为0,GCC将显示warning-Winvalid offset of(当然,如果已启用)。也许其他编译器也会这样做。

请注意神奇的0x10000000常量

如果该常数为0,则GCC将为s