Итак, если объект x
Circle
, будет вызвана функция Circle::draw_lines()
. Если объект x
относится к типу, скажем, Open_polyline
, который использует таблицу vtbl
точно в том виде, в каком ее определил класс Shape
, то будет вызвана функция Shape::draw_lines()
. Аналогично, поскольку в классе Circle
не определена его собственная функция move()
, при вызове x.move()
будет выполнена функция Shape::move()
, если объект x
относится к классу Circle
. В принципе код, сгенерированный для вызова виртуальной функции, может просто найти указатель vptr
и использовать его для поиска соответствующей таблицы vtbl
и вызова нужной функции оттуда. Для этого понадобятся два обращения к памяти и обычный вызов функции, — быстро и просто.Класс Shape
Shape
, но класс Open_polyline
имеет точно такую же простую структуру, поскольку не добавляет никаких данных-членов и не определяет виртуальную функцию. Таблица виртуальных функций vtbl
определяется для каждого класса, в котором определена виртуальная функция, а не для каждого объекта, поэтому таблицы vtbl
незначительно увеличивают размер программы.Обратите внимание на то, что на рисунке мы не изобразили ни одной невиртуальной функции. В этом не было необходимости, поскольку об этих функциях мы не можем сказать что-то особенное и они не увеличивают размеры объектов своего класса. Определение функции, имеющей то же имя и те же типы аргументов, что и виртуальная функция из базового класса (например, Circle::draw_lines()
vtbl
вместо соответствующей функции из базового класса, называется Circle::draw_lines()
замещает функцию Shape::draw_lines()
.Почему мы говорим о таблицах vtbl
14.3.2. Вывод классов и определение виртуальных функций
Мы указываем, что класс является производным, упоминая базовый класс перед его именем. Рассмотрим пример.
struct Circle:Shape { /* ... */ };
struct
class Circle : public Shape { public: /* ... */ };
Эти два объявления класса Circle
Не забудьте указать слово public
class Circle : Shape { public: /* ... */ }; // возможно, ошибка
В этом случае класс Shape
Circle
, а открытые функции-члены класса Shape
становятся недоступными для класса Circle
. Вряд ли вы стремились к этому. Хороший компилятор предупредит вас о возможной ошибке. Закрытые базовые классы используются, но их описание выходит за рамки нашей книги.Виртуальная функция должны объявляться с помощью ключевого слова virtual
virtual
указывать не надо.struct Shape {
// ...
virtual void draw_lines() const;
virtual void move();
// ...
};
virtual void Shape::draw_lines() const { /* ... */ } // ошибка
void Shape::move() { /* ... */ } // OK
14.3.3. Замещение