我试图通过虚拟继承和vTables / vPtrs来完全理解内存中发生的事情,而不是。
我有两个我编写的代码示例,我完全理解它们的工作原理,但我只是想确保在脑海中对对象内存布局有正确的想法。
Here是图片中的两个示例,我只想知道我对所涉及的内存布局的想法是否正确。
示例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; };
示例2:
与上述相同,但是:
class Right : public virtual Top {
public:
int c;
int a; // <======= added this
};
答案 0 :(得分:0)
C ++标准并没有对对象布局说太多。虚函数表(vtable)和虚拟基指针甚至不是标准的一部分。所以问题和asnwers只能说明可能的实现。
快速查看图形似乎显示正确的布局。
您可能会对这些进一步的参考感兴趣:
Multiple Inheritance Considered Useful一篇关于多重继承和虚拟继承的布局的ddj文章。
Microsoft patent描述了vfptr(虚函数表,又名vtables)和vbptr(虚拟基础poitners)的使用。
Right::a
还是Left::a
?在测试2 中,Right
和Left
共享相同的公共父Top
。因此Top
中只有一个子对象Bottom
,因此只有一个Top::a
。a
。
有趣的是,您已在测试中介绍了Right
中的成员a
。这是a
,与Top
继承的a
不同。它是一个独特的成员,只是与另一个成员同名,并且巧合#34;。因此,如果您通过Right
访问Right::a
,Top::a
会隐藏Bottom::Top::a
(顺便提一下Right::Top::a
,Left::Top::a
, 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 << " Rigth::a: " << (void*)&bottom.Right::a << endl;
};
)。在这种情况下,bottom.a表示Right :: a,不是因为对象布局,而是因为名称loockup(和隐藏)规则。这不依赖于实现:它是标准的和可移植的。
这是测试2的变体,用于演示这种情况:
{{1}}