duminică, 9 martie 2008

Operatori, constructor de copiere

Sa presupunem ca avem de creat o clasa vector. Cel mai economic ar fi sa o declaram in felul urmator:

class vector
{
int dimensiune;
int *elemente;
...
};

Ar fi bine ca toate metodele clasei sa fie cat mai intuitive pentru cel care o va utilzia in program. Adunarea sa se faca a+b si nu a.adunare(b), cin>>a si nu a.citeste etc.
La fel si pentru a[i] si nu a.getElement(i). Pentru asta suprascriem operatorul [].

int vector::operator [](int i)
{
return elemente[i]; //sau *(elemente+i), eventual si cu o verificare impotriva erorilor
}

Este corect definita functia de mai sus?

O alta problema care apare la clase care au membri pointeri ar fi atribuirea. Sa consideram urmatoarea bucata de cod:

vector a,b;
//initializam pe a
b=a;

Copierea se va face default de compilator - copie exact valorile din a in b. Dar elemente este o adresa, deci va copia adresa din a in b, si nu valorile de la adresa respectiva. Daca modificam valori in a.elemente si vor modifica si in b. Problema aceasta se rezolva scriind un constructor de copiere - constructor care primeste ca parametru tipul clasei careia ii apartine si/sau suprascriind operatorul =. Pentru constructor de copiere:

vector::vector(vector &a){...}

Constructorul de copiere va fi apelat in mai multe cazuri:
  • daca initializam o instanta a unei clase cu un obicet deja existent (vector a(b); echivalent cu a scrie vector a=b)
  • daca avem parametri de tipul cu constructor de copiere transmiri prin valoare (int ceva(vector a){..}) pentru ca se realizeaza o copie a obicetului pe stiva
Suprascrierea operatorului = este evidenta.

NOTA: 1. Este recomandat ca operatorii de tip = sa returneze referinte, pentru a putra face atribuiri inlantuite: a=b=c=d.
2. Daca avem o instanta a unei clase care ocupa multa memorie este recomandat sa o transmitem prin referinta si nu sa-i facem inca o copie in memorie (transmiterea prin valoare).
3. Daca pentru un operator transmitem parametrii prin referinta, e bine sa folosim specificatorul const, pentru a fi siguri ca nu se modifica in cadrul functiei:
vector operator + (const vector & a,const vector &b){...}


Tema laborator: Realizati o clasa vector care sa o folosim in urmatorul main:

int main()
{
int m;
cin>>m;
vector a(m);
cin>>a;
vector b;
cin b;
vector c=a+b;
cout<< a << "+" << b << "=" << c;
cout<< a << "*" << b << "=" << a*b; //produs scalar
for(int i=0;i< m;i++)
cout << a[i]<<" ";
count<< endl;
}

NOTA: Declararea variabilelor in C++
In C era obligatoriu sa-ti declari variabilele la inceputul blocului de instructiuni. In C++ poti sa le declari oriunde, insa pentru a face codul usor de citit este recomandat sa le declarati tot la inceputul blocului.
Un caz aparte este for-ul, daca il scriem for(int i....). Variabila i este recunoscuta doar in cadrul for-ului sau si dupa ce iesim din for?
Standard-ul initial C++ spunea ca o sa fie recunoscuta in tot blocul din care face for parte.
Realitatea spune ca depinde de compilator (in versiunile mai noi de Visual va fi recunoscuta doar in cadrul for-ului, insa Linux-ul s-ar putea sa respecte standardul).

Niciun comentariu: