2012-03-30 14 views
1

実際の仮想継承がどのように機能するか(すなわち、標準によるのではなく、g++のような実際の実装)をよりよく理解しようとしています。実際の質問は、ボトムに太字で記載されています。g ++で仮想継承テーブルはどのように機能しますか?

だから、私は自分自身に他のものの間であり継承グラフ、これらの単純なタイプを構築しました:

struct A { 
    unsigned a; 
    unsigned long long u; 
    A() : a(0xAAAAAAAA), u(0x1111111111111111ull) {} 
    virtual ~A() {} 
}; 

struct B : virtual A { 
    unsigned b; 
    B() : b(0xBBBBBBBB) { 
    a = 0xABABABAB; 
    } 
}; 

仮想継承が理にかなっているように(全体の階層では、私はまた、C: virtual ABC: B,Cを持っています。)

インスタンスのレイアウトをダンプし、vtableポインタをとり、最初の6つの8バイト値(スクリーンに収まるように任意)を印刷し、オブジェクトの実際のメモリをダンプする関数を書いた。それぞれの位置でたくさんにA Sを印刷することにより示されAオブジェクトが配置されているB対象とし、ダンプ

actual A object of size 24 at location 0x936010 
vtable expected at 0x402310 { 
      401036,   401068,   434232,    0,    0,    0, 
} 
1023400000000000aaaaaaaa000000001111111111111111 
[--vtable ptr--] 

Aオブジェクトのダンプ:これは、そのようなものになります。あなたが見ることができるように、BA一部が、私はB*にそれをBCをインスタンス化し、DYN-キャストしていた場合には異なる可能性がBオブジェクト(の先頭に16バイトのオフセットに位置しています

actual B object of size 40 at location 0x936030 
vtable expected at 0x4022b8 { 
      4012d2,   40133c,  fffffff0,  fffffff0,   4023c0,   4012c8, 
} 
b822400000000000bbbbbbbb00000000e022400000000000abababab000000001111111111111111 
           AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA (offset: 16) 

)。プログラムは、実行時にAの実際の位置(オフセット)を検索する必要があるため

私はに(によるアライメントに、または少なくとも216を期待しているだろうが、どこかのテーブルに表示されます。 レイアウトは本当にどのように見えますか?


編集:ダンプがdumpdumpPositionsを呼び出すことによって行われます:

using std::cout; 
using std::endl; 

template <typename FROM, typename TO, typename STR> void dumpPositions(FROM const* x, STR name) { 
    uintptr_t const offset {reinterpret_cast<uintptr_t>(dynamic_cast<TO const*>(x)) - reinterpret_cast<uintptr_t>(x)}; 
    for (unsigned i = 0; i < sizeof(FROM); i++) { 
    if (offset <= i && i < offset+sizeof(TO)) 
     cout << name << name; 
    else 
     cout << " "; 
    } 
    cout << " (offset: " << offset << ")"; 
    cout << endl; 
} 
template <typename T> void hexDump(T const* x, size_t const length, bool const comma = false) { 
    for (unsigned i = 0; i < length; i++) { 
    T const& value {static_cast<T const&>(x[i])}; 
    cout.width(sizeof(T)*2); 
    if (sizeof(T) > 1) 
     cout.fill(' '); 
    else 
     cout.fill('0'); 
    cout << std::hex << std::right << (unsigned)value << std::dec; 
    if (comma) 
     cout << ","; 
    } 
    cout << endl; 
} 
template <typename FROM, typename STR> void dump(FROM const* x, STR name) { 
    cout << name << " object of size " << sizeof(FROM) << " at location " << x << endl; 
    uintptr_t const* const* const vtable {reinterpret_cast<uintptr_t const* const*>(x)}; 
    cout << "vtable expected at " << reinterpret_cast<void const*>(*vtable) << " {" << endl; 
    hexDump(*vtable,6,true); 
    cout << "}" << endl; 
    hexDump(reinterpret_cast<unsigned char const*>(x),sizeof(FROM)); 
} 
+0

「ダンプ」を実行するコードを確認すると便利です。 – gbulmer

+0

@gbulmer:そこに行きます。私はその多くの助けを考えていませんが。 – bitmask

答えて

1

答えは実際にItanium ABIに、ここに記載されています。特にセクション2.5には、仮想テーブルのレイアウトが含まれています。

+0

これは私の2番目の推測でしたが、ダンプで見ることができるように、 'B'は16バイトしか持っていません(' A'部分の外に)。最初の8バイトはvptrで、2番目の8バイトは 'b'整数メンバ(整列)です。少なくとも、それは私がそれを読む方法です。私はオフセット16 **または**アドレス '0x4022c8'(' == 0x4022b8 + 16')をどこかに期待します。私は今あなたのリンクを見ていきます。 – bitmask

+0

仮想テーブル記述(カテゴリ3)には多くの注意点があります。これに関する文法の説明を知っていますか? – bitmask

関連する問題