C++ 虚拟继承内存布局

问题描述 投票:0回答:1

虚拟继承内存布局

我试图完全理解虚拟继承和vTables/vPtrs在内存中到底发生了什么。

我写了两个代码示例,我确切地理解它们工作的原因,但我只是想确保我心中对对象内存布局有正确的想法。

这里是图片中的两个示例,我只是想知道我对所涉及的内存布局的想法是否正确。

示例1:

class Top { public: int a;  };
class Left : public virtual Top {  public: int b; };
class Right : public virtual Top { public: int c; };
class Bottom : public Left, public Right { public:  int d; };

enter image description here

示例2:

与上面相同,但有:

class Right : public virtual Top {
public:
    int c;
    int a;  // <======= added this
};

enter image description here

c++ oop inheritance multiple-inheritance virtual-inheritance
1个回答
1
投票

C++ 标准没有对对象布局做太多说明。 虚拟函数表(vtable)和虚拟基指针甚至不是标准的一部分。所以问题和答案只能说明可能的实现。

快速查看您的绘图似乎显示了正确的布局。

您可能对这些进一步的参考资料感兴趣:

  • 多重继承被认为有用一篇关于多重继承和虚拟继承情况下布局的ddj文章。

  • 微软专利描述了vfptr(虚拟函数表,又名vtables)和vbptr(虚拟基指针)的使用。

编辑:Bottom继承
Right::a
还是
Left::a

在您的 测试 2 中,

Right
Left
共享同一个共同的父级
Top
。 因此
Top
内只有一个子对象
Bottom
,因此,也只有一个且相同的
Top::a

有趣的是,您在测试 2 中引入了

a
中的成员
Right
。 这是一个
a
,与继承自
a
Top
不同。它是一个独特的成员,只是“巧合”地与另一个成员同名。 因此,如果您通过
a
访问
Right
Right::a
会隐藏
Top::a
(顺便说一句,这也是
Bottom::Top::a
Right::Top::a
Left::Top::a
)。 在本例中,bottom.a 表示 Right::a,不是因为对象布局,而是因为名称查找(和隐藏)规则。 这不依赖于实现:它是标准的且可移植的。

这里有一个测试 2 的变体来演示这种情况:

int main() {
    Bottom bottom; 
    bottom.a = 7; 
    cout << bottom.Top::a << endl << bottom.Left::Top::a << endl;
    cout << bottom.Right::Top::a << endl << bottom.Left::a << endl;
    cout << bottom.Right::a << endl <<endl;
    bottom.Right::a = 4; 
    bottom.Left::a = 3; 
    cout << bottom.Top::a << endl << bottom.Left::Top::a << endl;
    cout << bottom.Right::Top::a << endl << bottom.Left::a << endl;
    cout << bottom.Right::a << endl <<endl;

    cout << "And the addresses are: " << endl; 
    cout << " Bottom:       " << (void*)&bottom << endl; 
    cout << " Top:          " << (void*)static_cast<Top*>(&bottom) << endl;
    cout << " Left:         " << (void*)static_cast<Left*>(&bottom) << endl;
    cout << " Right:        " << (void*)static_cast<Right*>(&bottom) << endl;
    cout << " Top::a:       " << (void*)&bottom.Top::a << endl;
    cout << " Left::Top::a: " << (void*)&bottom.Left::Top::a << endl;
    cout << " Right::Top::a:" << (void*)&bottom.Right::Top::a << endl;
    cout << " Left::a:      " << (void*)&bottom.Left::a << endl;
    cout << " Right::a:     " << (void*)&bottom.Right::a << endl;
}; 
© www.soinside.com 2019 - 2024. All rights reserved.