23829 afișări Candale Silviu (silviu) 07.06.2021 www.pbinfo.ro
Etichete: nicio etichetă

Generalități

Cuvântul polimorfism se referă la proprietatea unor substanțe, ființe, obiecte de a avea mai multe forme.

În contextul programării orientate pe obiecte, polimorfismul se referă la posibilitatea claselor de a avea mai multe metode cu același nume, dar cu efecte și rezultate diferite.

În C++ polimorfismul poate fi implementat prin:

  • supraîncărcarea funcțiilor;
  • supraîncărcarea operatorilor;
  • suprascrierea funcțiilor;
  • funcții virtuale.

Supraîncărcarea funcțiilor și operatorilor sunt tratate în acest articol: www.pbinfo.ro/articole/25851/supraincarcarea-functiilor-si-a-operatorilor.

Suprascrierea funcțiilor

Suprascrierea funcțiilor (overriding) se referă la situația ca într-o ierarhie de clase să avem metode cu același nume, dar cu efecte diferite. Considerăm clasele Animal și Caine.

#include<iostream>

using namespace std;

class Animal{
	public:
		void vorbeste()
		{
			cout << "Animalul vorbeste." << endl;
		}
};

class Caine: public Animal{
	public:
		void vorbeste()
		{
			cout << "Cainele latra." << endl;
		}
};

int main(){
	Caine C;
	Animal A;
	C.vorbeste();
	A.vorbeste();
	C.Animal::vorbeste();
	// A.Caine::vorbeste(); // imposibil
}

În exemplul anterior:

  • clasa Caine este derivată din clasa Animal;
  • obiectul C este de tip Caine, obiectul A este de tip Animal; ambele sunt obiecte statice;
  • metoda vorbeste() este disponibilă în ambele clase, fiind suprascrisă în clasa derivată
  • putem accesa corespunzător pentru fiecare obiect propria metoda vorbeste()
  • pentru obiectul derivat putem accesa metoda clasei de bază folosind operatorul de rezoluție: C.Animal::vorbeste(); – invers nu este posibil!

Constatăm că pentru obiectele referite static accesarea metodelor suprascrise este rezolvată elegant, putând accesa orice metodă disponibilă în obiectul curent (proprie obiectului curent sau proprie aflate mai “sus” în ierarhie).

Suprascrierea în cazul pointerilor

Să vedem cum putem accesa membri claselor de bază/derivată în cazul pointerilor. Folosind clasele definite mai sus, considerăm următorul exemplu:

Caine C;
Animal A;
Animal * p;
p = & A;
p->vorbeste(); // Animalul vorbeste.
p = & C;
p->vorbeste(); // Animalul vorbeste. (?!?)

Caine * q;
q = & C;
q->vorbeste();
// q = & A; // imposibil

Constatăm că:

  • pointerul la clasa derivată (q) poate memora doar adresa unui obiect al acesteia;
  • pointerul la clasa de bază (p) poate memora atât adresa unui obiect al clasei de bază, cât și adresa unui obiect al clasei derivate;
  • chiar dacă pointerul memoreaza adresa unui obiect al clasei derivată, prin acel pointer se accesează metode ale clasei de bază!

Funcții virtuale

C++ oferă un mecanism prin care se alege metoda accesată printr-un pointer dinamic, la execuția programului, în funcție de clasa din care face obiectul referit de pointer (de bază sau derivată). Acest mecanism este reprezentat de funcțiile virtuale.

Declararea unei funcții (metode) virtuale este precedată de cuvântul C++ rezervat virtual în clasa de bază:

virtual tipRezultat metoda(parametri)

Exemplu:

#include<iostream>

using namespace std;

class Animal{
	public:
		virtual void vorbeste()
		{
			cout << "Animalul vorbeste." << endl;
		}
};

class Caine: public Animal{
	public:
		void vorbeste()
		{
			cout << "Cainele latra." << endl;
		}
};

int main(){
	Caine C;
	Animal A;
	Animal * p;
	p = & A;
	p->vorbeste(); // Animalul vorbeste.
	p = & C;
	p->vorbeste(); // Cainele latra. (!)
}

Constatăm că:

  • p este declarat pointer la clasa de bază;
  • p poate memora fie adresa unui obiect din clasa de bază, fie adresa unui obiect din clasa derivată;
  • se apelează metoda corespunzătoare clasei din care face parte obiectul referit de pointer!

23829 afișări Candale Silviu (silviu) 07.06.2021 www.pbinfo.ro