Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
POO - Curs Doc-1.doc
Скачиваний:
0
Добавлен:
01.07.2025
Размер:
868.86 Кб
Скачать

§18. Realizarea conceptului de polimorfism

Un concept important în programarea orientată pe obiecte este noţiunea de polimorfism. Cuvântul polimorfism provine de la îmbinarea a două rădăcini polys ce înseamnă „numeros” şi morphe, ce înseamnă „formă”. În contextul programării polimorfism înseamnă o „singură interfaţă – mai multe forme de realizare”. O formă de polimorfism ar fi supraîncărcarea funcţiilor şi a operatorilor. În acest caz, interfaţa este numele funcţiei sau al operatorului, iar formele realizate sunt algoritmii diferiţi descrişi de fiecare funcţie în parte.

O formă mai complexă de polimorfism este obţinută utilizând conceptul de moştenire şi funcţii virtuale. În acest mecanism, sunt implicate cel puţin două tipuri de date:

  • tipul ce corespunde clasei de bază;

  • tipurile ce corespund claselor derivate.

În tipul de bază sunt definite o serie de funcţii membre virtuale. O funcţie virtuală are proprietatea de a putea fi schimbată în cadrul tipurilor derivate din clasa de bază, schimbându-i sensul după necesitate în clasa derivată. O funcţie virtuală este introdusă prin intermediul cuvântului-cheie virtual:

virtual tipr nume_fv(lista_pf);

Pentru ca să fie realizat conceptul de polimorfism, în clasa derivată prototipul funcţiei trebuie să fie identic cu prototipul descris în clasa de bază. La cea mai mică deosebire dintre prototipuri polimorfismul nu va fi realizat. Va fi descrisă schema ce generează polimorfism, pornind de la următoarea schemă de moştenire:

Clasa de bază conţine o serie de funcţii virtuale:

class cl_baza

{

. . .

virtual tipr1 nume_fv1(lista_pf1);

. . .

virtual tiprn nume_fvn(lista_pfn);

. . .

};

class cl_der1 : public cl_baza

{

. . .

[virtual tipr1 nume_fv1(lista_pf1);]

. . .

[virtual tiprn nume_fvn(lista_pfn);]

. . .

};

. . .

class cl_derk : public cl_baza

{

. . .

[virtual tipr1 nume_fv1(lista_pf1);]

. . .

[virtual tiprn nume_fvn(lista_pfn);]

. . .

};

Funcţiile virtuale din clasa de bază cl_baza pot fi implementate în clasele derivate, schimbându-le dacă este necesar sensul. Totodată, există posibilitatea de a păstra implementarea din clasa de bază şi în unele clase derivate. În acest caz, pur şi simplu nu sunt implementate funcţiile virtuale în clasele date.

tipr1 cl_baza :: nume_fv1 (lista_pf1)

{

.

. //realizare01

.

}

. . .

tiprn cl_baza :: nume_fvn (lista_pfn)

{

.

. //realizare0n

.

}

//--------------

tipr1 cl_der1 :: nume_fv1 (lista_pf1)

{

.

. //realizare11

.

}

. . .

tiprn cl_der1 :: nume_fvn (lista_pfn)

{

.

. //realizare1n

.

}

//--------------

. . .

//--------------

tipr1 cl_derk :: nume_fv1 (lista_pf1)

{

.

. //realizarek1

.

}

. . .

tiprn cl_derk :: nume_fvn (lista_pfn)

{

.

. //realizarekn

.

}

//--------------

După implementarea funcţiilor-membre pot fi generate obiectele necesare. Pentru a beneficia de polimorfism, trebuie de creat un pointer de tip clasa de bază. Încărcând în acest pointer adresa unui obiect, va fi posibil ca prin el să apelăm funcţii membre. În acest pointer pot fi încărcate adrese de obiecte de tip clasă de bază sau obiecte de tipul uneia dintre clasele derivate. Apelând prin intermediul acestui pointer funcţiile virtuale, va fi obţinut efectul de polimorfism. Interfaţa în cazul acesta va fi numele pointerului în combinaţie cu numele funcţiei virtuale, iar formele vor fi realizările funcţiei virtuale, fie realizarea din clasa de bază, fie realizările din clasele derivate. Dacă pointerul conţine adresa unui obiect de tipul clasei de bază, atunci la apelarea unei funcţii virtuale va fi apelată anume funcţia realizată în clasa de bază. Dacă însă pointerul conţine adresa unui obiect de tipul unei clase derivate, atunci la apelarea unei funcţii virtuale va fi apelată funcţia realizată anume în clasa derivată. Deci pointerul este sensibil la tipul obiectului a cărui adresă o conţine, determinând şi apelând funcţia care corespunde obiectului dat. În continuare, sunt reprezentate schematic ideile expuse mai sus:

cl_baza *p_baza, ob_baza(. . .);

cl_der1 ob_der1(. . .);

cl_der2 ob_der2(. . .);

. . .

cl_derk ob_derk(. . .);

p_baza=&ob_baza;

p_baza->nume_fv1(lista_pr); //va fi apelata realizare01

p_baza=&ob_der1;

p_baza->nume_fv1(lista_pr); //va fi apelata realizare11

p_baza=&ob_der2;

p_baza->nume_fv1(lista_pr); //va fi apelata realizare21

. . .

p_baza=&ob_derk;

p_baza->nume_fv1(lista_pr); //va fi apelata realizarek1

Fixând funcţiile virtuale ale unei clase, trebuie să ţinem cont de următoarele reguli:

  • constructorii unei clase nu pot fi nicidecum funcţii virtuale;

  • destructorul unei clase poate fi virtual.

Este cunoscut faptul că funcţiile-membri ale unei clase sau, altfel spus, metodele clasei sunt apelate prin intermediul unui obiect de tipul clasei date sau prin intermediul unui pointer. Desigur că pentru apelare este necesară o coordonare între adresele obiectului sau a pointerului şi a metodei, adică crearea unei legături corecte. Legarea unei metode de un obiect de anumit tip se face în procesul compilării şi o astfel de legătură se numeşte legătură statică (static binding), fiindcă este cunoscut şi obiectul, şi metoda apelată. Legarea metodei de pointer în lipsa polimorfismului este efectuată tot în timpul compilării după tipul pointerului şi de aceea este, de asemenea, o legătură statică. Legarea metodei de pointer în procesul polimorfismului poate fi efectuată doar în timpul rulării programului, fiindcă informaţia despre tipul pointerului este insuficientă, iar până la rulare nu este cunoscut obiectul a cărui adresă va fi încărcată în pointer şi deci nu poate fi determinată corect nici metoda apelată. De aceea o astfel de legătură se numeşte legătură dinamică (dynamic binding).

Pentru a putea determina corect metoda polimorfică apelată, clasele care conţin metode virtuale au un element suplimentar asociat cu ele, şi anume un tabel al funcţiilor virtuale. Cu ajutorul acestui tabel este calculată corect adresa metodei apelate. Ca rezultat, obiectele create în baza unei clase fără funcţii virtuale ar fi mai mici decât obiectele create în baza unei clase similare, dar care conţine funcţii virtuale. Totodată, apelarea metodelor nevirtuale este mai rapidă decât apelarea metodelor virtuale.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]