1

次のコード セグメントと出力について、理解に問題があります。主に test() が出力に見られるように機能する理由を誰でも説明できますか。MSCV 2008 C++ コンパイラを使用しています。

class AS
{
    int a;

public:
    AS():a(1){show();}
    virtual void show() {cout<<a<<endl;}
    void test() { cout<<"Calling show()"<<endl; this->show();}
};

class BS: virtual public AS
{
    int b;
public:
    BS():b(2){show();}
    virtual void show() {cout<<b<<endl;}
    void test() { cout<<"Calling show()"<<endl; this->show();}
};

class CS:public virtual  AS
{
    int c;
public:
    CS():c(3){show();}
    virtual void show() {cout<<c<<endl;}
    void test() { cout<<"Calling show()"<<endl; this->show();}
};

class DS:BS, public CS
{
    int d;
public:
DS():d(4){show();}
    virtual void show() {cout<<d<<endl;}
    void test() { cout<<"Calling show()"<<endl; this->show();}
};

int main()
{
cout<<"Class Sizes:"<<endl;
cout<<sizeof(AS)<<endl;
cout<<sizeof(BS)<<endl;
cout<<sizeof(CS)<<endl;
cout<<sizeof(DS)<<endl;

AS* aa = new DS();  
aa->test();
aa->show();

delete aa;

return 0;
}

出力は次のとおりです:-

Class Sizes:
8
20
20
32
1
2
3
4
Calling show()
4
4

aaの削除時のブレークポイント例外。なんで ?

4

2 に答える 2

0

これが私のビットです。間違っている場合は修正してください。

[注: vptr-vtable メカニズムは仮想関数呼び出しの実装に使用され、vbptr (仮想基本クラス ポインター) は仮想基本クラスの実装に使用されます。また、(いくつかのポリモーフィック クラスの) sizeOf は、使用されているコンパイラ + プラットフォームによって異なる場合があります]

1) クラス AS のインスタンスには 8 バイトが必要です (「int a」の 4 バイト + 非表示の vptr の 4 バイト) = 8

2) クラス BS のインスタンスには 20 バイトが必要です。

(基本クラス AS を保持するための 4 バイト + パディング 4 バイト + "int b" 用の 4 バイト + 隠し vptr 用の 4 バイト + vbptr 用の 4 バイト) = 20

3) クラス CS のインスタンスには 20 バイトが必要です。

(基本クラス AS を保持するための 4 バイト + パディング 4 バイト + "int c" 用の 4 バイト + 非表示の vptr 用の 4 バイト + vbptr 用の 4 バイト) = 20

4) クラス DS のインスタンスには 32 バイトが必要です。

(共有基本クラス AS を保持するための 4 バイト + 「int d」用の 4 バイト + 基本クラス BS を保持するための 8 バイト (メンバー サイズ + vbptr サイズを考慮) + 基本クラス CS を保持するための 8 バイト (メンバー サイズ + vbptr サイズを考慮) ) + 非表示の DS::vptr の 4 バイト + DS::vbptr の 4 バイト) = 32

[注意してください。vptr-vtable メカニズムを実装している間、コンパイラは vtable を仮想関数アドレスで拡張します。クラス DS のメモリ モデル内には単一の v-table と単一の v-ptr が存在します。一方、vbptr は、すべての仮想基本クラス内およびそれらを継承するクラス内で複製されます]。

繰り返しますが、これらはすべてコンパイラ固有の実装であり、コンパイラによって異なる場合があります。

また、すべての基本クラスのデストラクタを仮想として定義して、クラッシュを回避します。

于 2013-05-08T05:53:55.153 に答える