Documente Academic
Documente Profesional
Documente Cultură
Interfete
Cuprins:
• Functii inline
• Mostenire multipla – “death diamond” – clase de baza virtuale
• Ambiguitati la derivarea din mai multe clase de baza; tratarea
ambiguitatilor
• Identificatorii final si override (C++ 11)
• Functii si clase abstracte
• Interfete
1
/*1. */#include <iostream>
using namespace std;
class Baza
OBSERVATIE
{ protected: int atr1=0;
public: Baza(){} Am dreptul sa apelez doar
Baza(int i ){atr1=i;} constructorul din clasa de
}; baza directa, in cazul nostru
Derivata1
class Derivata1:public Baza
{ protected: int atr2=0;
public: Derivata1(){} DE CE?
Derivata1(int i, int j):Baza(i){atr2=j;}
}; Compilatorul il apeleaza pe cel
default din Derivata1 care il
class Derivata2:public Derivata1 apeleaza pe cel default din
{ protected: int atr3=0;
public: Derivata2(){} Baza =>s-ar apela de doua ori
constructorul din Baza
Derivata2(int i, int j,int k):Baza(i){atr2=j; atr3=k;}
};
int main() * exista o exceptie – slide 7
{
Derivata2 d(3,3,3);
// ERROR: type `class Baza' is not a direct base of `Derivata2'
return 0;
}
2. Functii virtuale declarate inline
Daca functia este inline - codul functiei este substituit in sursa compilata*, nu se face
efectiv apel de functie si astfel castig timp la executie.
OBS: Functiile implementate in headear sunt automat tratate ca inline*.
Implementati orice functie scurta ca inline (de exemplu : functiile pentru calculul ariei,
volumului, perimetrului, metodele pentru setarea si recuperarea atributelor)!
DA
C9: Mostenire multipla. Clase si functii abstracte. Interfete
Mostenire multipla. Clase de baza virtuale.
Baza
In cazul in care o clasa este derivata din doua clase de baza, constructorul sau o sa
apeleze constructorii claselor de baza.
Der12():Der1(),Der2(){}
Automat, se va aloca de doua ori spatiu pentru atributele mostenite din Baza.
Pentru a rezolva aceasta situatie – clasele de baza Der1 si Der2 trebuiesc derivate
in mod virtual din clasa de baza - > sunt clase de baza virtuale pentru Der12:
- sunt utilizate in cazul mostenirii multiple cand o serie de clase sunt derivate din
aceeasi clasa de baza si ele urmeaza sa fie clase parinte pentru o alta clasa
OBS: In cazul utilizarii claselor virtuale, pentru a crea un obiect de tip Der1_N - se vor
apela constructorii claselor imediat superioare, dar se va apela o singura data
constructorul clasei Baza, mai exact cel fara parametrii.
Este sarcina programatorului sa initializeze explicit atributele din clasa Baza, daca acest
lucru e de interes.
Avem comportament similar pentru destructorul ~Der1_N().
class Baza OBS: Faptul ca am
{protected: declarat functiile
int id=0; inline ar ajuta daca
public: implementarea lor nu
inline Baza(){}; ar fi facuta in header.
inline Baza(int ii):id(ii){}; (Teoretic trebuia sa
virtual inline void afisare(){ cout << id ; } impart clasele in
}; interfete - headere si
implementare).
class Der1: virtual public Baza
{protected :
int x=0;
public:
inline Der1(int ii,int xx):Baza(ii), x(xx){ };
inline void afisare(){ Baza::afisare(); cout << " "<< x << endl; }
};
void afisare(){Der1::afisare(); cout <<" " << y <<" "<< z<< endl;}//afisez doar o data id
};
//OBS: Destructorul pentru obiecte de tip Der12 va apela o singura data destructorul generat
//automat ~Baza().
int main()
{ Der12(1,2,3,4).afisare();
int n;
cout<<"dati dimensiunea:"<<endl;
cin>>n;
Baza ** colectie=new Baza*[n];
Obiectul de pe pozitia 0 este un Baza care pointeaza catre un obiect de tipul: Der1
care contine valorile: 0 0
Obiectul de pe pozitia 1 este un Baza care pointeaza catre un obiect de tipul: Der2
care contine valorile: 1 1
Obiectul de pe pozitia 2 este un Baza care pointeaza catre un obiect de tipul: Der12
care contine valorile: 2 2 2
Obiectul de pe pozitia 3 este un Baza care pointeaza catre un obiect de tipul: Baza
care contine valorile: 3
1. Considerati implementarea:
S-ar mosteni doua functii: Der1::afisare() si Der2::afisare(); afisare e declarata virtual in Baza
class Baza2{
protected: int atr2;
public: Baza2(int i){atr2=i;}
void afisare(){cout<<atr2;}
};
int main() {
Der d(1,1); d. afisare();
// ERROR: request for member `afisare' is ambiguous , candidates are:
//void Baza2::afisare() and void Baza1::afisare()
d.Baza1::afisare(); d.Baza2::afisare(); //trebuie sa precizez la care functie ma refer
return 0;}
C9: Mostenire multipla. Clase si functii abstracte. Interfete
Ambiguitati datorate mostenirii multiple
1. Daca in doua clase de baza exista functii cu acelasi nume si aceeasi semnatura -
nevirtuale, iar in clasa derivata nu se redefineste acea functie => sunt mostenite ambele
versiuni
class Baza1 {
public:
int i;
int j;
void f(int) {/*impl*/ }
};
class Baza2 {
public:
int j;
void f() {/*impl*/}
};
class Der : public Baza1, public Baza2 { class Baza1 {
public: public:
int i; //acopera ca vizibilitate atributul i din Baza1 int i;
}; // mosteneste j din Baza1 si j din Baza2 si Baza1::f() si Baza2::f(int) int j;
void f(int) {/*impl*/ }
int main() { };
Der d;
class Baza2 {
d.i = 5; public:
//este acoperit ca vizibilitate atributul din Baza1; int j;
//ne referim - fara ambiguitati la i din Der void f() {/*impl*/}
};
// d.j = 10;
//sunt mostenite 2 atribute cu acelasi nume
//ERROR: request for member `j' is ambiguous candidates are: int Baza2::j int Baza1::j;
// d.f();
// sunt mostenite doua functii cu acelasi nume , chiar daca avem semnatura diferita
// ERROR: request for member `f' is ambiguous candidates are: void Baza2::f()
// void Baza1::f(int)
d.Baza2::f(); //precizez despre care functie este vorba
return 0;
}
C9: Mostenire multipla. Clase si functii abstracte. Interfete
Cum procedez daca nu doresc ca o functie sa poata sa fie suprascrisa intr-o clasa
derivata?
class A {
public: virtual void f(){};
};
class B: public A {
public: void f() final {};
};
class C: public B {
public: void f() {}; //ERROR B::f is final
};
Clase declarate final (C++11)
- daca la un anumit punct intr-o ierarhie de clase, o clasa este declarata finala => nu se
va mai putea deriva in continuare din acea clasa
class O{};
class A final:public O{
};
class B: public A {
};
//ERROR class A is final
Observatii:
2. Nu se pot instantia obiecte de tipul unei clase abstracte, DAR pot sa declar pointeri de
acel tip
int main() {
// figura f; //ERROR; nu pot instantia obiecte de tipul unei clase abstracte; inca nu stiu care e
//implementarea pentru metodele abstracte;
cerc c(1); //pot instantia obiecte de tipul claselor derivate care au implementat metodele aria si
//perimetru
//Si atunci de ce este abstractizarea importanta?
//Pot sa declar un vector de pointeri de tip figura:
figura **v=new figura*[2];
//si sa il populez cu obiecte de tipul claselor derivate neabstracte (au implem. met. abstracte)
v[0]=&c; v[1]=new dreptunhghi(3,4);
//si sa utilizez proprietatile functiilor virtuale (declarate in clasa de baza)
for (int i=0;i<2;i++) v[i]->afisare(); // Altfel nu aveam cum sa creez vectorul neomogen de
//obiecte si sa folosesc polimorfismul. Clasele dreptunghi si cerc nu ar fi avut o baza comuna =>
//s-a pus la dispozitie o clasa de baza abstracta
return 0;
}
C9: Mostenire multipla. Clase si functii abstracte. Interfete
Interfata
Interfetele si clasele abstracte sunt foarte importante pentru dezvoltarea de ierarhii de clase
- ele reprezinta o schita a ceea ce trebuie implementat/suprascris in clasele derivate.
Interfetele sunt utile pentru a preciza, de la bun inceput intr-o ierarhie de clase, care sunt
metodele care trebuiesc supraincarcate in clasele derivate din acea ierarhie => precizeaza
care sunt comportamente comune (chiar daca acestea au implementari specifice) pentru
tipurile de date din ierarhie.
Clasele “concrete” - derivate din una sau mai multe interfete - sunt obligate ca, eventual, sa
furnizeze implementari pentru toate metodele abstracte/comportamentele
declarate/precizate in interfete.
#include <iostream>
using namespace std;
int main()
{cerc c(0,0,1);
c.afisare();
//punct p(1,1); //punct e o clasa abstracta
DAR Student si Angajat nu au in comun o clasa de baza ca sa pot realiza vectorul si folosi
functii virtuale.
Pot sa creez o interfata comuna pentru cele 3 clase:
class Object{
public:
virtual void afisare()=0;
virtual ~Object(){}
};
int main() {
Derived d;
return 0;
}
• Intr-o aplicatie am de creat tipuri de date pentru figuri geometrice atat 2D
cat si 3D. Vreau sa le afisez atributele, aria, perimetrul si volumul (daca se
poate calcula).
return 0;
}
//Concluzie: structurez ierarhia in fctie de cerinta.
Tipuri de derivare:
- derivarea este implicit privata: class Derivata: Baza
- dar vrem sa fie publica (aproape mereu): class Derivata: public Baza
- rar este protected: class Derivata: protected Baza
Drept de acces in Modificator acces Drept de acces in
clasa de baza clasa derivata
public public public
private inaccesibil
protected protected
public private private
private inaccesibil
protected protected
public protected protected
private inaccesibil
protected protected
Mostenirea private este utila daca vreau sa ascund functionalitati ale clasei de baza.
Daca totusi vreau sa fac publice o serie de atribute atunci o sa le declar in sectiunea
public a clasei derivate.
Daca se precizeaza numele unei functii, toate versiunile suprascrise ale ei sunt
expuse.
#include <iostream>
using namespace std;
class Aparat {
public:
void functia1() { cout<<"functia1"; }
int functia1(bool i) {if (i) return 1; return 0;}
void functia2() { cout<<"functia2"; }
void functia3() { cout<<"functia3"; }
};
int main() {
Aparat_Defect a;
a.functia1();
cout<<a.functia1(1);
a.functia2();
//a.functia3(); // ERROR: private member function named functia3
return 0;
}