c – 虚拟表和多个虚拟继承中的内存布局

c – 虚拟表和多个虚拟继承中的内存布局,第1张

概述考虑以下层次: struct A { int a; A() { f(0); } A(int i) { f(i); } virtual void f(int i) { cout << i; }};struct B1 : virtual A { int b1; B1(int i) : A(i) { f(i); } virtual void f(int i 考虑以下层次:
struct A {   int a;    A() { f(0); }   A(int i) { f(i); }   virtual voID f(int i) { cout << i; }};struct B1 : virtual A {   int b1;   B1(int i) : A(i) { f(i); }   virtual voID f(int i) { cout << i+10; }};struct B2 : virtual A {   int b2;   B2(int i) : A(i) { f(i); }   virtual voID f(int i) { cout << i+20; }};struct C : B1,virtual B2 {   int c;   C() : B1(6),B2(3),A(1){}   virtual voID f(int i) { cout << i+30; }};

> C实例的内存布局是什么?它包含几个vptrs,其中每个都放置在哪里?哪些虚拟表与C的虚拟表共享?每个虚拟表包含什么?

这里我怎么理解布局:

----------------------------------------------------------------|vptr1 | AptrOfB1 | b1 | B2ptr | c | vptr2 | AptrOfB2 | b2 | a |----------------------------------------------------------------

其中AptrOfBx是指向Bx包含的实例的指针(因为继承是虚拟的).
那是对的吗?哪个功能vptr1指向?哪个功能vptr2指向?
>给出以下代码

C* c = new C();dynamic_cast<B1*>(c)->f(3);static_cast<B2*>(c)->f(3);reinterpret_cast<B2*>(c)->f(3);

为什么所有打电话给f打印33?

解决方法 虚拟基地与普通基地截然不同.请记住,“虚拟”表示“在运行时确定” – 因此,必须在运行时确定整个基本子对象.

想象一下,你正在获得一个B& x引用,并且您有责任找到A :: a成员.如果继承是真实的,则B具有超类A,因此通过x查看的B对象具有A子对象,您可以在其中找到您的成员A :: a.如果x的派生最多的对象具有多个类型A的基数,那么您只能看到作为B的子对象的特定副本.

但是,如果继承是虚拟的,这些都不是有意义的.我们不知道我们需要哪个A子对象 – 这个信息在编译时根本不存在.我们可以像B一样处理一个实际的B对象; B& x = y,或与C z对应的C对象; B& x = z;或完全不同的东西,几乎从多个派生出来.唯一的知道方法是在运行时找到实际的基数A.

这可以通过一个更多级别的运行时间间隔来实现. (注意,与非虚函数相比,这与虚拟函数如何实现一个额外的运行时间间隔完全相同).而不是有一个指向vtable或者基本子对象的指针,一个解决方案是存储指向指针的指针到实际的子对象.这有时被称为“笨蛋”或“蹦床”.

所以实际的对象C z;可能看起来如下.内存中的实际排序取决于编译器并且不重要,我已经抑制了vtables.

+-+------++-+------++-----++-----+|T|  B1  ||T|  B2  ||  C  ||  A  |+-+------++-+------++-----++-----+ |         |                 | V         V                 ^ |         |       +-Thunk-+ | +--->>----+-->>---|     ->>-+                   +-------+

因此,无论你是否有B1&或者B2和amp,你首先查找thunk,那个又反过来告诉你在哪里找到实际的基本子对象.这也解释了为什么你不能从A&到任何派生类型:这个信息在编译时根本不存在.

有关更深入的解释,请查看this fine article.(在该描述中,thunk是C的vtable的一部分,虚拟继承总是需要维护vtables,即使在任何地方都没有虚拟函数).

总结

以上是内存溢出为你收集整理的c – 虚拟表和多个虚拟继承中的内存布局全部内容,希望文章能够帮你解决c – 虚拟表和多个虚拟继承中的内存布局所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/1255276.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-07
下一篇 2022-06-07

发表评论

登录后才能评论

评论列表(0条)

保存