Динамический полиморфизм возможен благодаря сочетанию двух средств: наследования и виртуальных функций. О механизме наследования вы узнали в предыдущей главе. Здесь же вы познакомитесь с виртуальными функциями.
Виртуальная функция — это функция, которая объявляется в базовом классе с использованием ключевого слова virtual и переопределяется в одном или нескольких производных классах. Таким образом, каждый производный класс может иметь собственную версию виртуальной функции. Интересно рассмотреть ситуацию, когда виртуальная функция вызывается через указатель (или ссылку) на базовый класс. В этом случае C++ определяет, какую именно версию виртуальной функции необходимо вызвать, по типу объекта, адресуемого этим указателем. Причем следует иметь в виду, что это решение принимается во время выполнения программы. Следовательно, при указании на различные объекты будут вызываться и различные версии виртуальной функции. Другими словами, именно по типу адресуемого объекта (а не по типу самого указателя) определяется, какая версия виртуальной функции будет выполнена. Таким образом, если базовый класс содержит виртуальную функцию и если из этого базового класса выведено два (или больше) других класса, то при адресации различных типов объектов через указатель на базовый класс будут выполняться и различные версии виртуальной функции. Аналогичный механизм работает и при использовании ссылки на базовый класс.
Чтобы объявить функцию виртуальной, достаточно предварить ее объявление ключевым словом virtual.
Функция объявляется виртуальной в базовом классе с помощью ключевого слова virtual. При переопределении виртуальной функции в производном классе ключевое слово virtual повторять не нужно (хотя это не будет ошибкой).
Класс, который включает виртуальную функцию, называется полиморфным классом.
Класс, который включает виртуальную функцию, называется полиморфным классом. Этот термин также применяется к классу, который наследует базовый класс, содержащий виртуальную функцию.
Рассмотрим следующую короткую программу, в которой демонстрируется использование виртуальных функций.
// Пример использования виртуальных функций.
#include <iostream>
using namespace std;
class base {
public:
virtual void who() {
// объявление виртуальной функции
cout << "Базовый класс.\n";
}
};
class first_d : public base {
public:
void who() {
// Переопределение функции who() для
// класса first_d.
cout << "Первый производный класс.\n";
}
};
class second_d : public base {
public:
void who() {
// Переопределение функции who() для
// класса second_d.
cout << "Второй производный класс.\n";
}
};
int main()
{
base base_obj;
base *p;
first_d first_obj;
second_d second_obj;
p = &base_obj;
p->who(); // доступ к функции who() класса base
p = &first_obj;
p->who(); // доступ к функции who() класса first_d
p = &second_obj;
p->who(); // доступ к функции who() класса second_d
return 0;
}
При выполнении эта программа генерирует такие результаты.
Базовый класс.
Первый производный класс.
Второй производный класс.
Теперь рассмотрим код этой программы подробно, чтобы понять, как она работает.