派生类如何在编译时无法解析其基类的成员?

时间:2012-02-17 05:49:23

标签: c++ class inheritance

考虑以下代码:

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; } 

如果程序有一个指向虚拟基类的指针,怎么能在编译时解析该成员的内存地址?据我所知,当创建每个派生类对象时,每个对象的内存布局包括:

  • 基类中的所有成员
  • 虚拟指针(虚拟析构函数)
  • 指向派生对象的虚拟基类的指针
  • 派生类对象的所有成员。

因此,找到基类成员应该只是从派生类对象的起始地址找到正确的偏移量。但为什么不能解决呢?

1 个答案:

答案 0 :(得分:1)

关键是X基类A 虚拟,因此A还不知道实际是谁基类将是。在这种情况下,实际的基础子对象将仅由最终派生对象C确定。换句话说,实际的基础子对象取决于*p的动态类型,不能静态决定。

想象一下,您有另一个class C2 : A, B, A2, B2,其中A2B2相似。您也可以使用指向foo的指针调用C2,现在基地X可能位于其他位置。