Программирование. Принципы и практика использования C++ Исправленное издание
Шрифт:
Shape
: информация о том, какая функция будет на самом деле вызываться при обращении к функции draw_lines
из класса Shape
. Для этого обычно в таблицу функций заносится ее адрес. Эта таблица обычно называется vtbl
(таблица виртуальных функций), а ее адрес часто имеет имя vptr
(виртуальный указатель). Указатели обсуждаются в главах 17-18; здесь они действуют как ссылки. В конкретных реализациях
vptr
и указатели vtbl
к нашему рисунку, получим следующую диаграмму. Поскольку функция
draw_lines
— первая виртуальная функция, она занимает первую ячейку в таблице vtbl
, за ней следует функция move
, вторая виртуальная функция. Класс может иметь сколько угодно виртуальных функций; его таблица vtbl
может быть сколь угодно большой (по одной ячейке на каждую виртуальную функцию). Теперь, когда мы вызовем функцию x.draw_lines
, компилятор сгенерирует вызов функции, найденной в ячейке draw_lines
таблицы vtbl
, соответствующей объекту x
. В принципе код просто следует по стрелкам на диаграмме. Итак, если объект
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
вместо соответствующей функции из базового класса, называется замещением (overriding). Например, функция Circle::draw_lines
замещает функцию Shape::draw_lines
. Почему
vtbl
и схемах размещения в памяти? Нужна ли нам эта информация, чтобы использовать объектно-ориентированное программирование? Нет. Однако многие люди очень хотят знать, как устроены те или иные механизмы (мы относимся к их числу), а когда люди чего-то не знают, возникают мифы. Мы встречали людей, которые боялись использовать виртуальные функции, “потому что они повышают затраты”. Почему? Насколько? По сравнению с чем? Как оценить эти затраты? Мы объяснили модель реализации виртуальных функций, чтобы вы их не боялись. Если вам нужно вызвать виртуальную функцию (для выбора одной из нескольких альтернатив в ходе выполнения программы), то вы не сможете запрограммировать эту функциональную возможность с помощью другого языкового механизма, который работал бы быстрее или использовал меньше памяти, чем механизм виртуальных функций. Можете сами в этом убедиться. 14.3.2. Вывод классов и определение виртуальных функций
Мы указываем, что класс является производным, упоминая базовый класс перед его именем. Рассмотрим пример.
struct Circle:Shape { /* ... */ };
struct
, являются открытыми (см. раздел 9.3) и наследуют открытые члены класса. Можно было бы написать эквивалентный код следующим образом:
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. Замещение
Поделиться:
Популярные книги
Физрук 2: назад в СССР
2. Физрук
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
На границе империй. Том 2
2. Фортуна дама переменчивая
Фантастика:
космическая фантастика
7.35
рейтинг книги
Последний Паладин
1. Путь Паладина
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Маленькая хозяйка большого герцогства
2. Герцогиня
Любовные романы:
любовно-фантастические романы
7.80
рейтинг книги
Под маской моего мужа
Любовные романы:
современные любовные романы
5.67
рейтинг книги
Главная роль 3
3. Главная роль
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Дракон
5. Совсем не герой
Фантастика:
фэнтези
попаданцы
9.31
рейтинг книги
Мне нужна жена
Любовные романы:
современные любовные романы
6.88
рейтинг книги
Кротовский, сколько можно?
5. РОС: Изнанка Империи
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Черный дембель. Часть 4
4. Черный дембель
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Идеальный мир для Лекаря 22
22. Лекарь
Фантастика:
юмористическое фэнтези
аниме
фэнтези
5.00
рейтинг книги
Он тебя не любит(?)
Любовные романы:
современные любовные романы
7.46
рейтинг книги
Довлатов. Сонный лекарь
1. Не вывожу
Фантастика:
альтернативная история
аниме
5.00
рейтинг книги
Газлайтер. Том 16
16. История Телепата
Фантастика:
боевая фантастика
попаданцы
аниме
5.00