10.5. Полиморфизъм
C++ включва такова свойство катоpolymorphism- способността за обекти от различни класове, свързани чрез наследяване, да реагират по различен начин при достъп до една и съща членска функция. Ако, например, класътПравоъгълник(правоъгълник) е извлечен от класаЧетириъгълник(четириъгълник), тогава обект от класПравоъгълникепо-специфична версия на обект от класЧетириъгълник.Операция (като изчисляване на периметър или площ), която може да бъде извършена върху обект от класЧетириъгълник ,може също да се изпълни върху обект от класПравоъгълник.
Полиморфизмът се реализира чрез виртуални функции. Когато използвате виртуална функция, ако заявката е направена с помощта на указател на базов клас (или референция), тогава C++ избира правилната заменена функция в съответния производен клас, свързан с дадения обект.
Понякога функция-член не е дефинирана като виртуална в базовия клас, но е заменена в производния клас. Ако такава функция член се извиква чрез указател на базов клас, тогава се използва версията на базовия клас. Ако тази функция член се извиква чрез указател на производен клас, тогава се използва версията на производния клас. Това не е полиморфно поведение.
Разгледайте следния пример, който използва основния класEmployee(служители) и производния класHourlyWorker(почасови работници), показани на Фигура 1. 9.5.
Служител e, *ePtr = &e;
HourlyWorker h, *hPtr = &h;
ePtr '->печат; // извикване на функцията-елемент print на базовия клас
hPtr->печат; // извикване на функцията-елемент print на производния клас
Нашият базов класСлужителии производен класкласHourlyWorkerима свои собствени функцииprint,които са дефинирани в тези класове. Тъй като тези функции не са декларирани виртуални и имат еднаква сигнатура, извикването на функциятаprintчрез указателя на класаEmployeeводи до извикване на функциятаprintот базовия класEmployee,, т.е. изпълнява се операциятаEmployee::print() и извикването на функциятаprintчрез указателя на класаHourlyWorkerводи до извикване на функциятаprintот производния класHourlyWorker.Функцията на базовия класprintсъщо е член на производния клас, но при извикване на функциятаprintна de rived клас обект, вариантът на базовия клас на функцията трябва да бъде извикан изрично, както следва:
Този запис изрично указва, че трябва да се извика функцията на базовия класprint.
Виртуални функции и полиморфизъм601
Чрез използването на виртуални функции и полиморфизъм, извикването на членска функция може да доведе до различни действия в зависимост от типа на обекта, който се извиква (ще видим по-късно, че това изисква малко излишни разходи). Такова полиморфно поведение предоставя на програмиста огромни възможности. В следващите няколко раздела ще видим примери, които демонстрират колко мощни са полиморфизмът и виртуалните функции.
Бележка за техниката на програмиране 10.6
Благодарение на виртуалните функции и полиморфизма, софтуерът може да контролира общите свойства на обектите, позволявайки на софтуерната среда да се „погрижи“ за спецификата на обектите по време на изпълнение на програмата. Програмистът може да манипулира широк набор от обекти, без дори да знае техните типове, иуправлението автоматично ще вземе предвид спецификата на тези обекти.
Бележка за техниката на програмиране 10.7
Полиморфизмът насърчава разширяемостта: софтуерът, който използва механизма на полиморфизма, е написан независимо от типовете обекти, към които се изпращат съобщения. По този начин нови типове обекти, които трябва да отговарят на подходящи съобщения, могат да бъдат включени в такава система, без да се променя нейната основа. С изключение на потребителския код, който създава нови обекти, програмата няма да изисква повторно компилиране.
Бележка за техниката на програмиране 10.8
Абстрактен клас дефинира интерфейс за различни типове елементи от класова йерархия. Абстрактният клас включва чисти виртуални функции, които трябва да бъдат дефинирани в производни класове. Всички функции в йерархията могат да използват един и същ интерфейс, използвайки полиморфизъм.
Въпреки че не можем да създаваме обекти от абстрактен базов клас, можемда декларираме указатели към абстрактен базов клас. След това тези указатели могат да се използват за предоставяне на възможност за полиморфно опериране с обекти от производни конкретни класове.
Помислете за използването на полиморфизъм и виртуални функции. Екранният мениджър трябва да показва много обекти, включително нови типове обекти, които ще бъдат включени в системата дори след като самата програма за екранен мениджър е написана. Може да се наложи системата да покаже различни форми (основният клас за тях е класът Shape), като квадрати, кръгове, триъгълници, правоъгълници и т.н. Всеки от тези класове форми произлиза от базовия клас Shape. Мениджърът на екрана използва указатели на базов клас (указатели към Shape), за дауправление на всички обекти, показани на екрана. За да начертае обект (независимо от нивото, на което обектът е в йерархията на наследяване), администраторът на екрана използва указателя на базовия клас към обекта и просто изпраща съобщение до обекта: "начертай". Функцията за рисуване е декларирана като чиста виртуална функция в базовия клас Shape и трябва да бъде повторно внедрена във всеки от производните класове. Всеки обект от базов клас Shape "знае как да рисува сам". Администраторът на екрана не трябва да се интересува