2012-03-30 3 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 A и BC: B,C, так что виртуальное наследование имеет смысл .)

Я написал несколько функций, чтобы сбросить компоновку экземпляров, взяв указатель vtable и напечатав первые 6 8-байтовых значений (произвольно для соответствия на экране), а затем сбрасываем фактическую память объекта. Это выглядит примерно так:

демпинга в A объект:

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

демпинг B объект и где объект A расположен, который обозначается печатью большого A с при соответствующем положении.

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

Как вы можете видеть, A часть B расположена по смещению 16 байт до начала B объекта (который может быть иначе, если бы я инстанцирован BC и дин-отливают его в B*!).

я бы ожидал 16 (или по крайней мере 2, из-за выравнивания), чтобы показать где-нибудь в таблице, так как программа должна искать фактическое местоположение (смещение) в A во время выполнения. Итак, как выглядит макет?


Edit: дамп делается вызовом dump и dumpPositions:

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

Это было мое второе предположение, но, как вы можете видеть на дампе, 'B' имеет только 16 байт (кроме части' A'). Первые 8 байтов - это vptr, а вторые 8 байтов - член целочисленного элемента 'b' (выровненный). По крайней мере, так я его прочитал. Я ожидал бы смещения 16 ** или ** адрес '0x4022c8' (' == 0x4022b8 + 16') где-нибудь. Однако я собираюсь взглянуть на вашу ссылку. – bitmask

+0

В описании виртуальной таблицы (категория 3) есть много предостережений. Вы знаете описание грамматики для этого? – bitmask