490 likes | 698 Views
Виртуални функции и виртуални класове. Полиморфизъм. Виртуални функции Полиморфизмът е свойство на член-функциите и се реализира с виртуални функции .
E N D
Виртуални функции и виртуални класове Полиморфизъм. Виртуални функции • Полиморфизмът е свойство на член-функциите и се реализира с виртуални функции. • Той се състои в осигуряване възможността генерираният код да се държи по различен начин в зависимост от условия, определяни по време на изпълнението на програмата. • Идеята на тези функции се основава на вида на свързването им: • статично или ранносвързване • динамично или късно свързване
Виртуални функции и виртуални класове Полиморфизъм. Виртуални функции • Статичното свързване на типа на обекта с извикваната член-функция става по време на компилацията и не се променя при изпълнение на програмата. • Kонфликтът между имената на наследените и собствените методи от един и същ тип и с едни и същи параметри се разрешава също по време на компилация чрез правилото на локалния приоритет и чрез явно посочване на класа, към който принадлежи методът. • Свързващият редактор замества имената на извикваните функции с конкретните им адреси.
Виртуални функции и виртуални класове Полиморфизъм. Виртуални функции Пример илюстриращ статично или ранно свързване #include <iostream.h> 1/2 class point { protected: int x,y; public: point(int a=0,int b=0) { x=a; y=b; } void out() {cout<<”точка:”<<x<<” “<<y<<”\n”; } }; class pointcol:public point { short color; public: pointcol(int a=0,int b=0,short cl=1):point(a,b) { color=cl; } void out() {cout<<”оцветена точка:”<<x<<” “<<y<<” с цвят:”<<color<<”\n”; } };
Виртуални функции и виртуални класове Полиморфизъм. Виртуални функции Пример илюстриращ статично или ранно свързване void main() 2/2 { point p(3,5),*adp=&p; pointcol pc(8,6,2),*adpc=&pc; adp->out(); //извиква се out на point adpc->out();//извиква се out на pointcol adp=adpc; adp->out(); //но adp е point по време на компилация adpc->out(); } По време на изпълнението точка:3 5 оцветена точка:8 6 с цвят:2 точка:86 оцветена точка:8 6 с цвят:2 Извиква се out() от класа point
Виртуални функции и виртуални класове Полиморфизъм. Виртуални функции Пример илюстриращ статично или ранно свързване Ако искаме след свързването на adp с адреса на pc да се изпълни член-функцията out() на pointcol void main() { point p(3,5),*adp=&p; pointcol pc(8,6,2),*adpc=&pc; adp=adpc; adp->out(); adpc->out(); ((pointcol*)adp)->out(); } точка:86 оцветена точка:8 6 с цвят:2 оцветена точка:8 6 с цвят:2 Извиква се out() от класа point Извиква се out() от класа pointcol след явно преобразуване
Виртуални функции и виртуални класове Полиморфизъм. Виртуални функции • Статичното свързване предполагапо време на създаването на класа да се предвидят възможните обекти, чрез които ще се викат член-функциите му. • При сложни йерархии от класове това е не само трудно, но и понякога невъзможно. • Динамично свързване на типа на обекта с извикваната член-функция е по време на изпълнение на програмата. • При него не се налага проверка на типа.
Виртуални функции и виртуални класове Полиморфизъм. Виртуални функции • Динамично свързване • При извикването на функция се задава само името, но не и конкретния адрес на прехода. • Или по време на изпълнение се дава възможността за промяна на връзките между имена и адреси. • Текстовете на програмите се опростяват, а промени се налагат много по-рядко.
Виртуални функции и виртуални класове Полиморфизъм. Виртуални функции • Динамично свързване • Кодът се усложнява и се забавя процеса на изпълнение на програмата. • Наличието на двата механизма на свързване – статично и динамично, дава възможност на програмиста да се възползва от положителните им страни. • Прилагането на механизма на късното свързване се осъществява върху специални член-функции на класове, наречени виртуални член-функции или само виртуални функции (преддекларацията им се поставя запазената дума virtual ).
Виртуални функции и виртуални класове Полиморфизъм. Виртуални функции Пример илюстриращ динамично или късно свързване #include <iostream.h> 1/2 class point { protected: int x,y; public: point(int a=0,int b=0) { x=a; y=b; } virtualvoid out() {cout<<”точка:”<<x<<” “<<y<<”\n”; } }; class pointcol:public point { short color; public: pointcol(int a=0,int b=0,short cl=1):point(a,b) { color=cl; } void out()//също е virtual(с или без служебна дума) { cout<<”оцветена точка:”<<x<<” “<<y<<”с цвят:”<<color<,”\n”;} };
Виртуални функции и виртуални класове Полиморфизъм. Виртуални функции Пример илюстриращ динамично или късно свързване void main() 2/2 { point p(3,5),*adp=&p; pointcol pc(8,6,2),*adpc=&pc; adp->out(); //извиква се out на point adpc->out();//извиква се out на pointcol adp=adpc; adp->out(); //adp е pointcol по време на изпълнение adpc->out(); } По време на изпълнението точка:3 5 оцветена точка:8 6 с цвят:2 оцветена точка:8 6 с цвят:2 оцветена точка:8 6 с цвят:2
Виртуални функции и виртуални класове Полиморфизъм. Виртуални функции Извод • Определянето на извикваната функция е в зависимост от типа на обекта, към който сочи указателят, а не от класа към който е указателят. • Указател на базовия клас (adp) се използва за извикване на член-функции на производния клас вместо едноименните (предефинирани) функции на базовия (в случай, когато последните са virtual). • Невъзможно е: adpc=adp (съобщение за грешка).
Виртуални функции и виртуални класове Полиморфизъм. Виртуални функции #include <iostream.h> 1/2 class point { int x, y; public: point(int a=0, int b=0) { x = a; y = b; } virtual void specific() { cout << “Точка: “; } void out() { specific(); cout << x << “ “ << y << “\n”;} }; class pointcol : public point { short color; public: pointcol(int a=0, int b=0, short c=1) : point(a,b) { color = c; } virtual void specific() { cout << “Оцветена точка с цвят: “ << color << “,”; } }; Виртуална функция за специфичните действия на класа Виртуална функция за специфичните действия на класа
Виртуални функции и виртуални класове Полиморфизъм. Виртуални функции void main() 2/2 { point p(3,5), *adp; adp = &p; pointcol pc(5,9,5), *adpc; adpc = &pc; p.out(); pc.out(); adp -> out(); adpc -> out(); adp = adpc; adp -> out(); adpc -> out(); } Извиква се out() от клас point, която извиква specific() Точка: 3 5 Оцветена точка с цвят: 5,5 9 Точка: 3 5 Оцветена точка с цвят: 5,5 9 Оцветена точка с цвят: 5,5 9 Оцветена точка с цвят: 5,5 9
Виртуални функции и виртуални класове Полиморфизъм. Виртуални функции извикване на член-функция на базата на динамичния тип на викащия обект #include <iostream.h> class animal { protected: int age; public: animal(): age(1) { } virtual void speak() { cout<<”Animal speaks.\n”; } }; class dog:public animal { public: void speak() { cout<<”Baow.\n”; } }; class cat:public animal { public: void speak() { cout<<”Meow.\n”; } }; class pig:public animal { public: void speak() { cout<<”Grouch.\n”; } }; speak() ще се извиква в зависимост от това къде сочи указателя в момента на изпълнение
Виртуални функции и виртуални класове Полиморфизъм. Виртуални функции void main() { animal *a[4],*ptr; int choice; for(int i=0;i<4;i++) { cout<<”(1)dog (2)cat (3)pig:”; cin>>choice; switch(choice) { case 1: ptr=new dog; break; case 2: ptr=new cat; break; case 3: ptr=new pig; break; default:ptr=new animal; } a[i]=ptr; } for(i=0;i<4;i++) a[i]->speak(); } масив от указатели към базов клас и указател за връзка с обектите ptr се свързва с обектите по време на изпълнение (1)dog(2)cat(3)pig:1 (1)dog(2)cat(3)pig:2 (1)dog(2)cat(3)pig:3 (1)dog(2)cat(3)pig:4 Baow. Meow. Grouch. Animal speaks.
Виртуални функции и виртуални класове Полиморфизъм. Виртуални функции Някои правила • При наличие на виртуална функция – деструкторът трябва да е виртуален. • Конструкторът не може да бъде виртуален. • Ако е предефинирана виртуална функция, но с друг брой на параметрите, то това е друга функция и няма динамично свързване с нея. • Възможно е виртуална функция да се дефинира извън клас. Тогава заглавието й не започва със запазената дума virtual, т.е. запазената дума virtual може да се среща само в тялото на клас.
Виртуални функции и виртуални класове Полиморфизъм. Виртуални функции Някои правила • Ако в даден клас е декларирана виртуална функция, декларираните член-функции със същия прототип (име, параметри и тип на върнатата стойност) в производните на класа класове също са виртуални дори ако запазената дума virtual бъде пропусната. • Виртуалните функции се наследяват като другите компоненти на класа. • Виртуалните функции се извикват чрез указател към или псевдоним на обект от някакъв клас. • Виртуалните функции не могат да бъдат декларирани като приятели на други класове.
Виртуални функции и виртуални класове Множествено наследяване • Производен клас на два или повече базови point color pointcol
Виртуални функции и виртуални класове Множествено наследяване • Производният клас наследява компонентите на всички базови, като типа на наследяването се задава поотделно за всеки базов клас. class point { int x,y; . . . }; class color { int cl; . . . }; class pointcol:public point,public color { . . . }; Деклариране на производен клас на два базови класа
Виртуални функции и виртуални класове Общ вид на конструктор на производен с два базови Множествено наследяване • параметри1 (параметри2+параметри3) са параметрите на pointcol; • параметри2 са параметрите за предаване на point • параметри3 са параметрите за предаване на color • Конструкторите се извикват в реда: 1) конструктор на point; 2) конструктор на color; 3) конструктор на pointcolor. • Деструкторите се извикват в обратен ред. • Ако базов клас се явява също производен, тонаследените компоненти се използват чрез многократно задаване на операцията :: pointcol:pointcol(параметри1):point(параметри2),color(параметри3) { . . . }
Виртуални функции и виртуални класове #include <iostream.h> 1/2 class point { protected: int x, y; public: point(int a, int b) { x = a; y = b; cout <<“Конструктор point.\n”; } ~point() { cout << “Деструктор point.\n”; } void out() { cout << “Координати: “ << x << “ “ << y << “\n”; } }; class color { protected: int cl; public: color(int c=0) { cl = c; cout <<“Конструктор color.\n”; } ~color() { cout << “Деструктор color.\n”; } void out() { cout << “Цвят: “ << cl << “\n”; } }; Множествено наследяване Пример за множествено наследяване
Виртуални функции и виртуални класове Извикването на конструкторите зависи от декларацията на производния клас Множествено наследяване class pointcol : public point, public color 2/2 { public: pointcol(int a, int b, int c) : color(c),point(a,b) { cout <<“Конструктор pointcol.\n”; } ~pointcol() { cout << “Деструктор pointcol.\n”; } void out() { point :: out(); color :: out(); } }; void main() { pointcol p(3,9,2); p.out(); p.point :: out(); p.color :: out(); } Конструктор point. Конструктор color. Конструктор pointcol. Координати: 3 9 Цвят: 2 Координати: 3 9 Цвят: 2 Деструктор pointcol. Деструктор color. Деструктор point.
Виртуални функции и виртуални класове Множествено наследяване classder : publicbase2, base1, base3 {public: der(intx = 0) : base3(x), base1(x), base2(x) {d = 5; } private: intd; intb1, b2, b3; //член данни на base1, base2, base3 }; . . . der object(6); Класът има 2 собствени и 3 наследени компоненти Инициализира 4-те член данни на object с 6
Виртуални функции и виртуални класове Множествено наследяване • Чрез обект на производния клас могат да се викат всички негови public компоненти – собствени и наследени. • Ако в базовите класове са дефинирани компоненти с еднакви имена, необходимо е да се използва пълното име на компонентата. • Ако всички основни класове basei на производния клас der имат член-функция f() и член-данна x с еднакви имена, различаването им в производния клас става чрез пълните им имена: base1::f(), base2::f(), ... base1::x, base2::x, ...
Виртуални функции и виртуални класове Виртуални класове class Base { int a; . . . }; class Drv1 : public Base { . . . }; class Drv2 : public Base { . . . } class Drv3 : public Drv1, public Drv2 { . . . } Drv3 наследява двукратно Base Проблем при член данните
Виртуални функции и виртуални класове Виртуални класове • При йерархията на класове с множествено (многократно) наследяване достъпът до наследените компоненти се извършва с операцията за принадлежност (::). • Член-данните на класа Base ще се появят два пъти във всички обекти на Drv3 (през Drv1 иDrv2). • Член-функциите имат едно копие. Base :: Drv1 :: a или Base :: Drv2 :: a
Виртуални функции и виртуални класове Виртуални класове class Base 1/2 { protected: int i; ………. }; class Drv1:public Base { protected: int j; ……. }; class Drv2:public Base { protected: int k; ……… }; class Drv3:public Drv1, public Drv2 { protected: int sum ……….. }; Множествено наследяване – вариант нееднозначност
Виртуални функции и виртуални класове Виртуални класове Нееднозначност! копие на i от Drv1 или от Drv2 void main() 2/2 { Drv3 ob; ob.i=10; ob.j=20; //коректно - j има едно копие в Drv3 ob.k=30; //коректно - k има едно копие в Drv3 ob.sum=ob.j+ob.k; cout<<ob.sum; //извежда се 50 }
Виртуални функции и виртуални класове Виртуални класове class Base { protected: int i; ………. }; class Drv1:public Base { protected: int j; ……. }; class Drv2:public Base { protected: int k; ……… }; class Drv3:public Drv1, public Drv2 { protected: int sum ……….. }; Множествено наследяване – вариант на нееднозначностпремахната с оператор ::
Виртуални функции и виртуални класове Виртуални класове нееднозначността е премахнатас оператор :: void main() { Drv3 ob; ob.drv1::i=10; ob.j=20; //коректно - j има едно копие в Drv3 ob.k=30; // коректно - k има едно копие в Drv3 ob.sum=ob.j+ob.k+ob.drv1::i; cout<<ob.sum; //извежда се 60 }
Виртуални функции и виртуални класове Виртуални класове class Base { protected: int i; ………. }; class Drv1 : virtual public Base { protected: int j; ……. }; class Drv2:virtual public Base { protected: int k; ……… }; class Drv3:public Drv1, public Drv2 { protected: int sum ……….. }; дублирането е премахнато със създаване само на едно копие в Drv3
Виртуални функции и виртуални класове Виртуални класове • Променя се типът на наследяване на базовия клас от преките му наследници, като се описва, че той се наследява виртуално. Коректно е. В Drv3 има само едно копие void main() { Drv3 ob; ob.i=10; ob.j=20; //коректно - j има едно копие в Drv3 ob.k=30; // коректно - k има едно копие в Drv3 ob.sum=ob.j+ob.k+ob.i; cout<<ob.sum; //извежда се 60 Drv1 my; my.i=80; //virtual на Base не влияе на Drv1 }
Виртуални функции и виртуални класове Виртуални класове Конструктори и деструктори • Класът Base e virtual. Създаването на обект на Drv3 трябва да доведе до еднократно създаване на член-променливите на Base. • Параметрите на конструктора на Base се определят от конструктора на Drv3. • Дефинираните в конструкторите на Drv1 и Drv2 извиквания на конструктора на Base се използват само при създаване на собствените им обекти.
Виртуални функции и виртуални класове Виртуални класове Конструктори и деструктори • Ако има виртуални класове, то техните конструктори се извикват най-напред. • Редът на извикване на останалите зависи от реда на деклариране в Drv3. • Деструкторите се извикват в обратен ред.
Виртуални функции и виртуални класове Виртуални класове Пример за използване на конструктори и деструктори Базов клас - virtual Обект на pegasus ще съдържа еднократно данните на animal
Виртуални функции и виртуални класове Пример за използване на конструктори и деструктори #include <iostream.h> 1/4 enum COLOR {red,green,white,black,brown}; class animal { protected: int age public: animal(int age_n):age(age_n) { cout<<”конструктор animal\n”; } virtual ~animal() { cout<<”деструктор animal\n”; } virtual int get_age() { return age; } virtual void set_age(int age_n) { age=age_n; } }; Дефиниция на базов клас
Виртуални функции и виртуални класове Пример за използване на конструктори и деструктори class horse:virtual public animal 2/4 { protected: int height; COLOR col; public: horse(int age_n,COLOR c,int h): animal(age_n),col(c),height(h) { cout<<”конструктор horse\n”; } ~horse() { cout<<”деструктор horse\n”; } }; class bird:virtual public animal { protected: COLOR col; public: bird(int age_n,COLOR c):animal(age_n),col(c) { cout<<”конструктор bird\n”; } ~bird() { cout<<”деструктор bird\n”; } }; Дефиниция на клас наследник – I ниво Инициализират се данни на базовия класисобствени данни Дефиниция на клас наследник – I ниво
Виртуални функции и виртуални класове Пример за използване на конструктори и деструктори Дефиниция на клас наследник – II ниво class pegasus:public horse,public bird 3/4 { long nbr_believers; public: pegasus(COLOR c,int h,long n,int age_n): animal(age_n*2), horse(age_n,c,h),bird(age_n,c),nbr_beleivers(n) { cout<<”конструктор pegasus\n”; } }; аnimal (virtual) class се инициализира в конструктора на наследника на II ниво
Виртуални функции и виртуални класове Пример за използване на конструктори и деструктори void main() 4/4 { pegasus *p=new pegasus(white,5,100,2); int age=p->get_age(); cout<<”този пегас е на “<<age<<” години\n”; delete p; } конструктор animal конструктор horse конструктор bird конструктор pegasus този пегас е на 4 години деструктор pegasus . . . деструктор animal
Виртуални функции и виртуални класове Абстрактни (контейнерни) класове • Чисти виртуални функции – имат само декларации • Дефинирането на тези функции се извършва в класовете наследници. • Абстрактен клас – клас, който има поне една чиста виртуална функция. • Не се създават обекти на абстрактен клас. • Абстрактните класове служат като базови на други класове. Чрез тях се обединяват в обща структура различни йерархии.
Виртуални функции и виртуални класове Абстрактни (контейнерни) класове • Полиморфизмът позволява създаването на класове с различна логическа структура, които могат да включват обекти от други класове. • Логическата структура на класа се реализира отделно от обектите, които се включват в него. • Връзката между тях се реализира чрез указатели към контейнери, които съхраняват обекти от различни класове. • Логическата структура на контейнерните класове може да е различна – масив, списък и т.н.
Виртуални функции и виртуални класове Абстрактни (контейнерни) класове • Пример: Да се напише програма, която създава хетерогенен едносвързан списък, в който могат да съхраняват обекти от два класа: point(точка) иcomplex (комплексно число).
Виртуални функции и виртуални класове • Пример current NULL begin Обект 1 Обект 1 Обект 1 Обект 2 Обект 3
Виртуални функции и виртуални класове • Пример #include <iostream.h>1/6 #include <stddef.h> class base { public: virtual void out() = 0;//чиста виртуална функция }; struct element { element *next; //указател към следващ елемент void *content;//указател към произволен обект }; class list { element *begin; //указател към началото на списъка element *current;//указател към текущ елемнт public: list() { begin = NULL; current = begin; } ~list();
Виртуални функции и виртуални класове • Пример void new(void *); //добавя нов елемент в списъка 2/6 void first(){ current = begin; } //позициониране върху 1-ви елемент void *next_el() //връща адреса на текущия елемент { void *ad = NULL;//или NULL при последен елемент if(current != NULL)//и позиционира на следващ елемент { ad = current -> content; current = current -> next; } return ad; } void out_list(); //извежда списъка int end()//връща 1 при край на списък { return (current == NULL); } };
Виртуални функции и виртуални класове • Пример list :: ~list() 3/6 { element *next_el; current = begin; while(current != NULL) { next_el = current -> next; delete current; current = next_el; } } void list :: new(void *x) { element *adel = new element; adel -> next = begin; adel -> content = x; begin = adel; } Дефиниция на деструктор Дефиниция на функция за добавяне на нов елемент
Виртуални функции и виртуални класове • Пример void list :: out_list() 4/6 { base *ptr; first(); while( !end() ) { ptr = (base*)next_el(); ptr -> out(); } } class point : public base { int x,y; public: point(int a = 0, int b = 0) { x=a; y=b; } void out() { cout << “точка: “ << x << “ “ << y << “\n”; } }; Дефиниция на фумкция за извеждане на списъка Дефиниция на клас точка
Виртуални функции и виртуални класове • Пример Дефиниция на клас комплексно число class complex : public base5/6 { double r, i; public: complex(double a = 0, double b = 0) { r=a; i=b; } void out() { cout << “комплексно число: “ << r << “+“ << i<< “i\n”; } };
Виртуални функции и виртуални класове • Пример void main() 6/6 { list l; point a(5,6), b(7,8); complex x(1.2,3.4), y(0.2,0.4); l.new(&a); l.new(&x); l.out_list(); l.new(&y); l.new(&b); l.out_list(); } Обект списък с елементи – обекти точки и комплексни числа Добавя в списъка точка и комплексно число Добавя в списъка комплексно число и точка комплексно число: 1.2+3.4i точка: 5 6 точка: 7 8 комплексно число: 0.2+0.4i комплексно число: 1.2+3.4i точка: 5 6