对象大小与虚拟 [英] object size with virtual

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

问题描述

我有一些关于虚拟对象大小的问题。

I have some questions about the object size with virtual.

1)虚函数

class A {
    public:
       int a;
       virtual void v();
    }

类A的大小为8bytes ....一个整数)加一个虚指针(4字节)
很清楚!

The size of class A is 8bytes....one integer(4 bytes) plus one virtual pointer(4 bytes) It's clear!

class B: public A{
    public:
       int b;
       virtual void w();
}

B类的大小是多少?我测试使用sizeof B,它打印
12

What's the size of class B? I tested using sizeof B, it prints 12

这是否意味着只有一个vptr是有的,即使B类和A类都有虚函数?为什么只有一个vptr?

Does it mean that only one vptr is there even both of class B and class A have virtual function? Why there is only one vptr?

class A {
public:
    int a;
    virtual void v();
};

class B {
public:
    int b;
    virtual void w();
};

class C :  public A, public B {
public:
    int c;
    virtual void x();
};

C的大小为20 ........

The sizeof C is 20........

似乎在这种情况下,两个vptrs是在布局.....这是怎么回事?我认为两个vptrs一个是为类A和另一个是为类B ....所以没有vptr虚拟函数的类C?

It seems that in this case, two vptrs are in the layout.....How does this happen? I think the two vptrs one is for class A and another is for class B....so there is no vptr for the virtual function of class C?

我的问题是,关于继承中vptrs数量的规则是什么?

My question is, what's the rule about the number of vptrs in inheritance?

虚拟继承

2) virtual inheritance

    class A {
    public:
        int a;
        virtual void v();
    };

    class B: virtual public A{                  //virtual inheritance 
    public:
        int b;
        virtual void w();
    };

    class C :  public A {                      //non-virtual inheritance
    public:
        int c;
        virtual void x();
    };

class D: public B, public C {
public:
    int d;
    virtual void y();
};

A的大小为8字节-------------- 4 (int a)+ 4(vptr)= 8

The sizeof A is 8 bytes -------------- 4(int a) + 4 (vptr) = 8

B的大小是16字节--------------没有虚拟be 4 + 4 + 4 = 12.为什么还有另外4个字节? B类的布局是什么?

The sizeof B is 16 bytes -------------- Without virtual it should be 4 + 4 + 4 = 12. why there is another 4 bytes here? What's the layout of class B ?

C的大小是12字节。 -------------- 4 + 4 + 4 = 12.很清楚!

The sizeof C is 12 bytes. -------------- 4 + 4 + 4 = 12. It's clear!

D的大小是32字节---- ----------它应该是16(B类)+ 12(C类)+ 4(int d)= 32是吗?

The sizeof D is 32 bytes -------------- it should be 16(class B) + 12(class C) + 4(int d) = 32. Is that right?

    class A {
    public:
        int a;
        virtual void v();
    };

    class B: virtual public A{                       //virtual inheritance here
    public:
        int b;
        virtual void w();
    };

    class C :  virtual public A {                    //virtual inheritance here
    public:
        int c;
        virtual void x();
    };

  class D: public B, public C {
   public:
        int d;
        virtual void y();
    };

sizeof A is 8

sizeof A is 8

sizeof B是16

sizeof B is 16

sizeof C是16

sizeof C is 16

sizeof D是28是否意味着28 = 16(B类) + 16(类C) - 8(A类)+ 4(这是什么?)

sizeof D is 28 Does it mean 28 = 16(class B) + 16(class C) - 8(class A) + 4 ( what's this? )

我的问题是,为什么应用虚拟继承时有额外的空间?

My question is , why there is an extra space when virtual inheritance is applied?

在这种情况下,对象大小的底层规则是什么?

What's the underneath rule for the object size in this case?

在所有基类和部分基类上应用virtual时有什么区别?

What's the difference when virtual is applied on all the base classes and on part of the base classes?

推荐答案

这是所有实现定义。我使用VC10 Beta2。帮助理解这个东西(实现虚拟函数)的关键,你需要知道在Visual Studio编译器中的秘密切换, / d1reportSingleClassLayoutXXX

This is all implementation defined. I'm using VC10 Beta2. The key to help understanding this stuff (the implementation of virtual functions), you need to know about a secret switch in the Visual Studio compiler, /d1reportSingleClassLayoutXXX. I'll get to that in a second.

基本规则是vtable需要位于offset 0的任何指向对象的指针。这意味着多个vtables用于多重继承。

The basic rule is the vtable needs to be located at offset 0 for any pointer to an object. This implies multiple vtables for multiple inheritance.

这里有几个问题,我将从顶部开始:

Couple questions here, I'll start at the top:

是否意味着只有一个vptr是有的,即使B类和A类都有虚函数?为什么只有一个vptr?

这是虚函数的工作方式,希望基类和派生类共享同一个vtable指针在派生类中的实现。

This is how virtual functions work, you want the base class and derived class to share the same vtable pointer (pointing to the implementation in the derived class.

看起来在这种情况下,两个vptrs在布局.....这是怎么回事?两个vptr一个是用于类A,另一个是用于类B ....因此没有vptr用于类C的虚拟函数。

这是C类的布局,由/ d1reportSingleClassLayoutC报告:

This is the layout of class C, as reported by /d1reportSingleClassLayoutC:

class C size(20):
        +---
        | +--- (base class A)
 0      | | {vfptr}
 4      | | a
        | +---
        | +--- (base class B)
 8      | | {vfptr}
12      | | b
        | +---
16      | c
        +---

你是正确的,有两个vtables,每个基类一个。多重继承;如果C *被强制转换为B *,指针值将被调整8个字节。对于虚函数调用,vtable仍然需要在偏移量为0。

You are correct, there are two vtables, one for each base class. This is how it works in multiple inheritance; if the C* is casted to a B*, the pointer value gets adjusted by 8 bytes. A vtable still needs to be at offset 0 for virtual function calls to work.

上面布局中的类A的vtable被当作类C的vtable a C *)。

The vtable in the above layout for class A is treated as class C's vtable (when called through a C*).

B的大小是16字节--------------没有虚拟的应该是4 + 4 + 4 = 12.为什么还有另外4个字节? B类的布局是什么?

这是此示例中类B的布局:

This is the layout of class B in this example:

class B size(20):
        +---
 0      | {vfptr}
 4      | {vbptr}
 8      | b
        +---
        +--- (virtual base A)
12      | {vfptr}
16      | a
        +---

正如你所看到的,虚拟继承。虚拟继承很复杂。

As you can see, there is an extra pointer to handle virtual inheritance. Virtual inheritance is complicated.

D的大小是32字节--------------它应该是16(B类)+ 12(C类)+ 4(int d)= 32.是不是这样?

The sizeof D is 32 bytes -------------- it should be 16(class B) + 12(class C) + 4(int d) = 32. Is that right?

不,36字节。同样的处理虚拟继承。在此示例中D的布局:

No, 36 bytes. Same deal with the virtual inheritance. Layout of D in this example:

class D size(36):
        +---
        | +--- (base class B)
 0      | | {vfptr}
 4      | | {vbptr}
 8      | | b
        | +---
        | +--- (base class C)
        | | +--- (base class A)
12      | | | {vfptr}
16      | | | a
        | | +---
20      | | c
        | +---
24      | d
        +---
        +--- (virtual base A)
28      | {vfptr}
32      | a
        +---

我的问题是,应用虚拟继承时的空间?

虚拟基类指针,很复杂。基本类在虚拟继承中被组合。而不是将基类嵌入到类中,该类将具有指向布局中基类对象的指针。如果你有两个使用虚拟继承(diamond类层次结构)的基类,它们都将指向对象中的相同的虚拟基类,而不是具有该基类的单独副本。

Virtual base class pointer, it's complicated. Base classes are "combined" in virtual inheritance. Instead of having a base class embedded into a class, the class will have a pointer to the base class object in the layout. If you have two base classes using virtual inheritance (the "diamond" class hierarchy), they will both point to the same virtual base class in the object, instead of having a separate copy of that base class.

这种情况下对象大小的底层规则是什么?

没有规则:编译器可以做任何它需要做的事。

Important point; there are no rules: the compiler can do whatever it needs to do.

最后的细节;使所有这些类布局图我编译:

And a final detail; to make all these class layout diagrams I am compiling with:

cl test.cpp /d1reportSingleClassLayoutXXX

其中XXX是您要查看布局的structs /类的子字符串匹配。使用这个你可以自己探索各种继承方案的影响,以及为什么/添加填充等。

Where XXX is a substring match of the structs/classes you want to see the layout of. Using this you can explore the affects of various inheritance schemes yourself, as well as why/where padding is added, etc.

这篇关于对象大小与虚拟的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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