* Виртуални функции
Публикувано на 14 ноември 2008 в раздел С/С++.
Виртуалната функция e член-функция, която се дефинира в базовия клас и се предефинира в производния клас. Както и при виртуалните класове ключовата дума е virtual. Когато виртуална функция се предефинира в производен клас, ключовата дума virtual не е необходима. Чрез виртуалните функции се постига също "полиморфизъм по време на изпълнение". За целта виртуалната функция трябва да бъде извикана посредством указател. Когато указател към базов клас сочи към обект от производен клас, съдържащ виртуална функция, и тази функция се извика посредством указател, С++ решава коя версия на функцията ще бъде извикана въз основа на типа на обекта, сочен от указателя. Именно това решение се взема по време на изпълнение.
Пример: Следната програма създава общ базов клас, наречен area, който съдържа двата размера на една фигура. Той също така декларира чисто виртуална функция getarea(), която е предефинирана от производните класове, и връща лицето на типа фигура, дефинирана от производния клас.
#include "stdafx.h" #include "iostream.h" class area { double dim1, dim2; public: void setarea(double d1, double d2) { dim1 = d1; dim2 = d2; } void getdim(double &d1, double &d2) { d1 = dim1; d2 = dim2; } virtual double getarea() = 0; }; class rectangle : public area { public: double getarea() { double a, b; getdim(a, b); return a*b; } }; class triangle : public area { public: double getarea() { double a, ha; getdim(a, ha); return (a*ha)/2; } }; int main() { rectangle r; int a, b; cout << "Vavedete daljinata na stranata a: "; cin >> a; cout << "Vavedete daljinata na stranata b: "; cin >> b; r.setarea(a, b); triangle t; cout << "Vavedete stranata AB na triagalnik: "; cin >> a; cout << "Vavedete visochinata kam tazi strana: "; cin >> b; t.setarea(a, b); area *p; p = &r; cout << "Pravoagalnikat ima lice: "; // Извикваме виртуалната функция от клас area cout << p->getarea() << endl; p = &t; cout << "Liceto na triagalnika e: "; // Отново извикваме виртуалната функция от клас area // но тя вече сочи съм getarea() от triangle cout << p->getarea(); cout << endl; return 0; }
Инстанция на абстрактен клас НЕ може да се прави. Не съм споменал в статията обаче какво е абстрактен клас.
Когато в един клас има виртуална функция, то той не е обезателно абстрактен. Класът става абстрактен когато функцията е т.нар. "pure virtual function" или както е в нашия случай:
virtual double getarea() = 0;
С така дефинирана виртуална функция класът Е абстрактен и НЕ може да се прави инстанция. Нищо обаче не ни спира да създаваме указатели. В горния пример аз съм създал "указател към обект от клас area", а не "инстанция на обект от клас area". На този указател пък присвояваме стойност на адрес не на обект от тип area (такъв не можем да създадем), а на обект от тип "rectangle" или "triangle", т.е. получава се "полиморфизъм".
Както казах обаче може да имаме виртуална функция в клас и въпреки това да направим инстанция на обект. Например промени горния код с:
virtual double getarea(){
cout << "I do not know how to calculate the area";
}
Така вече ще можеш да правиш инстанция на area (този клас вече не е абстрактен).
Много интересен пример. Може ли да създаваме инстанции на абстрактен клас? От това, което сме учили досега стана ясно, че абстрактните класове се използват само, за да бъдат наследявани, но НЕ и да им се създават инстанции.
Ясно.