【问题标题】:How a derived class cannot resolved members of its base class at compile time?派生类如何在编译时无法解析其基类的成员?
【发布时间】:2012-03-08 13:50:20
【问题描述】:

考虑这段代码:

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++ object model》一书中说:

编译器无法修复通过X::i访问的物理偏移量 pafoo() 中,因为pa 的实际类型可能随每个 foo()'s 调用。

因此,编译器必须创建如下内容:

// possible compiler transformation 
void foo( const A* pa ) { pa->__vbcX->i = 1024; } 

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

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

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

【问题讨论】:

    标签: c++ class inheritance


    【解决方案1】:

    重点是基类X 相对于A虚拟,所以A 还不知道实际 基类是谁将会。实际的基础子对象将仅由最终派生对象确定,在这种情况下为C。也就是说,实际的基础子对象取决于*p的动态类型,不能静态决定。

    假设您有另一个class C2 : A, B, A2, B2,其中A2B2 相似。您也可以使用指向C2 的指针调用foo,现在基础X 可能在其他地方。

    【讨论】:

    • 我认为虚拟类是为了共享同一个基类子对象:http://www.learncpp.com/cpp-tutorial/118-virtual-base-classes/,并且首先在继承树中构造。如果根据文章,我认为C类的内存布局将是一个由X + A + B + C的内存布局组成的连续区域,在A的情况下是X + A。它怎么会有问题找到基地的成员?
    猜你喜欢
    • 2019-01-20
    • 2017-09-30
    • 2016-05-21
    • 2018-01-16
    • 2012-09-16
    • 2012-08-29
    • 2017-11-08
    • 2017-08-07
    相关资源
    最近更新 更多