基类中的虚拟继承和空vtable [英] Virtual inheritance and empty vtable in base class

查看:99
本文介绍了基类中的虚拟继承和空vtable的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有此代码:

#include <iostream>

class Base
{
   int x;
};

class Derived : virtual public Base
{
   int y;
};

int main()
{
    std::cout << sizeof(Derived) << std::endl; // prints 12
    return 0;   
}

我已经读到,当虚拟地继承某个类时,则会为派生类创建空的vtable,因此内存布局如下:

I have read that when some class is virtually inherited then there is created empty vtable for class Derived, so memory layout is as follows:

Derived::ptr to empty vtable
Derived::y
Base::x

,它是12个字节.问题是-如果没有任何虚拟方法,此 empty 空表的用途是什么?

and it is 12 bytes. The question is - what is purpose of this empty vtable if there are not any virtual methods and how is it used?

推荐答案

Derived需要某种方式来了解Base子对象的位置.使用虚拟继承时,相对于派生类的位置,基类的相对位置不是固定的:它可以位于完整对象中的任何位置.

Derived needs some way to know where the Base subobject is. With virtual inheritance, the relative location of the base class is not fixed with respect to the location of the derived class: it may be located anywhere in the full object.

考虑一个涉及钻石继承的更典型示例.

Consider a more typical example involving diamond inheritance.

struct A
{
    int a;
};

struct B1 : virtual A
{
    int b1;
};

struct B2 : virtual A
{
    int b2;
};

struct C : B1, B2
{
    int c;
};

在这里,B1B2都实际上是从A派生的,因此在C中,恰好有一个A子对象. B1B2都需要知道如何找到该A子对象(以便他们可以访问a成员变量,或者如果我们要定义它们,则可以访问A的其他成员).

Here, both B1 and B2 derive virtually from A, so in C, there is exactly one A subobject. Both B1 and B2 need to know how to find that A subobject (so that they can access the a member variable, or other members of A if we were to define them).

在这种情况下,这就是vtable的用途:B1B2都将具有一个包含A子对象的偏移量的vtable.

This is what the vtable is used for in this case: both B1 and B2 will have a vtable that contains the offset of the A subobject.

为演示编译器可以如何实现上述钻石继承示例,请考虑以下类布局和虚拟表,这些类布局和虚拟表是由Visual C ++ 11开发人员预览版生成的.

To demonstrate what a compiler might do to implement the above diamond inheritance example, consider the following class layouts and virtual tables, generated by the Visual C++ 11 Developer Preview.

class A size(4):
        +---
 0      | a
        +---

class B1        size(12):
        +---
 0      | {vbptr}
 4      | b1
        +---
        +--- (virtual base A)
 8      | a
        +---

class B2        size(12):
        +---
 0      | {vbptr}
 4      | b2
        +---
        +--- (virtual base A)
 8      | a
        +---

class C size(24):
        +---
        | +--- (base class B1)
 0      | | {vbptr}
 4      | | b1
        | +---
        | +--- (base class B2)
 8      | | {vbptr}
12      | | b2
        | +---
16      | c
        +---
        +--- (virtual base A)
20      | a
        +---

和以下vtable:

B1::$vbtable@:
 0      | 0
 1      | 8 (B1d(B1+0)A)

B2::$vbtable@:
 0      | 0
 1      | 8 (B2d(B2+0)A)

C::$vbtable@B1@:
 0      | 0
 1      | 20 (Cd(B1+0)A)

C::$vbtable@B2@:
 0      | 0
 1      | 12 (Cd(B2+0)A)

请注意,偏移量是相对于vtable的地址的,并且请注意,对于为CB1B2子对象生成的两个vtable,偏移量是不同的.

Note that the offsets are relative to the address of the vtable, and note that for the two vtables generated for the B1 and B2 subobjects of C, the offsets are different.

(还要注意,这完全是实现细节,其他编译器可能会以不同的方式实现虚拟函数和基础.此示例演示了一种实现方式,并且通常以这种方式实现.)

(Also note that this is entirely an implementation detail--other compilers may implement virtual functions and bases differently. This example demonstrates one way that they are implemented, and they are very commonly implemented this way.)

这篇关于基类中的虚拟继承和空vtable的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆