Що таке віртуальні таблиці?
У C++ віртуальні таблиці (v-tables) — це механізм, який підтримує поліформізм під час виконання. Вони дозволяють похідним класам перекривати функції з базових класів, що забезпечує динамічну поведінку залежно від типу об'єкта. Давайте розберемо цей концепт на простому прикладі з птахами, такими як "ворона" та поведінка "літати".
Пояснення прикладу:
Базовий клас і віртуальна функція:
Базовий клас (наприклад, Bird) оголошує віртуальну функцію для поведінки (наприклад, fly()).
Загалом,
Віртуальні функції гарантують, що функція, яка буде виконуватись, визначається під час виконання, залежно від фактичного типу об'єкта (наприклад, Crow).
- Похідний клас:
Похідні класи, такі як Crow, перекривають віртуальну функцію базового класу для реалізації конкретної поведінки.
- Механізм віртуальної таблиці:
Кожен клас з віртуальними функціями має v-table, що фактично є таблицею вказівників на віртуальні функції, які об'єкти цього класу можуть викликати.
Як це працює:
Кожен об'єкт такого класу містить вказівник на v-table класу. Коли на об'єкті викликається віртуальна функція, для визначення правильної функції, яку потрібно викликати, звертаються до v-table.
Приклад коду:
#include
using namespace std;
// Базовий клас
class Bird {
public:
virtual void fly() { // Віртуальна функція
cout << "Bird flies in general." << endl;
}
virtual ~Bird() {} // Віртуальний деструктор для коректного очищення
};
// Похідний клас
class Crow : public Bird {
public:
void fly() override { // Перекриття функції базового класу
cout << "Crow flies in a unique way." << endl;
}
};
int main() {
Bird* bird1 = new Bird(); // Об'єкт базового класу
Bird* bird2 = new Crow(); // Об'єкт похідного класу
bird1->fly(); // Викликає Bird::fly()
bird2->fly(); // Викликає Crow::fly() завдяки v-table
delete bird1;
delete bird2;
return 0;
}
o/p : Bird flies in general.
Crow flies in a unique way.
Пояснення:
- Коли створюється об'єкт Bird:
Його вказівник v-table вказує на v-table класу Bird.
v-table містить вказівник на Bird::fly().
- Коли створюється об'єкт Crow:
Його вказівник v-table вказує на v-table класу Crow.
v-table містить вказівник на Crow::fly(), який перекриває Bird::fly().
При виклику fly() через bird1->fly() або bird2->fly() програма звертається до вказівника v-table в об'єкті, щоб визначити, яку функцію викликати.
Ключові моменти:
Віртуальні таблиці дозволяють динамічну диспетчеризацію, що дає змогу викликати правильну функцію для фактичного типу об'єкта.
Якби fly() не було оголошено як віртуальну, виклики функцій вирішувалися б на етапі компіляції (статична диспетчеризація), і bird2->fly() неправильно викликав би Bird::fly().
Висновок:
Віртуальні таблиці в C++ схожі на каталог, який допомагає об'єктам вирішити, яку версію функції викликати під час виконання.
Це гарантує, що якщо об'єкт Crow
буде оброблений як Bird
, він все одно використовуватиме поведінку Crow
при виклику функції fly()
.
Перекладено з: THE BASICS : VIRTUAL TABLES IN C++