2012-03-30 7 views
1

Ich versuche zu verstehen, wie virtuelle Vererbung in der Praxis funktioniert (das heißt, nicht nach dem Standard, sondern in einer tatsächlichen Implementierung wie g++). Die eigentliche Frage ist unten, in Fettdruck.Wie funktioniert die virtuelle Vererbungstabelle in g ++?

So baute ich mir ein Vererbungsgraphen, die unter anderem hat diese einfachen Typen:

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; 
    } 
}; 

(In der ganzen Hierarchie Ich habe auch ein C: virtual A und BC: B,C, so dass die virtuelle Vererbung macht Sinn .)

Ich schrieb ein paar Funktionen, um das Layout von Instanzen zu entladen, den Vtable-Zeiger zu nehmen und die ersten 6 8-Byte-Werte zu drucken (beliebig auf den Bildschirm zu passen) und dann den tatsächlichen Speicher des Objekts auszugeben. Das sieht so ähnlich:

Dumping ein A Objekt:

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

Dumping ein B Objekt und wo das A Objekt befindet, das durch den Druck einer Menge A s an der jeweiligen Position angezeigt wird.

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

Wie Sie das A Teil B bei einem Offset von 16 Bytes zu Beginn des B Objekt (die unterschiedlich sein können, wenn ich es instanziiert hatte ein B* gegossen dyn-BC und befindet sich sehen !).

ich erwartet hätte die 16 (oder zumindest ein 2 aufgrund Ausrichtung) zu zeigen sich irgendwo in der Tabelle, da das Programm den aktuellen Standort zu suchen hat (Offset) von A zur Laufzeit. Also, wie sieht das Layout wirklich aus?


Edit: Der Dump erfolgt durch dump und dumpPositions Aufruf:

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

Es wäre nett/hilfreich, den Code zu sehen, der den "Dump" macht. – gbulmer

+0

@gbulmer: Da gehst du. Obwohl ich nicht denke, dass es viel hilft. – bitmask

Antwort

1

Die Antwort ist eigentlich hier dokumentiert, in der Itanium ABI. Insbesondere Abschnitt 2.5 enthält das Layout der virtuellen Tabelle.

+0

Das war meine zweite Vermutung, aber wie Sie in der Dump sehen können, hat 'B' nur 16 Byte (neben dem' A' Teil). Die ersten 8 Bytes sind die vptr, während die zweiten 8 Bytes das 'b'-Integer-Element (aligned) sind. Zumindest lese ich es so. Ich würde irgendwo den Offset 16 ** oder ** die Adresse '0x4022c8' (' == 0x4022b8 + 16') erwarten. Ich werde mich jetzt jedoch um deinen Link kümmern. – bitmask

+0

Die virtuelle Tabelle Beschreibung (Kategorie 3) hat viele Vorbehalte. Kennen Sie eine Grammatikbeschreibung dafür? – bitmask