Etichete: POO

Introducere

Derivarea claselor (moștenirea) este unul dintre principiile fundamentale ale programării orientate pe obiecte. Ne permite să definim o clasă pornind de la altă clasă, creată anterior, și facilitează crearea și întreținerea aplicațiilor. Tototdată permite reutilizarea codului și micșorează timpul de implementare a programelor.

La crearea unei clase, în loc să scriem date și funcții membre complet noi, putem să precizăm că noua clasă va moșteni membri unei clase existente. Se obțin astfel ierarhii de clase.

Moștenirea are sens numai când obiectele din clasa moștenită fac parte din obiectele clasei de bază – relația dintre ele este de tipul Is A (este un/o). De exemplu:

  • paralelogramul este un patrulater. Clasa Paralelogram poate fi derivată din clasa Patrulater.
  • câinele este un animal. Clasa Caine poate fi derivată din clasa Animal.

Terminologie

Fie B o clasă care există deja, iar D clasa care moștenește membrii clasei B. Spunem că:

  • B este clasa de bază;
  • D este clasa derivată;
  • clasa D s-a obținut prin derivarea clasei B;
  • clasa B a fost derivată și s-a obținut clasa D;
  • clasa D moștenește clasa B;
  • relația de moștenire se reprezintă prin următoarea diagramă:

În C++, o clasă poate fi derivată pornind de la mai multe clase de bază. Totodată, specificatorii de acces cunoscuți (public, private, protected) sunt folosiți și pentru a preciza modul în care se face derivarea. Efectul lor este legat de vizibilitatea membrilor clasei de bază în clasa derivată.

Declararea unei clase

Cea mai simplă formă de derivarea a unei clase este prezentată mai jos:

class D: public B{
	// membri noi ai clasei derivate
}

Observații:

  • clasa B este clasa de bază, care trebuie să fie deja definită;
  • clasa D este clasa derivată;
  • specificatorul de acces folosit în exemplu, public, face ca:
    • membrii public din clasa de bază B rămân public și în clasa derivată D – pot fi accesați din afara clasei D;
    • membrii protected din clasa de bază B rămân protected și în clasa derivată D – pot fi accesați din clasa derivata D și vor putea fi acesați din alte clase vor moșteni clasa D;
    • membrii private din clasa de bază B nu pot fi accesați din clasa derivată D;
  • la definiția clasei derivate, în loc de public putem folosi private sau protected. Semnificația lor va fi discutată ceva mai târziu!

Exemplu

#include<iostream>

using namespace std;

class Animal{
	private:

	protected: 
		int varsta;
	public:
		Animal(){
			varsta = 0;
			cout << "S-a nascut un animal." << endl;
		}
		~Animal(){
			cout << "Animalul a murit." << endl;
		}
		void creste()
		{
			++ varsta;
			cout << "Animalul are " << varsta << (varsta == 1 ? " an":" ani") << endl;
		}
};

class Caine: public Animal{
	public:
		Caine(){
			cout << "S-a nascut un caine." << endl;
		}
		~Caine(){
			cout << "Cainele a murit." << endl;
		}
		void latra()
		{
			for(int i = 1 ; i <= varsta ; i ++)
				cout << "Ham " ;
			cout << endl;
		}
		void creste()
		{
			++ varsta;
			cout << "Cainele are " << varsta << (varsta == 1 ? " an":" ani") << endl;
		}
};

int main(){
	Caine X;
	X.creste(); 
	X.Animal::creste();
	X.latra(); 
	X.creste();
	X.latra();
}
S-a nascut un animal.
S-a nascut un caine.
Cainele are 1 an
Animalul are 2 ani
Ham Ham 
Cainele are 3 ani
Ham Ham Ham 
Cainele a murit.
Animalul a murit.

Observații

  • Animal este clasa de bază, iar Caine este clasa derivată;
  • din clasa derivată (metoda latra()) am accesat proprietatea varsta din clasa de bază:
    • acest lucru a fost posibil deoarece proprietatea varsta a fost declarată protected
    • dacă ar fi fost declarată private, nu putea fi accesată din clasa derivată
  • din exterior – funcția main(), pentru obiectul X de tip Caine am accesat:
    • metoda latra(), disponibilă doar în clasa derivată;
    • metoda creste(), moștenită din clasa de bază;
    • ambele metode sunt publice în clasa derivată;
  • ambele clase sunt înzestrate cu constructori și destructori:
    • în cazul constructorului, mai întâi se apeleaza cel al clasei de bază, apoi cel al clasei derivate;
    • în cazul destructorului, ordinea este inversă;
  • dacă în clasa de bază și în clasa derivată avem doi membri cu același nume (overriding), prioritate are cel din clasa derivată. Pentru a-l accesa pe cel din clasa de bază vom folosi operatorul de rezoluție:
    X.creste(); // Cainele are 1 an
    X.Animal::creste(); // Animalul are 2 ani
  • în exemplul de mai jos se evidențiază modul în care se poate face atribuirea între o variabilă de tipul clasei de bază și una de tipul clasei derivate:
    int main(){
    	Caine X;
    	X.creste();  // Cainele are 1 an
    	X.latra();	 // Ham
    	Animal A;
    	A = X;
    	A.creste();	// Animalul are 2 ani
    	// X = A; eroare de sintaxă
    }

    A este de tipul Animal (clasa de bază), iar X este de tipul Caine (clasa derivată). Atunci:
    • atribuirea A = X; este corectă. În A se vor copia doar membri din X care fac parte din clasa de bază.
    • atribuirea X = A; nu este corectă. Clasa derivată conține și membri care nu aparțin clasei de bază, ce nu pot fi inițializați prin această atribuire!

Accesul la membrii claselor derivate

Accesul la membrii (date sau funcții) clasei de bază în clasa derivată se face în funcție de regulile de acces la membrii clasei de bază și în funcție de modalitatea în care s-a făcut derivarea.

Sunt trei moduri de declarare a membrilor unei clase:

  • publici – public – pot fi accesați din afara clasei, dar și din interiorul ei
  • protejati – protected – nu pot fi accesați din exteriorul clasei (de bază sau derivate). Pot fi accesați din interiorul clasei de bază și din interiorul claselor derivate
  • privați – private – pot fi accesați numai din interiorul clasei.

Modalitățile de derivarea ale unei clase sunt:

  • derivare publică:
    class D: public B{ … }
    • membrii publici ai clasei B rămân publici și în clasa D;
    • membrii protejați al clasei B rămân protejați în clasa D;
    • membrii privați ai clasei B sunt inaccesibili în clasa D;
  • derivare protejată:
    class D: protected B{ … }
    • membrii publici ai clasei B devin protejați și în clasa D;
    • membrii protejați al clasei B rămân protejați în clasa D;
    • membrii privați ai clasei B sunt inaccesibili în clasa D;
  • derivare privată:
    class D: private B{ … }
    • membrii publici ai clasei B devin privați și în clasa D;
    • membrii protejați al clasei B devin privați în clasa D;
    • membrii privați ai clasei B sunt inaccesibili în clasa D;