Ответ
Таблица виртуальных функций (vtable) — это внутренний механизм компилятора C++ для реализации динамического полиморфизма (позднего связывания). Для каждого класса, содержащего виртуальные функции, компилятор неявно создает массив указателей на эти функции. Каждый объект такого класса содержит скрытый указатель (vptr) на vtable своего класса.
Как это работает:
- Компилятор создает уникальную vtable для каждого полиморфного класса.
- В конструкторе объекта указатель vptr инициализируется адресом vtable соответствующего класса.
- При вызове виртуальной функции через указатель или ссылку на базовый класс, код:
- Через vptr находит vtable объекта.
- По фиксированному смещению в vtable находит адрес нужной функции.
- Вызывает эту функцию.
Пример:
#include <iostream>
class Base {
public:
virtual void func1() { std::cout << "Base::func1n"; }
virtual void func2() { std::cout << "Base::func2n"; }
virtual ~Base() {} // Виртуальный деструктор обязателен для полиморфных классов
};
class Derived : public Base {
public:
void func1() override { std::cout << "Derived::func1n"; } // Переопределение
// func2() не переопределена, в vtable Derived будет указатель на Base::func2
};
int main() {
Base* obj = new Derived(); // vptr объекта указывает на vtable класса Derived
obj->func1(); // Вызовется Derived::func1 через vtable
obj->func2(); // Вызовется Base::func2 через vtable
delete obj;
return 0;
}
Вывод:
Derived::func1
Base::func2
Накладные расходы:
- Память: Один дополнительный указатель (vptr) на каждый объект + память на саму vtable.
- Время: Двойное разыменование указателя при вызове (vptr -> vtable -> функция) и потеря возможностей инлайнинга.