Указатель инкрементируется и декрементируется относительно своего базового типа. Следовательно, если указатель на базовый класс используется для доступа к объекту производного типа, инкрементирование или декрементирование не заставит его ссылаться на следующий объект производного класса. Вместо этого он будет указывать на следующий объект базового класса. Таким образом, инкрементирование или декрементирование указателя на базовый класс следует расценивать как некорректную операцию, если этот указатель используется для ссылки на объект производного класса.

Тот факт, что указатель на базовый тип можно использовать для ссылки на любой объект, выведенный из базового, чрезвычайно важен и принципиален для C++. Как будет показано ниже, эта гибкость является ключевым моментом для способа реализации динамического полиморфизма в C++.

Ссылки на производные типы

Подобно указателям, ссылку на базовый класс также можно использовать для доступа к объекту производного типа. Эта возможность особенно часто применяется при передаче аргументов функциям. Параметр, который имеет тип ссылки на базовый класс, может принимать объекты базового класса, а также объекты любого другого типа, выведенного из него.

Виртуальные функции

Динамический полиморфизм возможен благодаря сочетанию двух средств: наследования и виртуальных функций. О механизме наследования вы узнали в предыдущей главе. Здесь же вы познакомитесь с виртуальными функциями.

Виртуальная функция — это функция, которая объявляется в базовом классе с использованием ключевого слова virtual и переопределяется в одном или нескольких производных классах. Таким образом, каждый производный класс может иметь собственную версию виртуальной функции. Интересно рассмотреть ситуацию, когда виртуальная функция вызывается через указатель (или ссылку) на базовый класс. В этом случае C++ определяет, какую именно версию виртуальной функции необходимо вызвать, по типу объекта, адресуемого этим указателем. Причем следует иметь в виду, что это решение принимается во время выполнения программы. Следовательно, при указании на различные объекты будут вызываться и различные версии виртуальной функции. Другими словами, именно по типу адресуемого объекта (а не по типу самого указателя) определяется, какая версия виртуальной функции будет выполнена. Таким образом, если базовый класс содержит виртуальную функцию и если из этого базового класса выведено два (или больше) других класса, то при адресации различных типов объектов через указатель на базовый класс будут выполняться и различные версии виртуальной функции. Аналогичный механизм работает и при использовании ссылки на базовый класс.

Чтобы объявить функцию виртуальной, достаточно предварить ее объявление ключевым словом virtual.

Функция объявляется виртуальной в базовом классе с помощью ключевого слова virtual. При переопределении виртуальной функции в производном классе ключевое слово virtual повторять не нужно (хотя это не будет ошибкой).

Класс, который включает виртуальную функцию, называется полиморфным классом.

Класс, который включает виртуальную функцию, называется полиморфным классом. Этот термин также применяется к классу, который наследует базовый класс, содержащий виртуальную функцию.

Рассмотрим следующую короткую программу, в которой демонстрируется использование виртуальных функций.

// Пример использования виртуальных функций.

#include

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;

Перейти на страницу:

Все книги серии Изучайте C++ с профессионалами

Похожие книги