2016-08-26 3 views
-5

У меня есть путаница в отношении vtable после прочтения более подробной информации о mangling. напра:Разрешение функции от vtable в C++

class Base 
{ 
public: 
    virtual void print() 
    { 
    } 
}; 

class A : public Base 
{ 
public: 
    void hello() 
    { 
     .... 
    } 

    void print() 
    { 
    } 
}; 

A obj; 
obj.hello(); 

Base* test = new A(); 
test->print(); 

Согласно моему пониманию после имени manging obj.hello() вызова будет преобразован в нечто вроде _ZASDhellov(&obj) Теперь

  1. как это виртуальные функции будут вызываться из виртуальных таблиц?
  2. мое дикое предположение test->__vtable[_ZASDprintv](&test(dynamic cast to derived???)) верное?
  3. Как имена функций разрешены из таблицы vtable?
+4

'A :: hello()' не является виртуальной функцией. – tkausl

+0

Нет виртуальных функций и, следовательно, нет vtable в коде, который вы показываете. –

+0

Я знаю.если это виртуальная функция, как она будет оцениваться? –

ответ

3

Во-первых, vtables никоим образом не являются частью языка C++, а скорее деталью реализации, используемой конкретными компиляторами. Ниже я описываю один из способов, который обычно используется как таковой.

Во-вторых, ваша функция hello не является виртуальной. Чтобы сделать его виртуальным, вы просто предварительно предварите объявление virtual.

Предполагая, что он теперь виртуальный: ваша догадка довольно близка. Фактически, vtable (к которому указатель хранится с каждым экземпляром виртуального класса) представляет собой массив указателей функций. То, как определенная функция просматривается в ней, - это ее порядковый номер. Первая объявленная виртуальная функция в A - первая запись в ее vtable, вторая - вторая запись и так далее. Если A имел базовый класс, индекс первой (не переопределенной) виртуальной функции A в таблице был бы n+1, где n - это индекс последней виртуальной функции его базового класса. Если A имеет более одного базового класса, их записи предшествуют записям A в порядке их объявления в качестве базовых классов A.

Если A использует виртуальное наследование, изображение немного сложнее, я не буду разбираться, если вы специально не заинтересованы.

ОБНОВЛЕНИЕ: Я добавлю краткое описание для случая виртуального наследования по запросу. Если A имеет Base как виртуальный базовый класс, A в vtable будет хранить в самом начале (перед адресами функции) смещение байта, где данные Base начинаются с объекта A. Это необходимо, потому что, в отличие от обычного наследования, базовый класс не имеет своих данных, предшествующих данным производного класса, вместо этого он следует за ним. Таким образом, любой вызов функции виртуальной функции, определенный в Base, должен иметь смещение указателя this на эту сумму. Кроме того, Base должен иметь свой собственный указатель vtable, прямо в начале своих данных, где он ожидает его найти. Таким образом, полный объект A будет содержать два указателя vtable вместо одного. Фактический vtable, на который указывает этот второй указатель, будет таким же, как первый указатель vtable, за исключением расширенного, чтобы пропустить запись смещения, описанную выше (так что любой код Base с использованием vtable найдет первую виртуальную функцию в начале, где она ожидается). Помимо этих различий, сам vtable такой же, как и раньше.

+0

Я бы назвал «Если у' А' был базовый класс, индекс «А» первый »... - мне потребовалось пару секунд, чтобы понять, что антецедент« это »был« А », а не «базовый класс». +1 для упоминания виртуального наследования (которое приближается к точке, где я говорю «потому что магия»). –

+0

Я включил ваше предложение, спасибо – Smeeheey

+0

СПАСИБО @Smeeheey Теперь картина понятна. Будет полезно, если вы сможете объяснить, использует ли A виртуальное наследование. –