2017-01-16 3 views
1

У меня есть некоторые конкретные вопросы о виртуальных деструкторах и vtable.Виртуальный деструктор C++ & vtable

Предположим, у меня есть следующий код:

class Base 
{ 
public: 

    virtual ~Base(); 

}; 

class Child : public Base 
{ 
public: 

    ~Child(); 
}; 

Вопросы:

  1. Где сохраненную виртуальные таблицы? Всегда ли это в базовом классе, и все подклассы просто содержат указатель на него?
  2. Добавление виртуального метода только увеличивает размер (класс) на 8 байтов вправо? (предположим, 64-битная система) Как насчет базового класса, если он хранит таблицу?
  3. Создание экземпляра типа Child через новый оператор, а затем удаление ... будет вызван деструктор базы? (Я спрашиваю, потому что деструктор класса Child не является виртуальным ... означает ли это, что это влияет только на подкласс Child?).
+2

* 1 и 2: * осуществление определено. * 3: * Да. – DeiDei

+5

Я предполагаю, что вы имели в виду 'Ребенок' на самом деле быть дочерним классом' Базы'? –

+0

1. (a) Каждый класс должен иметь свою собственную таблицу vtable, иначе техника не может работать. (б) В действительности нет такой вещи, как «в классе». 2. поэтому не имеет значения. 3. Деструктор ребенка * является * виртуальным, если базовый класс. – EJP

ответ

3

В приведенном ниже объяснении предполагается, что реализация виртуальной диспетчеризации, используемая компилятором, основана на виртуальных таблицах.

  1. Каждый класс с виртуальными методами (объявлен или унаследован) имеет свою собственную виртуальную таблицу. Если подкласс переопределяет функцию виртуального члена в базе, указатель на функцию переопределения помещается в таблицу vtable класса; в противном случае указатель на реализацию базового класса сохраняется на месте.

  2. Добавление первой виртуальной функции увеличивает размер класса экземпляр на размер указателя vtable. Виртуальные функции после первого не добавляют к размеру экземпляра.

  3. С ~Base является виртуальным, ~Child также является виртуальным, хотя ключевое слово virtual опущено. В случае переопределения ключевое слово virtual является необязательным.

+0

Я не понимаю, почему ответ основан на предположениях (логические предположения, чтобы быть правдой), а не происхождение вопроса. Основной язык между программистами - это код, а код отрицает предположение –

+2

@JacekCz. Из всего остального ясно, что он забыл добавить ': public Base' в' Child'. – dasblinkenlight

+0

"указатель на функцию переопределения помещается в копию" Что подразумевается под "копией" в этом контексте? –

2

Создание экземпляра типа ребенка с помощью нового оператора, то удалить ... будет База деструктор называться?

Не в исходном коде вопрос, потому что вы не имеете Child унаследовав от Base.

Предполагая, что это ошибка, и мы исправим его, тогда будет вызываться ~Base, когда вы уничтожаете Child, даже если он не является виртуальным, только потому, что под-объект базового класса уничтожается как часть нормальной последовательности уничтожения ,

Причина для виртуальных деструкторов поэтому вы можете удалить ChildчерезBase * и до сих пор ~Child вызывается правильно.

Например, с:

struct Base { ~Base(); }; 
struct Child: Base { ~Child(); }; 

struct VBase { virtual ~VBase(); }; 
struct VChild: VBase { ~VChild(); }; 

это работает для обеих иерархий:

template <typename Derived> 
void test_static() { 
    Derived d; 
} 
test_static<Child>(); // ~Child then ~Base invoked when d is destroyed 
test_static<VChild>(); // ~VChild then ~VBase invoked when d is destroyed 

, но это работает только с виртуальным деструктора:

template <typename Derived, typename Base> 
void test_dynamic() { 
    std::unique_ptr<Base> p(new Derived); 
} 
test_dynamic<Child, Base>; // only ~Base invoked when p destroyed 
test_dynamic<VChild,VBase>; // ~VChild then ~VBase invoked as before. 

Что касается vtable вопросов, это деталь реализации, существует ли она, и если да, то где она есть, и вам не нужно беспокоиться об этом.

Смежные вопросы