0
#include<iostream>    
using namespace std;

class A
{
    public:
        int i;
};

class B: virtual public A
{
    public:
        int j;
};

class C: virtual public A
{
    public:
        int k;
};
class D: virtual public B, virtual public C
{
    public:
        int l;
};

int main()
{

    cout<<" A : "<<sizeof(A)<<endl;
    cout<<" B : "<<sizeof(B)<<endl;
    cout<<" C : "<<sizeof(C)<<endl;
    cout<<" D : "<<sizeof(D)<<endl;
}

输出:

1
8
8
16

据我了解,在虚拟继承期间,每个基类都有一个 vptr,因此 D 类有两个 vptr,大小为 16。

假设如果类 D 也具有虚拟功能,则假设虚拟 ~D()。现在大小应该增加到 24(D 一个 vptr)。

但这并没有发生。

我如何误解了虚拟 ptr 的概念。

谁能解释清楚??

4

2 回答 2

1

D需要一个vptr,不管它有没有虚功能,BCdo一样。

原因是编译器需要一种方法来从任何实例获取D到它的A,BC, 基类子对象。由于该继承是虚拟的,E因此可能会出现一些类,它派生自D派生自具有相同虚拟基础的其他事物。的布局D必须考虑到存在的可能性E

因此,从作为其实例的完整对象到其基类子对象的完整对象没有固定的偏移量D,因为该完整对象可能是 as-yet-undefined 的实例E

我不确定这是否完全解释了您看到的行为。我从来没有使用过 which 的实现sizeof(int) == 1,我也没有任何理由解释为什么BandD是 8 和 16。

于 2013-02-07T17:56:49.827 回答
0

为什么添加虚函数D需要额外的 vptr?类图像将以Bor开头C,并且 D可以将其功能附加到任何一个。(一旦你有了虚继承,你就需要某种指针,即使没有虚函数。)

添加一个虚函数A 产生影响(几乎可以肯定,当然,这里的一切都取决于实现)。对于它的价值,您可能想尝试以下方法:

#include <iostream>
#include <iomanip>
#include <cstdint>

typedef std::uintptr_t Word;

class SaveIOFormat
{
    std::basic_ios<char>* myStream;
    char myFill;
    std::basic_ios<char>::fmtflags myFlags;
    int myPrecision;
public:
    SaveIOFormat( std::basic_ios<char>& stream )
        : myStream( &stream )
        , myFill( stream.fill() )
        , myFlags( stream.flags() )
        , myPrecision( stream.precision() )
    {
    }
    ~SaveIOFormat()
    {
        myStream->fill( myFill );
        myStream->flags( myFlags );
        myStream->precision( myPrecision );
    }
};

template <typename T>
class DumpAsWords
{
    Word const* myObj;
    typedef Word const* Iterator;
    typedef char sizeMustBeMultipleOfSizeofWord
            [ sizeof(T) % sizeof(uintptr_t) == 0 ? 1 : -1 ];
    static int const ourLength = sizeof(T) / sizeof(Word);
public:
    DumpAsWords( T const& obj )
        : myObj( reinterpret_cast<Word const*>( &obj ) )
    {
    }
    friend std::ostream& operator<<( std::ostream& dest,
                                     DumpAsWords const& obj )
    {
        SaveIOFormat saveExcursion( dest );
        dest.fill( '0' );
        dest.setf( std::ios::hex, std::ios::basefield );
        for ( Iterator current = obj.myObj, end = obj.myObj + ourLength;
                current != end;
                ++ current ) {
            if ( current != obj.myObj ) {
                dest << ' ';
            }
            dest << std::setw( sizeof(Word) * 2 ) << *current;
        }
        return dest;
    }
};

template <typename T>
DumpAsWords<T>
dump( T const& obj )
{
    return DumpAsWords<T>( obj );
}

class B
{
    Word i;
public:
    B() : i( 1 ) {}
    virtual ~B() {}
};

class L : virtual public B
{
    Word i;
public:
    L() : i( 2 ) {}
};

class R : virtual public B
{
    Word i;
public:
    R() : i( 3 ) {}
};

class D : public L, public R
{
    Word i;
public:
    D() : i( 4 ) {}
};

int
main()
{
    D aD;

    std::cout << "sizeof B: " << sizeof(B) << std::endl;
    std::cout << "sizeof L: " << sizeof(L) << std::endl;
    std::cout << "sizeof R: " << sizeof(R) << std::endl;
    std::cout << "sizeof D: " << sizeof(D) << std::endl;
    std::cout << std::endl;

    std::cout << "addrof B: " << static_cast<B*>( &aD ) << std::endl;
    std::cout << "addrof L: " << static_cast<L*>( &aD ) << std::endl;
    std::cout << "addrof R: " << static_cast<R*>( &aD ) << std::endl;
    std::cout << "addrof D: " << static_cast<D*>( &aD ) << std::endl;
    std::cout << std::endl;

    std::cout << "dump: " << dump( aD ) << std::endl;
    return 0;
}

(如果它有点长,那是因为我从我的库中复制/粘贴了一些代码以使其更简单和更清晰。)

在我的机器上,这给出了:

sizeof B: 16
sizeof L: 32
sizeof R: 32
sizeof D: 56

addrof B: 00000000001AFEB8
addrof L: 00000000001AFE90
addrof R: 00000000001AFEA0
addrof D: 00000000001AFE90

dump: 000000013fb90bb0 0000000000000002 000000013fb90bb8 0000000000000003 0000000000000004 000000013fb90ba8 0000000000000001

如您所见,顺序是 D 中的 L,D 中的 R,D,B(在 L,R 和 D 中)。D 与 L 共享 vptr。

(这是在 64 位 Windows 机器上使用 VC++ 11 编译的。你的结果很容易不同。)

于 2013-02-07T18:41:34.290 回答