(跟进:C++ pointer multi-inheritance fun)
我正在编写一些涉及从基本引用计数指针类继承的代码;并且出现了一些复杂的C ++。我把它减少如下:
假设我有:
class A{int x, y;};
class B{int xx, yy;};
class C: public A, public B {int z;};
C c;
C* pc = &c;
B* pb = &c;
A* pa = &c;
// does pa point to a valid A object?
// does pb point to a valid B object?
// does pa == pb ?
此外,确实:
// pc == (C*) pa ?
// pc == (C*) pb ?
谢谢!
此处,“==”表示相同值的点。
答案 0 :(得分:3)
但是你需要知道C ++如何组织内存。类的布局,CClass,如下:
offset
0 First base class in list of base classes
sizeof first base class Next base class
sizeof first N-1 base classes Nth base class
sizeof all base classes CClass
好吧,如果有一个继承树,它会比那更复杂,但你应该得到基本的想法。假设int是四个字节,那么C类的布局如下:
offset
0 A::x
4 A::y
8 B::xx
12 B::yy
16 C:z
但是C类型的对象都是上面的所有,所以指向C的指针指向偏移量0.但是,C ++允许隐式向下转换,因此指向C的指针可以转换为指向A的指针或者指向B的指针。但是如果你看一下上面的指针,指向B的指针是偏移8而不是0(指向C的指针),指向A的指针是偏移0的指针。所以,铸造一个指向C的指针指向B的指针将指针值加8。这是因为B的方法假设'this'指针指向B的第一个成员(B :: xx),但如果重新解释为指向B的指针(即值相同)则指向C的指针将是指针在B实际存在之前的8个字节的地址,以便所有B的方法都使用,在这个例子中是A的成员。
向上转播(最后两次转换)是不同的鱼。从指针到B到指向C的指针真的很难,因为你不知道指向B的指针是指向B的实例还是指向C的实例加8。这就是RTTI和动态强制转换的用武之地。启用RTTI(运行时类型信息)后,指向B的指针包含描述B实际上是什么的附加信息 - 一个简单的B或B作为C的一部分。这确实有额外的成本,执行时间和内存使用。
最后,这确实突出了C风格演员的模糊性。你真的应该使用C ++样式转换(static_cast<>等),因为这澄清了转换的方式。
* 这也可能是肯定的,我想这取决于编译器以及RTTI是打开还是关闭。您需要深入了解标准和编译器实现的细节。