Sunteți pe pagina 1din 7

L8 CONSTRUCTORI I DESTRUCTORI N PROCESUL DE DERIVARE Legtura ntre clasa derivat i clasele ei de baz comport unele aspecte eseniale cu privire

e la: a. relaiile ntre constructorii, respectiv destructorii clasei derivate i ai claselor de baz; b. conversiile obiectelor claselor derivate spre cele ale claselor de baz, respectiv a pointerilor spre aceste obiecte; c. redeclararea datelor membre i suprancrcarea funciilor membre ale claselor de baz n clasa derivat. Constructorii i destructorii sunt funcii membre care nu se pot moteni, dar se pot apela de ctre clasa derivat n anumite condiii de protecie. Un constructor al clasei derivate apeleaz, ntotdeauna, mai nti un constructor corespunztor al clasei de baz pentru a avea certitudinea c datele membre motenite au fost corect create i iniializate. Apelul constructorilor claselor de baz, de ctre constructorii clasei derivate, se poate realiza: a) implicit (atunci cnd este posibil); b) explicit (prin specificarea parametrilor necesari). Ordinea n care se execut apelul constructorilor din clasele de baz este impus de ordinea dat prin lista claselor de baz motenite, prezent n definiia clasei derivate. Reamintim faptul, c funcia constructor se apeleaz automat la crearea fiecrui obiect al clasei (static, automatic, dinamic (cu operatorul new)), inclusiv pentru obiectele temporare. Destructorul este o funcie care se apeleaz automat pentru a elimina un obiect dintr-o clas la finele duratei sale de existen, sau, n cazul variabilelor dinamice, el este solicitat prin program cu operatorul delete, inclusiv pentru obiecte temporare. Constructorul se apeleaz dup alocarea memoriei necesare pentru datele membre ale obiectului n faza final a crerii lui. Destructorul este apelat naintea eliberrii zonei de memorie alocate datelor membre ale obiectului, n faza iniial a eliminrii obiectului.

Ordinea de execuie a funciilor constructor, respectiv destructor n procesul de motenire reiese i din urmtorul exemplu: #include <iostream.h> #include <conio.h> class B1 { public: B1( ){cout<<"(1)Se apeleaza constructorul pentru clasa B1\n";} ~B1( ){cout<<"(2)Se apeleaza destructorul pentru clasa B1\n";} }; class B2 { public: B2( ){cout<<"(3)Se apeleaza constructorul pentru clasa B2\n";} ~B2( ){cout<<"(4)Se apeleaza destructorul pentru clasa B2\n";} }; class B3 { public:

88

B3( ){cout<<"(5)Se apeleaza constructorul pentru clasa B3\n";} ~B3( ){cout<<"(6)Se apeleaza destructorul pentru clasa B3\n";} }; class D1:public B1,public B2 { public: D1( ){cout<<"(7)Se apeleaza constructorul pentru clasa D1\n";} ~D1( ){cout<<"(8)Se apeleaza destructorul pentru clasa D1\n";} }; class D2:public D1,public B3 { public: D2( ){cout<<"(9)Se apeleaza constructorul pentru clasa D2\n";} ~D2( ){cout<<"(10)Se apeleaza destructorul pentru clasa D2\n";} }; void main( ) { D1 ob1; D2 ob2; } S se urmreasc i s se explice ordinea n care se tipresc mesajele: (1),(3),(7),(1),(3),(7), (5), (9),(10),(6),(8),(4),(2),(8),(4),(2). Ce se ntmpla dac se utiliza protected? La instanierea unui obiect, apelul constructorului const n transmiterea de valori parametrilor constructorului respectiv pentru iniializarea datelor membre. Constructorul clasei derivate trebuie s conin parametri corespunztori tuturor valorilor necesare la iniializarea obiectelor. #n cazul unui obiect al unei clase derivate, o parte din aceste valori se folosesc pentru iniializarea datelor membre ale obiectului, specifice clasei derivate, iar o parte pentru iniializarea datelor membre ale sale, care au fost motenite din clasele de baz. Transferul valorilor de iniializare a datelor membre ale unui obiect, ce corespund motenirii de la clasele de baz, se pune n eviden cu ajutorul antetului constructorului clasei derivate. Exemplu: class D:public B_1, public B_2, public B_3 { . D(...); // constructor n clasa derivat (prototip) }; Antetul constructorului D() are forma urmtoare: D::D():B_1(),B_2(),B_3() O expresie de forma B_k()(k=1,2,3) va conine ntre paranteze o list de expresii care definesc valori iniiale pentru datele membre corespunztoare clasei B_k. O astfel de expresie va lipsi din antetul constructorului D() dac: a) clasa B_k nu are constructor; b) datele membre ale clasei B_k se iniializeaz cu valori implicite (exist constructor cu parametri implicii); c) clasa B_k nu are date membre. Expresia B_k() constituie un apel explicit al unui constructor al clasei B_k.

Constructorii claselor de baz se pot apela din clasa derivat, dac protecia lor este de tip public sau protected.

89

Lista apelurilor constructorilor claselor de baz nu se afl n prototipurile constructorilor clasei derivate, ci numai n antetele lor.

Exist urmtoarele situaii distincte cu privire la existena constructorilor n clasele de baz, respectiv clasa derivat din acestea: a) Nu exist constructori att n clasa derivat ct i n clasele de baz motenite. n acest caz, la instanierea obiectelor clasei derivate se apeleaz constructorii implicii generai de compilator. Exemplu: S notm cu B clasa de baz, iar cu D clasa derivat. Un obiect d al clasei derivate D se instaniaz fr iniializri. O instaniere n acest caz este de forma: D d; // se apeleaz constructorul implicit generat de compilator b) Cel puin una din clasele de baz are constructori, iar clasa derivat nu are constructori. Atunci: 1) toi constructorii, care exist n clasele de baz, vor fi implicii, sau cu toi parametrii cu valori implicite (parametri implicii); 2) nu se pot face iniializri la instanierea obiectelor clasei derivate; 3) la o instaniere a clasei derivate, se apleleaz constructorul implicit al clasei derivate generat de compilator, i constructorii claselor de baz cu parametri implicii. Exemplu: class B{ protected: int u,z; //date membre n clasa de baz public: B(int p=5, int q=5){u=p; z=q;} // constructor cu parametrii implicii n clasa de baz }; class D:public B{ protected: int alfa; public: . }; O declaraie de forma D d; arat c obiectul d se creeaz apelnd constructorul cu parametrii implicii al clasei B. Datele membre u i z se vor iniializa cu valoarea 5, iar data membr alfa nu este iniializat. c) Nu exist constructori definii de programator n nici-o clas de baz motenit, dar exist astfel de constructori n clasa derivat. Atunci: 1) este necesar s existe acces al clasei derivate la toate datele membre ale claselor de baz care comport iniializri; 2) constructorul clasei derivate va iniializa toate datele membre specifice clasei derivate ct i pe cele provenite din clasele de baz; Exemplu: class B { protected:

90

int u,z; public: // nu exist constructor definit de programator }; class D:public B { protected: int alfa,i,j; public: D(int p=0, int q=0, int lu=200, int lz=250) { u=p; z=q; i=lu; j=lz; if(p>=0 && p<=lu && q>=0 && q<=lz) alfa =1; else alfa=0; } . }; Exemple de instanieri: D d; // d.u=0, d.z=0, d.i=200, d.j=250, d.alfa =1 D d(100,500); // continuai i comentai ! d) Att clasa derivat ct i cel puin o clas de baz motenit au constructori definii de programator. Atunci: 1) constructorul clasei derivate conine parametri pentru toate datele membre ce comport iniializri; 2) valorile parametrilor ce corespund datelor membre specifice clasei derivate sunt utilizate pentru iniializarea datelor respective n mod obinuit (prin constructorul clasei derivate), iar restul de valori sunt utilizate la apelul explicit al constructorilor claselor de baz. Exemplu: class zona {protected: int u; int v; public: zona(int ui, int vi); //constructor al clasei de baz }; class punct:public zona { //clasa punct este derivat din clasa zona . public: punct(int Ui, int Vi); // constructor al clasei derivate }; zona::zona(int ui, int vi) { //def. constructorului clasei de baz u=ui; v=vi;

91

} punct::punct(int Ui, int Vi):zona(Ui,Vi){} //apel explicit al constructorului clasei de baz Se observ c la apelul constructorului clasei de baz se utilizeaz aceeai sintax ca la listele de iniializare. Se poate privi "cantitatea" motenit ca un membru ascuns care se iniializeaz printrun apel al unui constructor. n apelul constructorului, vom folosi identificatorul clasei, pentru c un astfel de membru ascuns nu are identificator. Atunci, cnd cel puin o clas din lista claselor de baz motenite are un constructor care nu este implicit i nici cu toi parametrii implicii, clasa derivat trebuie s aib cel puin un constructor definit de programator. Se tie c dac nu exist un constructor de copiere ntr-o clas, compilatorul, cnd este necesar, genereaz n mod automat un constructor de copiere implicit. Apelul acestuia conduce la copierea bit cu bit a datelor membre ale unui obiect surs (obiect care se copiaz) n datele membre corespunztoare unui obiect destinaie (obiect care se creeaz). Necesitatea unui constructor de copiere definit de programator se impune atunci cnd: a) copierea bit cu bit devine insuficient; b) clasele conin date membre pointeri spre zone de memorie alocate dinamic n heap; c) folosind date membre motenite din clasa de baz, procesul de copiere bit cu bit conduce la anumite erori. Utilitatea constructorului de copiere const n: a) iniializarea unui obiect printr-un alt obiect; b) transfer de obiecte prin parametri; c) returnarea obiectelor la revenirea din funcii. Apelul unui constructor de copiere se face n situaii de genul urmtor: a) Clasa derivat i clasele de baz motenite nu au constructori de copiere definii de programator.

n acest caz, copierea se va face bit cu bit, apelndu-se constructorii de copiere implicii generai de compilator. b) Cel puin o clas de baz are un constructor de copiere definit de programator, dar un astfel de constructor nu exist n clasa derivat corespunztoare. n aceast situaie, dac este nevoie de un constructor de copiere, pentru a crea un obiect alclasei derivate D (vezi utilitatea sa), se va apela constructorul de copiere implicit al clasei D, generat de compilator. Aceasta nseamn copierea bit cu bit a datelor membre specifice clasei D i a datelor membre motenite de la clasele de baz care nu au un astfel de constructor. Celelalte date membre se iniializeaz prin apelul automat al constructorilor de copiere ce exit n clasele de baz. c) Clasa derivat are constructor de copiere definit de programator. Apelul constructorului de copiere al clasei derivate D se face cnd este nevoie. Folosirea constructorilor din clasele de baz corespunztoare se face n funcie de definiia constructorului de copiere al clasei derivate. Apelul constructorului de copiere al clasei derivate nu apeleaz automat constructorii de copiere ai claselor de baz. Un astfel de apel al constructorului de copiere al clasei derivate se va face conform anumitor reguli. 1) Dac clasa derivat D posed un constructor de copiere de antet: D(const D& d) // antetul constructorului de copiere al clasei derivate atunci clasa de baz B, fie c nu are nici un constructor definit de programator, fie c are un constructor implicit, sau cu toi parametrii implicii. O instaniere de forma: D d_1=d; // d este un obiect al clasei derivate anterior declarat apeleaz constructorul de copiere al clasei derivate D cu antetul precizat anterior. Un astfel de apel conduce la apelarea

92

automat a constructorului prezent n clasa de baz B (generat de compilator sau cel definit de programator). 2) Dac clasa de baz B are constructori definii de programator dar nici unul nu este implicit sau cu toi parametrii implicii, atunci constructorul de copiere al clasei derivate D trebuie s conin apelul explicit al unui constructor al clasei de baz B. Antetul constructorului de copiere al clasei derivate D va fi de forma: D(const D& d):B().

Destructorii opereaz n n sens invers fa de constructori. Deoarece destructorii nu au parametri, apelurile lor se realizeaz n mod implicit de ctre compilator. Ordinea de apel ar fi urmtoarea: destructorul clasei derivate (cnd un obiect "derivat" iese din domeniul su); destructori pentru membrii specifici clasei derivate; destructorul clasei de baz; destructori pentru membrii clasei de baz.

Aplicaie: S se defineasc clasa derivat "segment" avnd clasa de baz "punct_1". S se pun n eviden modul de utilizare al constructorilor n procesul de derivare. #include<iostream.h> #include<conio.h> #include<math.h> class punct_1{ protected: double x,y; public: punct_1(){;} punct_1(double x1, double y1) {x=x1;y=y1;} punct_1(punct_1*a){x=a->x; y=a->y;} void afis_punct() { cout<<"Abscisa punctului:"<<x; cout<<"Ordonata punctului:"<<y; } double dist(punct_1 p_2) { return (sqrt((x-p_2.x)*(x-p_2.x)+(y-p_2.y)* (y-p_2.y))); } double& ret_x(){return x;} double& ret_y(){return y;} }; class segment: public punct_1 { punct_1 varf,p_1; public: segment(double x_0,double y_0,double xv,double yv): punct_1(x_0,y_0) { punct_1 varf; varf.ret_x()=p_1.ret_x();

93

varf.ret_y()=p_1.ret_y(); } punct_1 ret_orig() { punct_1 p; p.ret_x()=x; p.ret_y()=y; return p; } }; void main(void) { punct_1 p_1(5,6), p_2(7,8); clrscr(); cout<<"Distanta:\n"<<p_1.dist(p_2); cout<<"\n"; segment s_1(5,6,7,8); cout<<"Originea:"<<s_1.ret_orig().ret_x(); cout<<"\n"; cout<<"Extremitatea:"<<s_1.ret_orig().ret_y(); getch(); } Tematica propus
1.

S se implementeze o clas punct. S se citeasc coordonatele carteziene a dou puncte din plan, s se determine un al treilea punct care s mpart segmentul determinat de primele dou puncte ntr-un raport dat k. Definii clasa derivat segment i efectuai operaii permise cu obiecte ale clasei derivate. Pornind de la clasa de baz punct, construii clasa derivat arc i reprezentai un digraf prin matricea sa de adiacen.

2.

3. S se dea exemple de ierarhii de clase care s nu fie unice.


4. 5.

S se implementeze urmtoarea ierarhie de clase: monoid, grup, inel, corp. Pe un stativ dreptunghiular se gsesc n rnduri cu cte m eprubete pe fiecare rnd care sunt pline cu diverse substane chimice. Un laborant efectueaz o serie de experiene, combinnd substanele existente n dou eprubete vecine (vertical sau orizontal). Dac reacia a avut loc, atunci vor rezulta alte dou substane . De la intrare se vor citi reaciile sub forma I J K L ceea ce semnific faptul c substana I reacioneaz cu substana J i rezult produii K i L. Substana K va fi pus n locul substanei I, iar L n locul lui J. Dup ncheierea tuturor experienelor,cunoscnd doar configuraia iniial i pe cea final, s se reconstituie etapele care s-au efectuat n trecerea de la configuraia iniial la cea final. Pot exista, iniial,mai multe eprubete cu aceeai substan chimic.

94

Evaluare