Sunteți pe pagina 1din 9

LABORATOR

Motenirea multipl:
Clase virtuale. Funcii
virtuale. Polimorfism.
Clase abstracte

Sumar

Clase virtuale. Evitarea ambiguitilor n clase de baz


Funcii virtuale
Polimorfism
Clase abstracte

Clase virtuale. Evitarea ambiguitilor n clase de baz


Atunci cnd programele create deriveaz o clas ce motenete mai multe clase
derivate anterior dintr-o singur clas de baz, este posibil ca acea clas s conin
membri care, dei unici n cadrul claselor prini, poart acelai nume n cadrul clasei
derivate. n astfel de situaii, ambiguitatea membrilor clasei va face compilatorul s
eueze. De exemplu, dac scriei un program care utilizeaz clasa baza i deriveaz din
acesta dou clase, derivata1 i derivata2, programul nu are ambiguiti. ns, dac mai
trziu programul deriveaz clasa derivata3 din ambele clase derivata1 i derivata2, fiecare
obiect al clasei derivata3 va conine de fapt cte dou obiecte ale clasei de baz.
Baza
public: i
Derivata1
public: i

Derivata2
public: i
Derivata3
deriv1::i
deriv2::i

Cei doi membri i din derivata3 creeaz ambiguitate.


Ex.1a:
#include<iostream.h>
class baza
{
public:
int i;
};
//derivata1 mosteneste baza
class derivata1:public baza
{
public:
int j;
};
//derivata2 mosteneste baza
class derivata2:public baza
{
public:
int k;
};
//derivata3 mesteneste atat derivata1 cat si derivata2
//aceasta inseamna ca in derivata3 exista doua copii ala bazei
class derivata3:public derivata1, public derivata2
{
public:
int suma;
};
void main()
{
derivata3 ob;
ob.i=10;
/* Aceasta provoaca ambiguitatea si anume oprirea compilatorului deoarece
nu se stie la care i se face referirea */
ob.j=20;
ob.k=30;
ob.suma=ob.i+ob.j+ob.k;
cout<<ob.i<<" ";
cout<<ob.j<<" "<<ob.k<<'\t';
cout<<ob.suma<<endl;
}

Ex.1b:
//acesta varianta de program foloseste explicit operatorul de declarare
#include<iostream.h>

class baza
{
public:
int i;
};
class derivata1:public baza
{
public:
int j;
};
class derivata2:public baza
{
public:
int k;
};
class derivata3:public derivata1,public derivata2
{
public:
int suma;
};
void main()
{
derivata3 ob;
ob.derivata1::i=10;
ob.j=20;
ob.k=30;
ob.suma=ob.derivata1::i+ob.j+ob.k;
cout<<ob.derivata1::i<<" ";
cout<<ob.j<<" "<<ob.k<<'\t';
cout<<ob.suma<<endl;
}
/*
Dupa cum se vede, deoarece s-a facut selectia (si anume derivata1 din baza) acest program ruleaza
normal.
Totusi, acesta solutie ridica o problema mai ampla: ce se intampla daca este ceruta efectiv doar o copie
pentru baza?
Exista vreo cale de a preveni includerea a doua copii in derivata3? Raspunsul este pozitiv, si anume
prin folosirea claselor vortuale.
Cand doua sau mai multe obiecte sunt derivate intr-o clasa de baza comuna, puteti preveni prezenta
intr-unul dintre acestea a mai multor copii ale clasei de baza, declarand-o virtual in momentul in care
ea este mostenita
*/

Ex.1c:
#include<iostream.h>
class baza
{

public:
int i;
};
class derivata1:virtual public baza
{
public:
int j;
};
class derivata2:virtual public baza
{
public:
int k;
};
class derivata3:public derivata1,public derivata2
{
public:
int suma;
};
void main()
{
derivata3 ob;
ob.i=10;
ob.j=20;
ob.k=30;
ob.suma=ob.i+ob.j+ob.k;
cout<<ob.i<<" ";
cout<<ob.j<<" "<<ob.k<<'\t';
cout<<ob.suma<<endl;
}

/* n acest exemplu fiecare din cele dou clase derivate intermediare motenesc clasa de
baz n mod virtual, ceea ce permite clasei derivate din final, derivata3, s moteneasc
ambele clase fr s mai apar probleme de ambiguitate. */

Funcii virtuale
S urmrim n ce const problema:
Fie o clas C1 care conine o metod M1 care o apeleaz pe o alta M2 din aceeai
clas. Pn aici nimic deosebit. O alt clas C2 o motenete pe prima. n cadrul acesteia
redefinim metoda M2, dar nu redefinim metoda M1. Declarm un obiect de tip C2 i
apelm metoda M1. Problema este urmtoarea: care va fi metoda apelat de M1, M2 din

C1 sau M2 din C2? n situaia n care procedm ca pn acum va fi apelat metoda M2


din C1.

Ex.2a:
#include<iostream.h>
class C1
{
public:
void M1()
{
M2();
}
void M2()
{
cout<<"unu "<<endl;
}

};
class C2:public C1
{
public:
void M2()
{
cout<<"doi "<<endl;
}
};
void main()
{
C1 x;
x.M1();
C2 y;
y.M1();
}

n acest caz se va afia pe ecran:


unu
unu

Evident, o astfel de situaie nu convine. De ce am redefinit metoda M2() dac este


apelat tot cea veche?
O astfel de metod de selecie a metodei prin obiectul care o apeleaz se numete
selecie static. Codul de apel al funciei este obinut la compilare i rmne nemodificat
pe parcursul executrii programului.

Aceast situaie poate fi remediat, adic s fie apelat metoda M2() redefinit.
Exist posibilitatea ca selecia s se fac n momentul apelului (nu la compilare). n astfel
de cazuri programatorul poate decide care metod s fie selectat. O selecie de acest tip
se numete selecie dinamic sau virtual.
Pentru a realiza selecia dinamic trebuie s procedm astfel:

cnd se declar, n cadrul clasei de baz, o metod ce va fi redefinit, este


precedat de cuvntul virtual

orice redefinire a metodei (tipul retur al funciei i lista parametrilor trebuie s fie
identice), se face utiliznd acelai cuvnt cheie virtual acest lucru este
recomandat, nu neaparat obligatoriu.

Ex.2b:
#include<iostream.h>
class C1
{
public:
void M1()
{
M2();
}
virtual void M2()
{
cout<<"unu "<<endl;
}

};
class C2:public C1
{
public:
virtual void M2()
{
cout<<"doi "<<endl;
}
};
void main()
{
C1 x;
x.M1();
C2 y;
y.M1();
}

n acest caz se va afia pe ecran:


unu
doi

Polimorfism
Polimorfismul este legat de motenire, o particularizare a acesteia. Polimorfismul,
prin definiie, este capacitatea unui singur obiect de a lua forme diferite. Limbajul C++
accept polimorfismul prin intermediul funciilor virtuale. Cu ajutorul funciilor virtuale,
acelai pointer poate indica diferite clase pentru a realiza diferite operaii.
Ex.3:
#include<iostream.h>
#include<math.h>
class baza
{
public:
int add(int a,int b)
{
return a+b;
}
virtual int scad(int a,int b)
{
return a-b;
}
virtual int inmult(int a,int b)
{
return a*b;
}
};
class deriv1:public baza
{
public:
int inmult(int a,int b)
{
return a*b*2;
}
};
class deriv2:public baza
{
public:
int scad(int a,int b)
{
return abs(a-b);
}
};
void main()
{

baza *a=new baza;


cout<<a->add(1,2)<<' '<<a->scad(2,10)<<' '<<a->inmult(10,10)<<endl;
a=new deriv1;
cout<<a->add(1,2)<<' '<<a->scad(2,10)<<' '<<a->inmult(10,10)<<endl;
a=new deriv2;
cout<<a->add(1,2)<<' '<<a->scad(2,10)<<' '<<a->inmult(10,10)<<endl;
}

Clase abstracte
n cele mai multe situaii, clasa de baz a unei ierarhii va trebui s fie foarte
general, elementele specifice rmnnd a fi ataate derivrilor acesteia. De fapt,
generalitatea clasei de baz poate atinge un astfel de grad nct aceast clas nici s nu
intervin n crearea obiectelor. Astfel de clase se numesc clase abstracte.
Clasele abstracte sunt nzestrate cu un tip special de funcii, virtuale pure. Pentru
a vedea cum se declar astfel de clase, vom considera exemplul urmtor. Aceast clas
conine funcii specifice, citire() i afisare(). Nedorind s definim aceste funcii n clasa
abstract, le vom face virtuale pure:
virtual void citire(int)=0;
virtual voi afisare(int)=0;

deci, vom iniializa numele lor, corpul ataat urmnd s fie implementat n clase derivate.
Abstractizarea trebuie neleas n adevratul sens al cuvntului, deoarece nu este
permis definirea de obiecte din astfel de clase. Trebuie create mai nti clase derivate din
acestea, n cadrul crora se vor redefini metodele virtuale pure. n cazul n care rmn
metode neimplementate, clasele derivate n aceast situaie rmn, n continuare,
abstracte. Cu toate c nu putem defini obiecte avnd ca tipuri clase abstracte, putem
defini pointeri ctre astfel de clase sau chiar referine.
Ex.4:
#include<iostream.h>
#include<stdio.h>
class abstract
{
public:
//functii virtuale pure
virtual void citire()=0;
virtual void afisare()=0;
};

class numar:public abstract


{
int n;
public:
virtual void citire()
{
cout<<"Dati un numar: ";
cin>>n;
}
virtual void afisare()
{
cout<<"Numarul este: "<<n<<endl;
}
};
class sir:public abstract
{
char* s;
public:
virtual void citire()
{
cout<<"Introduceti un sir: ";
s=new char[255];
gets(s);
}
virtual void afisare()
{
cout<<"Sirul este: "<<s<<endl;
}
};
void main()
{
//aplicarea polimorfismului
abstract* ob;
ob=new numar;
ob->citire();
ob->afisare();
ob=new sir;
ob->citire();
ob->afisare();
}

S-ar putea să vă placă și