在浏览此 C++ 常见问题解答时 https://isocpp.org/wiki/faq/mixing-c-and-cpp#cpp-objs-passed-to-c我遇到了语句
Most C++ compilers use a binary object layout that causes this conversion to happen with multiple inheritance and/or virtual inheritance.
我无法理解它的含义和应用。根据 C++ FAQ,此对象布局机制有助于 C++ 编译器进行以下检查
In C++ it is easy to check if a Derived* called dp points to the same object as is pointed to by a Base* called bp: just say if (dp == bp) .... The C++ compiler automatically converts both pointers to the same type, in this case to Base*, then compares them. Depending on the C++ compiler’s implementation details, this conversion sometimes changes the bits of a pointer’s value.
任何人都可以帮助理解任何流行的 C++ 编译器的二进制对象布局,以及指针值的位变化的可能变化和相应机制。以及它如何帮助比较基类/派生类的指针。
编辑:请解释为什么下面的陈述也是有效的。
NOTE: you must be especially careful when converting both to void* since that conversion will not allow either the C or C++ compiler to do the proper pointer adjustments! The comparison (x == y) might be false even if (b == d) is true:
最佳答案
在此上下文中,“二进制对象布局”是指“包含对象的二进制数据如何在内存中布局。”
考虑这个 C++ 代码:
struct Left
{
int ll;
};
struct Right
{
int rr;
};
struct Derived : Left, Right
{
int dd;
};
在内存中组织这些(概念上)的一种可能方法如下:
+ Derived ----------------+
| + Left + + Right + |
| | ll | | rr | dd |
| +------+ +-------+ |
+-------------------------+
当然,这个类只有3个int
,所以有了上面的概念布局,真正的布局应该是这样的:
+ Derived------+
| ll | rr | dd |
+--------------+
现在想象一下这段代码:
Derived d;
Dervied *pd = &d;
Left *pl = &d;
Right *pr = &d;
pd
指向d
的开始,与它的ll
成员的开始相同。
pl
将指向 d
的 Left
子对象。 Left
的开始是 ll
成员的开始。比较pl == pd
时,pd
需要转换为类型Left*
。请记住,pd
已经指向 ll
的开始,因此不需要更改 pd
的值。这纯粹是一种概念转换(类型的改变)。
pr
指向 d
的 Right
子对象。由于 Right
对象以 rr
成员开头,因此 pr
指向 rr
。同样,执行 pr == pd
需要将 pd
转换为类型 Right*
。 d
的Right
子对象以rr
成员开头,但是pd
指向的地址ll
成员。因此,pd
的值(= 位)必须通过此转换更改(增加一个 int
的大小)以指向 rr
代替。实际上,在将 &d
从 Derived*
转换为 Right*
以初始化 pr
时,这个转换已经发生过一次与它。
这也应该解释为什么在 void*
类型中比较不起作用。显然,&d.ll != &d.rr
,即使 pl == pr
。
关于c++ - "C++ compilers use a binary object layout"这句话的含义和用途是什么,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29144356/