CATEGORII DOCUMENTE |
Revenim la exemplul din sectiunea 17.1. Am vazut ca daca se executa programul virtual1.cpp se apeleaza functiile membru functia_1 si functia_2 ale clasei de baza. Insa functia membru functia_1 fiind supraincarcata in clasa derivata, ar fi de dorit ca functia supraincarcata sa fie apelata in loc de cea a clasei de baza.
Acest lucru se poate realiza declarand functia_1 ca functie membru virtuala. Astfel pentru orice apelare a functiei membru functia_1, determinarea acelui exemplar al functiei membru din ierarhia de clase care se va executa, se va face la executie si nu la compilare. Aceasta proprietate se numeste legare dinamica.
In limbajul C++ o functie membru se declara virtuala in cadrul declararii clasei respective in modul urmator. Antetul functiei membru se va incepe cu cuvantul cheie virtual.
O functie membru se declara virtuala in clasa de baza. Supraincarcarile ei se vor considera virtuale in toate clasele derivate ale ierarhiei.
In cazul exemplului de mai sus declararea clasei de baza se modifica in felul urmator.
class baza ;
Rezultatul obtinut prin executie se modifica astfel:
S-a apelat functia membru functia_2 a clasei de baza
S-a apelat functia membru functia_1 a clasei derivate
Deci intr-adevar se apeleaza functia membru functia_1 a clasei derivate. Prezentam in continuare un alt exemplu in care apare necesitatea introducerii functiilor membru virtuale. In acest caz functia membru virtuala va fi de fapt supraincarcarea unui operator.
Sa se defineasca clasa fractie referitoare la numerele rationale, avand ca date membru numaratorul si numitorul fractiei. Clasa trebuie sa aiba un constructor, valoarea implicita pentru numarator fiind zero iar pentru numitor unu, precum si doi operatori: * pentru inmultirea a doua fractii si *= pentru inmultirea obiectului curent cu fractia data ca si parametru. Deasemenea clasa fractie trebuie sa aiba si o functie membru pentru afisarea unui numar rational. Folosind clasa fractie ca si clasa de baza se va defini clasa derivata fractie_scrie, pentru care se va supraincarca operatorul de inmultire * astfel incat concomitent cu efectuarea inmultirii sa se afiseze pe stdout operatia respectiva. Operatia *= nu se va supraincarca, dar operatia efectuata trebuie sa se afiseze pe dispozitivul standard de iesire si in acest caz. In limbajul C++ clasele se definesc in modul urmator. Fisierul fractie2.cpp
#include <conio.h>
#include <iostream.h>
class fractie ;
fractie::fractie(int numarator1 = 1,
int numitor1 = 0)
fractie fractie::operator *(fractie& r)
fractie& fractie::operator *=( fractie& q )
void fractie::afiseaza()
class fractie_scrie: public fractie
fractie operator *( fractie& r);
};
fractie fractie_scrie::operator * (fractie& q)
int main()
Prin executie se obtine:
15 / 8
15 / 8
(3 / 4) * (5 / 2) = 15 / 8
15 / 8
15 / 8
15 / 8
Observam ca rezultatul nu este cel dorit, deoarece operatia de inmultire s-a afisat numai o singura data, si anume pentru expresia r1 = p1 * q1. In cazul expresiei r2 = p1 *= q1 insa nu s-a afisat operatia de inmultire. Acest lucru se datoreaza faptului ca functia membru operator *= nu s-a supraincarcat in clasa derivata. Deci s-a apelat operatorul *= mostenit de la clasa fractie. In interiorul operatorului *= s‑a apelat functia membru operator *, dar deoarece aceasta functie membru s-a determinat inca in faza de compilare, rezulta ca s-a apelat operatorul de inmultire referitor la clasa fractie si nu cel referitor la clasa derivata fractie_scrie. Deci afisarea operatiei s-a efectuat numai o singura data.
Solutia este, ca si in exemplul anterior, declararea unei functii membru virtuale, si anume operatorul * se va declara virtuala. Deci declararea clasei de baza se modifica in felul urmator:
class fractie ;
Dupa efectuarea acestei modificari prin executarea programului obtinem:
15 / 8
15 / 8
(3 / 4) * (5 / 2) = 15 / 8
(3 / 4) * (5 / 2) = 15 / 8
15 / 8
15 / 8
15 / 8
Deci se observa ca afisarea operatiei s-a facut de doua ori, pentru ambele expresii. Functiile virtuale, ca si alte functii membru de fapt, nu trebuie neaparat supraincarcate in clasele derivate. Daca nu sunt supraincarcate atunci se mosteneste functia membru de la un nivel superior.
Determinarea functiilor membru virtuale corespunzatoare se face pe baza unor tabele construite si gestionate in mod automat. Obiectele claselor care au functii membru virtuale contin si un pointer catre tabela construita. De aceea gestionarea functiilor membru virtuale necesita mai multa memorie si un timp de executie mai indelungat.
Politica de confidentialitate | Termeni si conditii de utilizare |
Vizualizari: 801
Importanta:
Termeni si conditii de utilizare | Contact
© SCRIGROUP 2024 . All rights reserved