1
class RootBase{
public:
    RootBase():ai(12){}
    virtual void fas(){
        printf("%p \n", this);
    }
private:
    int ai;

};

class Base : virtual public RootBase{

public:
    Base():bai(1){}

    virtual void fas(){

    }
    virtual void fa(){

    }
private:
    int bai;
};

Base *pBase = new Base; 

クラスのメモリ位置に関する仮想継承関係のケースをテストします。ベースのサイズが24バイトであるため、結果は私を驚かせます。仮想関数テーブルポインター、仮想ベーステーブルポインター、およびメンバー変数を含む20バイトを理解できます。

pBaseが指すBaseオブジェクトのメモリ分散は次のとおりです。

 60 77 41 00 68 77 41 00 01 00 00 00 00 00 00 00 54 77 41 00 0c 00 00 00

しかし、13番目から16番目のバイト、0x00000000、NULL(x86 32ビットの整数0)の意味を理解できません。4バイト0は何をしますか?(OS:win xp、IDE:visual studio 8.0)

また、整数0はアライメントのパディングを表すと思いますが、8バイトにパディングする理由はありません。

4

1 に答える 1

4

これは、説明しているクラスのオブジェクトレイアウトのダンプから直接取得されます。それがあなたの質問に答えることを願っています。もう少し研究して、私vtordispはクラスのためにそれを発見しましたBase。仮想ベースで宣言されたクラスのコンストラクタまたはデストラクタから仮想関数を呼び出すときに使用されるオフセットです。どうやらそれはあなたの仮想関数テーブルがどこにあるかを彼らに知らせるためです。

5年以上前のMSFTのJonathanCavesから:

使用されることはめったにありませんが、ユーザーがコンストラクタまたはデストラクタで仮想関数を呼び出した場合に備えて、仮想基本クラスから継承するクラスに追加し、仮想関数をオーバーライドする必要があります。

注:1>すべての行の前文について申し訳ありません。Microsoftとそのツールを非難する。

1>  class RootBase  size(8):
1>      +---
1>   0  | {vfptr}
1>   4  | ai
1>      +---
1>  
1>  RootBase::$vftable@:
1>      | &RootBase_meta
1>      |  0
1>   0  | &RootBase::fas
1>  
1>  RootBase::fas this adjustor: 0
1>  
1>  
1>  class Base  size(24):
1>      +---
1>   0  | {vfptr}
1>   4  | {vbptr}
1>   8  | bai
1>      +---
1>  12  | (vtordisp for vbase RootBase)
1>      +--- (virtual base RootBase)
1>  16  | {vfptr}
1>  20  | ai
1>      +---
1>  
1>  Base::$vftable@Base@:
1>      | &Base_meta
1>      |  0
1>   0  | &Base::fa
1>  
1>  Base::$vbtable@:
1>   0  | -4
1>   1  | 12 (Based(Base+4)RootBase)
1>  
1>  Base::$vftable@RootBase@:
1>      | -16
1>   0  | &(vtordisp) Base::fas
1>  
1>  Base::fas this adjustor: 16
1>  Base::fa this adjustor: 0
1>  
1>  vbi    class     offset   o.vbptr  o.vbte fVtorDisp
1>         RootBase      16        4       4          1

まったく同じコードを使用しますRootBase通常の基本クラス(つまり、ではなくvirtual public RootBasepublic RootBaseを作成すると、オブジェクトのレイアウトに大きな影響があります。

1>  class RootBase  size(8):
1>      +---
1>   0  | {vfptr}
1>   4  | ai
1>      +---
1>  
1>  RootBase::$vftable@:
1>      | &RootBase_meta
1>      |  0
1>   0  | &RootBase::fas
1>  
1>  RootBase::fas this adjustor: 0
1>  
1>  
1>  class Base  size(12):
1>      +---
1>      | +--- (base class RootBase)
1>   0  | | {vfptr}
1>   4  | | ai
1>      | +---
1>   8  | bai
1>      +---
1>  
1>  Base::$vftable@:
1>      | &Base_meta
1>      |  0
1>   0  | &Base::fas
1>   1  | &Base::fa
1>  
1>  Base::fas this adjustor: 0
1>  Base::fa this adjustor: 0

仮想ベースがなくなると、「who-am-i」オフセットが保存されなくなり、オブジェクト形式がかなりきれいにクリーンアップされたように見えることに注意してください。

于 2013-01-05T04:27:20.287 に答える