Использование виртуальных функций
Полиморфизм иногда характеризуется одной фразой: "Один интерфейс – много методов". Это означает, что основной класс операций может быть оформлен в одном стиле, а конкретные действия могут быть различными. Перегрузка функций или операций - это пример полиморфизма во время компиляции. Во время выполнения это достигается использованием указателей на базовые классы и виртуальных функций.
Виртуальные функции - это функции, которые объявляются с помощью ключевого слова 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-ный класс может ссылаться на предыдущие производные классы, тогда схема наследования будет иметь вид:
В этом случае каждый объект класса D будет иметь два подобъекта класса base. Чтобы избежать неоднозначности при обращении к членам базового класса, можно объявить этот базовый класс виртуальным. Для этого используется зарезервированное слово virtual, то же, что при объявлении виртуальных функций
class X: virtual public Base {...};
class Y: virtual public Base {...};
class D: public X, public Y ...;
Теперь класс D имеет только один подъобъект класса base. Для этого примера Схема наследования:
При обычном наследовании объект производного класса содержит в своем составе подобъект базового класса, тогда как при виртуальном наследовании объект производного класса содержит скрытый указатель на подобъект виртуального базового класса. Этот указатель компилятор неявно использует при работе с объектом для доступа к членам-данным, унаследованным от виртуального базового класса.
4 ОРГАНИЗАЦИЯ ВЫПОЛНЕНИЯ КУРСОВОЙ РАБОТЫ
Целью выполнения курсовой работы является закрепление теоретических знаний и отработка практических навыков работы на ПК и программирования.
Выполнение курсовой работы рассчитано на один семестр и предполагает аудиторные занятия и самостоятельную работу студентов. Каждому студенту выдается задание, подписанное руководителем.