Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/141.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ C++;虚拟方法的对象大小_C++_Virtual Functions_Objectsize - Fatal编程技术网

C++ C++;虚拟方法的对象大小

C++ C++;虚拟方法的对象大小,c++,virtual-functions,objectsize,C++,Virtual Functions,Objectsize,我有一些关于虚拟对象大小的问题 1)虚拟功能 class A { public: int a; virtual void v(); } 类的大小是8字节…一个整数(4字节)加上一个虚拟指针(4字节) 很清楚 class B: public A{ public: int b; virtual void w(); } B类的尺寸是多少?我用sizeof B测试过,它可以打印 十二, 这是否意味着只有一个vptr,即使

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

1)虚拟功能

class A {
    public:
       int a;
       virtual void v();
    }
类的大小是8字节…一个整数(4字节)加上一个虚拟指针(4字节) 很清楚

class B: public A{
    public:
       int b;
       virtual void w();
}
B类的尺寸是多少?我用sizeof B测试过,它可以打印 十二,

这是否意味着只有一个vptr,即使B类和A类都有虚拟功能?为什么只有一个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

在这种情况下,布局中似乎有两个VPTR……这是如何发生的?我认为这两个vptr一个用于A类,另一个用于B类…所以C类的虚拟功能没有vptr

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

2)虚拟继承

    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(inta)+4(vptr)=8

B的大小是16个字节------------如果没有虚拟值,它应该是4+4+4=12。为什么这里还有4个字节?B班的布局是什么

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

class B: public A{
    public:
       int b;
       virtual void w();
}
D的大小是32字节------------它应该是16(B类)+12(C类)+4(int D)=32。是这样吗

    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();
    };
A的大小是8

B的尺寸是16

C的大小是16

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

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

在这种情况下,对象大小的基本规则是什么


当virtual应用于所有基类和部分基类时有什么区别呢?

我不确定,但我认为这是因为指向的指针,所有这些都是您意识到的完全由实现定义的。你不能指望这些。没有“规则”

在继承示例中,下面是类A和B的虚拟表的外观:

      class A
+-----------------+
| pointer to A::v |
+-----------------+

      class B
+-----------------+
| pointer to A::v |
+-----------------+
| pointer to B::w |
+-----------------+
如您所见,如果您有一个指向类B的虚拟表的指针,那么它作为类a的虚拟表也是完全有效的


在您的C类示例中,如果您仔细想想,就无法生成一个虚拟表,该虚拟表作为C类、a类和B类的表都是有效的。一个虚拟表对A类和C类有效(很可能),另一个对A类和B类有效。

这都是实现定义的。我用的是VC10β2。帮助理解这些内容(虚拟函数的实现)的关键是,您需要了解Visual Studio编译器中的一个秘密开关,/d1reportSingleClassLayoutXXX。我马上就讲

基本规则是,对于指向对象的任何指针,vtable都需要位于偏移量0处。这意味着多重继承有多个vtable

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

这是否意味着只有一个vptr,即使B类和A类都有虚拟功能?为什么只有一个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();
};
这就是虚拟函数的工作方式,您希望基类和派生类共享同一个vtable指针(指向派生类中的实现)

似乎在这种情况下,布局中有两个vptr…这是怎么发生的?我认为两个vptr一个用于A类,另一个用于B类…因此C类的虚拟功能没有vptr

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

class C size(20):
        +---
        | +--- (base class A)
 0      | | {vfptr}
 4      | | a
        | +---
        | +--- (base class B)
 8      | | {vfptr}
12      | | b
        | +---
16      | c
        +---
您是正确的,有两个vtable,每个基类一个。这是它在多重继承中的工作方式;如果将C*强制转换为B*,指针值将调整8个字节。vtable仍然需要位于偏移量0处,虚拟函数调用才能工作

上述A类布局中的vtable被视为C类的vtable(通过C*调用时)

B的大小是16个字节------------如果没有虚拟,它应该是4+4+4=12。为什么这里还有4个字节?B类的布局是什么

这是本例中B类的布局:

class B size(20):
        +---
 0      | {vfptr}
 4      | {vbptr}
 8      | b
        +---
        +--- (virtual base A)
12      | {vfptr}
16      | a
        +---
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
        +---
正如您所看到的,有一个额外的指针来处理虚拟继承。虚拟继承非常复杂

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

    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();
    };
不,36字节。虚拟继承的处理方法相同。本例中D的布局:

class B size(20):
        +---
 0      | {vfptr}
 4      | {vbptr}
 8      | b
        +---
        +--- (virtual base A)
12      | {vfptr}
16      | a
        +---
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
        +---
我的问题是,为什么应用虚拟继承时会有额外的空间

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

在这种情况下,对象大小的基本规则是什么

重要的一点;没有规则:编译器可以做它需要做的任何事情

最后一个细节;为了制作所有这些类布局图,我正在使用:

cl test.cpp /d1reportSingleClassLayoutXXX

其中XXX是您希望查看其布局的结构/类的子字符串匹配。使用它,您可以自己探索各种继承方案的影响,以及添加填充的原因/位置等。

考虑它的一个好方法是了解处理强制转换必须做些什么。我将通过显示您描述的类的对象的内存布局

代码示例#2 内存布局如下所示:

vptr | A::a | B::b vptr | A::A | B::B 将指向B的指针向上投射到类型a将产生相同的地址,使用相同的vptr。这就是为什么这里不需要额外的vptr

代码示例#3 vptr | A::A | vptr | B::B | C::C 正如你所看到的,这里有两个vptr,正如你所猜测的。为什么?因为它是tr