Использование виртуальных функций

Полиморфизм иногда характеризуется одной фразой: "Один интерфейс – много методов". Это означает, что основной класс операций может быть оформлен в одном стиле, а конкретные действия могут быть различны­ми. Перегрузка функций или операций - это пример полиморфизма во время компиляции. Во время выполнения это достигается использованием указа­телей на базовые классы и виртуальных функций.

Виртуальные функции - это функции, которые объявляются с помощью ключевого слова virtual в базовом классе и переопределяются в одном или нескольких производных классах. При этом прототипы функций в раз­ных классах одинаковы. Если типы функций различны, то механизм вирту­альности не включается. Если функции, объявленные виртуальными, отли­чаются только типом возвращаемого значения, то возникает ошибка.

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

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

В одном или нескольких производных классах переопределение функ­ции может отсутствовать. При этом механизм виртуальности сохраняется и вызывается функция базового класса, ближайшего к тому, где функция пе­реопределена.

Виртуальная функция должны быть членом класса. Она не может быть дру­жественной для класса, в котором определена. Однако виртуальная функ­ция может быть "другом" другого класса.

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

Вызов виртуальной функции обычно реализуется по таблице виртуаль­ных функций класса. Эта таблица создается во время компиляции, а свя­зывание происходит во время выполнения. Иногда это называется поздним связыванием.

Пример использование виртуальных функций). Определим класс figure, который описывает плоскую фигуру, для вы­числения площади которой достаточно двух измерений. В этом классе опишем виртуальную функцию show_area(), печатающую значение площади фигуры. На основании этого класса строятся другие классы, для которых определена формула вычисления площади конкретной фигуры.

#include <iostream.h> virt88.cpp

Class figure

{ protected:

double x, y;

public:

void set_dim(double i, double j = 0)

{ x = i; y = j;}

virtual void show_area()

{ cout<<"Площадь не определена для этого класса \n"; }

};

Class triangle: public figure

{ public:

void show_area()

{

cout<<"Треугольник с высотой "<<x<<" и основанием "<<y;

cout<<" имеет площадь "<<x*y/2<<"\n";

}

};

Class rectangle: public figure

{public:

void show_area()

{

cout<<"Прямоугольник со сторонами "<< x <<" и "<<y;

cout<<" имеет площадь "<<x*y<<"\n";

}

};

Class circle: public figure

{public:

void show_area()

{

cout<<"Круг с радиусом "<<x;

cout<<" имеет площадь "<< 3.14159*x*x << "\n";

}

};

Void main()

{

figure f, *p; // объявление указателя на базовый тип

triangle t; // создание объекта производного типа

rectangle s;

circle c;

p=&f; p->set_dim(1,2);

p->show_area();

p=&t; p->set_dim(3,4); // Одинаковый вызов в трех случаях! p->show_area();

p=&s; p->set_dim(5,6);

p->show_area();

p=&c; p->set_dim(8); // Второй параметр задается по умолчанию,

p->show_area(); // хотя можно было бы его задать любым (не исп.)

}

Виртуальная функция в базовом классе может не определяться (тело функции отсутствует), тогда она записывается следующим образом:

virtual void show( ) //=0;

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

Виртуальные базовые классы

При множественном наследовании базовый класс не может быть задан в производном более одного раза. (Нельзя: class D: Base, Base...;)

В то же время базовый класс может быть передан производному клас­су несколько раз косвенно

class X: public Base ...;

class Y: public Base ...;

class D: public X, public Y ...;

Таким образом разные производные классы могут ссылаться на один и тот же базо­вый класс, а некоторый n-ный класс может ссылаться на предыдущие производные классы, тогда схема наследования будет иметь вид:

Использование виртуальных функций - student2.ru

В этом случае каждый объект класса D будет иметь два подобъекта класса base. Чтобы избежать неоднозначности при обращении к членам ба­зового класса, можно объявить этот базовый класс виртуальным. Для этого используется зарезервированное слово virtual, то же, что при объявлении виртуальных функций

class X: virtual public Base {...};

class Y: virtual public Base {...};

class D: public X, public Y ...;

Теперь класс D имеет только один подъобъект класса base. Для это­го примера Схема наследования:

Использование виртуальных функций - student2.ru

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

4 ОРГАНИЗАЦИЯ ВЫПОЛНЕНИЯ КУРСОВОЙ РАБОТЫ

Целью выполнения курсовой работы является закрепление теоретических знаний и отработка практических навыков работы на ПК и программирования.

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

Наши рекомендации