考虑以下代码:
class X { public: int i; };
class A : public virtual X { public: int j; };
class B : public virtual X { public: double d; };
class C : public A, public B { public: int k; };
// cannot resolve location of pa->X::i at compile-time
void foo( const A* pa ) { pa->i = 1024; }
main() {
foo( new A );
foo( new C );
// ...
}
在“ Inside C ++对象模型”一书中,有人说:
编译器无法修复通过
X::i
访问的物理偏移量pa
内的foo()
,因为pa
的实际类型可能会因每个类型而异foo()'s
次调用。
因此,编译器必须创建如下内容:
// possible compiler transformation
void foo( const A* pa ) { pa->__vbcX->i = 1024; }
如果程序有一个指向虚拟基类的指针,怎么能在编译时解析该成员的内存地址?据我所知,当创建每个派生类对象时,每个对象的内存布局包括:
因此,找到基类成员应该只是从派生类对象的起始地址找到正确的偏移量。但为什么不能解决呢?
答案 0 :(得分:1)
关键是X
基类A
虚拟,因此A
还不知道实际是谁基类将是。在这种情况下,实际的基础子对象将仅由最终派生对象C
确定。换句话说,实际的基础子对象取决于*p
的动态类型,不能静态决定。
想象一下,您有另一个class C2 : A, B, A2, B2
,其中A2
和B2
相似。您也可以使用指向foo
的指针调用C2
,现在基地X
可能位于其他位置。