Home - Rasfoiesc.com
Educatie Sanatate Inginerie Business Familie Hobby Legal
Doar rabdarea si perseverenta in invatare aduce rezultate bune.stiinta, numere naturale, teoreme, multimi, calcule, ecuatii, sisteme




Biologie Chimie Didactica Fizica Geografie Informatica
Istorie Literatura Matematica Psihologie

C


Index » educatie » » informatica » C
» Supraincarcarea operatorului de asignare


Supraincarcarea operatorului de asignare


Supraincarcarea operatorului de asignare

Exista mai multi operatori de asignare: =, *=, /=, %=, +=, -=, >>=, <<=, &=, ^=, |=, dintre care primul este operatorul simplu de asignare, ceilalti fiind combinatie cu alti operatori.

In asignarea simpla (=), valoarea expresiei care reprezinta operandul dreapta inlocuieste valoarea operandului stanga. Daca ambii operanzi sunt de tip aritmetic, operandul dreapta este convertit la tipul operandului stanga, dupa care are loc atribuirea valorii. Nu exista o conversie implicita la tipul enumerare, astfel incat, daca operandul stanga este o enumerare, cel din dreapta trebuie sa fie de acelasi tip.



Pentru tipurile definite de utilizator, functia operator de asignare (operator=()) trebuie sa fie o functie membra nestatica a clasei si nu poate fi mostenita. In multe privinte, functia operator seamana mai mult cu constructorii decat cu ceilalti operatori, dar este, totusi diferita de operatia de initializare pe care o efectueaza constructorii.    In lipsa unei functii operator=() definita de utilizator pentru o clasa X, este utilizata definitia implicita de asignare prin copierea membru cu membru astfel:

class X ;

X& X::operator=(const X& op2)

void f()

Ceilalti operatori de asignare ( , etc) nu au o semnificatie predefinita pentru clase, deci, pentru a putea fi folositi, trebuie sa fie definiti de utilizator.

In cazul claselor de obiecte care nu contin date alocate dinamic la initializare sau prin intermediul altor functii membre, asignarea prin copiere membru cu membru functioneaza corect si, in general, nu mai este necesar sa fie supraincarcat operatorul de asignare. Acest lucru s-a    remarcat si in executiile din Exemplele 1 sau 2.

Nu acelasi lucru este valabil pentru clasele care contin date alocate dinamic. Situatia este foarte asemanatoare celei prezentate in cazul constructorilor de copiere: daca o clasa contine date alocate dinamic, copierea membru cu membru care se executa implicit la asignare sau la constructia prin copiere, are ca efect copierea pointerilor la datele alocate dinamic, deci doi pointeri din doua obiecte vor indica catre aceeasi zona din memoria heap. Acesta situatie conduce la numeroase si subtile erori care se vor analiza mai sugestiv pe un exemplu de clasa care modeleaza un sir de caractere, clasa String

n           Exemplul 3

Fie clasa String care implementeaza un sir de caractere, folosind constante de tip sir

#include <string.h>

class String;

Clasa String contine un pointer la un sir de caractere, str, si o variabila de tip intreg size care memoreaza dimensiunea vectorului de caractere corespunzator, deci inclusiv spatiul necesar pentru caracterul 0 de la sfarsitul sirului. Constructorii si destructorul sunt simplu de implementat. Constructorul implicit creaza un obiect String cu un sir de caractere de lungime zero. Constructorul de initializare construiestc un obiect String avand ca argument un sir de caractere terminat cu nul. Dimensiunea tabloului de caractere pe care il aloca in memoria heap este strlen(p)+1, pentru a se insera caracterul 0 de la sfarsit. Constructorul de copiere este absolut necesar, pentru a aloca un sir nou in memoria heap si a evita astfel erorile care ar putea apare prin copierea pointerului, care ar indica catre acelasi sir in memoria heap. Se asemenea este absolut necesar sa fie definit destructorul, pentru eliminarea sirului de caractere alocat dinamic in heap.

String::String()

String::String(const char *p)

String::String(const String& r)

String::~String()

Functiile operator <<() si operator >>() care definesc operatiile de inserare si de extragere a unui obiect String dintr-un stream definite in acest punct vor fi prezentate detaliat in sectiunea 6.

ostream& operator <<(ostream &stream, const String &r)

istream& operator >>(istream &stream, String &r)

Operatorul de asignare este asemanator constructorului de copiere: nu efectueaza copierea membru cu membru a datelor ci aloca un spatiu nou in memoria heap pentru sirul de caractere str si efectueaza copierea continutului acestuia. In plus, la asignare, mai este necesara stergerea sirului pe care obiectul String pentru care se executa operatia de asignare ar fi putut sa-l aiba alocat in memoria heap. S-au definit doua functii operator=(), cu argumente de tip diferit (o referinta la clasa String si un pointer si un sir de caractere), selectia intre aceste functii efectuandu-se pe baza tipului argumentului de apel.

String& String::operator=(const String &op2)

String& String::operator=(const char* p)

Se pot studia situatiile in care se folosesc diferiti constructori sau operatori de asignare pentru obiecte din clasa String. Fie functia f3()

void f3 ()

La executia acestei functii, la consola se afiseaza mesajele:

Constructor init

Constructor init

abcd

Constructor copiere

Operator=(String&)

abcd

Operator=(char*)

mnp

Destructor

Destructor

Destructor

care indica modul in care sunt apelati constructorii, destructorul si functiile operator de asignare. S-au creat trei obiecte din clasa String, obiectele sir1 si sir2 prin constructori de initializare, iar obiectul sir3 prin constructorul de copiere. Asignarile catre obiectul sir3 utilizeaza acea functie operator=() care se potriveste tipului argumentului. La iesirea din blocul funtiei, cele trei obiecte sunt distruse si se apeleaza de fiecare data destructorul, care eliminina din memoria heap sirul de caractere str corespunzator fiecarui obiect.

Aceasta este executia corecta a programului, asigurata de definirea corecta a constructorilor, destructorului si a functiilor de copiere. Lipsa unora dintre aceste functii poate avea urmari dintre cele mai grave.

De exemplu, lipsa functiei operator:

String& operator=(const String &op2);

are ca efect folosirea operatorului implicit de asignare, care copiaza in variabila str a obiectului sir3 valoarea pointerului str din obiectul sir2, deci ambii pointeri indica acelasi sir de caractere "abcd": sir2.str = sir3.str. Eroarea se evidentiaza la iesirea din functia f1(): eliminarea obiectului sir3 produce stergerea sirului de caractere "abcd", acelasi pe care incearca sa-l steearga apoi si destructorul apelat pentru obiectul sir2. Aceasta operatie de stergere a unor date care au fost deja sterse din memorie provoaca executia anormala a programului si la consola va apare un mesaj de eroare. Mai sunt posibile si alte erori de executie provenite din aceasta asignare eronata, care pot fi studiate in exercitiile propuse.

Tot ca exercitii se vor studia si alte situatii care evidentiaza comportamentul functiilor operator de asignare.






Politica de confidentialitate




Copyright © 2024 - Toate drepturile rezervate