Добавил:
владимир Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ООП_С++ / Лабы / ООП_Лабораторная работа №5.doc
Скачиваний:
0
Добавлен:
17.08.2025
Размер:
261.12 Кб
Скачать

Виртуальные функции и полиморфизм

Механизм виртуальных функций в ООП используется для создания метода, предназначенного для работы с различными (по типам) объектами. Например методы ввода-вывода необходимы для всех объектов производных классов, поэтому целесообразно их определять в базовом классе, а затем переопределять в производных классах.

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

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

Итак, для включения механизма позднего (динамического) связывания необходимо выполнение следующих условий:

  • в базовом классе определяется прототип функции и объявляется как virtual

  • в производных классах функция переопределяется

  • обращение к функции выполняется через указатель базового класса

Пример 5: Объявим в базовом классе виртуальную функцию show ()

class point

{. . .

virtual void show ()

{ cout<<x<<'\t'<<y<<endl;}

};

В производных классах circ и сylinder определение функций остается без изменений. Обращаем внимание на то, что указатель базового класса может адресовать объекты как базового, так и производного класса.

int _tmain(int argc, _TCHAR* argv[])

{point p1(1,2),*pp;

cout<<"-------p1-----"<<endl;

pp=&p1; // Указатель базового класса связываем с точкой

pp->show(); // печать информации о точке

circ s1(1,2,3);

cout<<"-------s1-----"<<endl;

pp=&s1; // Указатель базового класса связываем с окружностью

pp->show(); // печать информации об окружности

cylinder c2(0,10,15,50);

pp=&c1; // Указатель базового класса связываем с цилиндром

pp->show(); // печать информации о цилиндре

system("pause");

return 0;

}

Как легко заметить, в отличие от предыдущего примера 4 ,где функцию вызывал объект класса ( вызов p1.show() и т.п.), в примере 5 по внешнему виду невозможно определить функция какого класса будет вызываться (вызов pp->show() не несет этой информации), поэтому как всегда при динамической работе, все определяет контекст работы программы.

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

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

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

  3. Хотя деструктор может быть виртуальным, но конструктор виртуальным быть не может.

Если в производном классе виртуальная функция не переопределяется, то тогда используется ее версия из базового класса. Например, если закомментировать функцию show() в классе cylinder, то увидим: circle : x=2 y=3 r=6 p=37.68 q=113.04

int main(int argc, char* argv[])

{ . . .

cylinder c1,c2(0,10,15,50),c3(s2,9);

pp= &c3; //указатель связывается с объектом класса Cylinder

pp->show(); // вызывается show() класса circ

}

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