Home - qdidactic.com
Didactica si proiecte didacticeBani si dezvoltarea cariereiStiinta  si proiecte tehniceIstorie si biografiiSanatate si medicinaDezvoltare personala
referate stiintaSa fii al doilea inseamna sa fii primul care pierde - Ayrton Senna





Aeronautica Comunicatii Drept Informatica Nutritie Sociologie
Tehnica mecanica


Informatica


Qdidactic » stiinta & tehnica » informatica
Supraincarcarea operatorilor - supraincarcarea operatorului de atribuire



Supraincarcarea operatorilor - supraincarcarea operatorului de atribuire



1. Supraincarcare.

2. Functii prieten.

3. Modalitati de supraincarcare a operatorilor.

4. Operatori redefiniti ca functii prieten.

5. Operatori redefiniti ca functii membri.

6. Supraincarcarea operatorului de atribuire.

7. Supraincarcarea operatorului de indexare.

8. Supraincarcarea operatorilor new si delete.

9. Supraincarcarea operatorului apel de functie.

10. Supraincarcarea operatorilor de conversie.

11. Supraincarcarea operatorilor << si >>.

12. Probleme.


Operatorii sunt notatii concise, infixate, pentru operatii matematice uzuale. Limbajul C++, ca orice limbaj de programare asigura un set de operatori pentru tipurile primitive. In plus, fata de limbajul C, C++ ofera posibilitatea asocierii operatorilor existenti cu tipurile definite de utilizator . Astfel, prezinta interes extinderea operatorilor in aritmetica complexa, algebra matriciala, in lucrul cu siruri de caractere, etc. Un operator poate fi privit ca o functie, in care termenii sunt argumentele functiei (in lipsa operatorului , expresia a+b s-ar calcula apeland functia aduna(a,b)).



Limbajul C++ introduce urmatorii operatori noi: new si delete- pentru gestiunea memoriei dinamice, operatorul de rezolutie (::) si operatorii de acces la membri: . si ->*


1. Supraincarcare.

Prin supraincarcarea unui operator, acesta este utilizat in contexte diferite, avind aceeasi semnificatie sau o semnificatie diferita. Astfel operatorul + este supraincarcat pentru adunarea intregilor si a realilor; operatorul << este supraincarcat cu semnificatia de deplasare la stinga, daca termenii sunt intregi sau inserare in flux, daca un termen este un flux de date, iar celalalt un obiect.

Programatorul poate asocia noi semnificatii operatorilor existenti prin supraincarcarea operatorilor. Vom evita folosirea termenului redefinire, caruia ii vom da o semnificatie diferita, in contextul mostenirii.

Anumiti operatori pot fi utilizati cu orice tip de termeni (sunt deja supraincarcati global de catre compilator). Acestia sunt: new, delete, sizeof, ::, =, &, ->*, .*, ., ->.

Pot fi supraincarcati urmatorii operatori:

- * / % ^ & | ~ ! = < >

+= -= *= /= %= ^= &= |= >>= <<= == != <= >=

&& || ++ -- ->* , -> << >> [] ()

new new[] delete delete[]

Nu pot fi supraincarcati operatorii: ::, ., .*, ?:, sizeof.

Setul de operatori ai limbajul C++ nu poate fi extins prin asocierea de semnificatii noi unor caractere, care nu sunt operatori de exemplu nu putem defini operatorul **)

Prin supraincarcarea unui operator nu i se poate modifica aritatea (astfel operatorul este unar si poate fi redefinit numai ca operator unar. De asemeni asociativitatea si precedenta operatorului se mentin.

La supraincarcarea unui operator nu se pot specifica argumente cu valori implicite.

Operatorii supraincarcati intr-o clasa sunt mosteniti in clasele derivate (exceptie face operatorul de atribuire

Semnatura unei functii in care se supraincarca un operator este:

tip_rezultat operator#(lista_argumente);


2. Functii prieten.

In afara functiilor membre, datele private si cele protejate mai pot fi accesate de functiile prieten (friend) ale clasei. O functie este considerata prietena al unei clase, daca declararea functiei precedate de specificatorul friend, apare in declararea clasei,. Definitia functiei prieten se face global, in afara clasei.

Daca o functie are ca parametri obiecte apartinand la doua clase diferite, atunci ea poate fi declarata ca functie membru a unei clase si prieten al celeilalte clase, sau ca functie prietena ambelor clase.

De exemplu fie o functie de inmultire a unei matrice cu un vector. Parametrii functiei vor fi doua obiecte - o matrice si un vector. Clasele respective Mat si Vec pot declara fiecare, functia MatVec() ca prietena:

class Mat;

class Vec;

De asemenea functiile prieten se utilizeaza in contextual supraincarcarii operatorilor.

Declararea unei functii prieten poate fi facuta in orice parte a clasei (publica, privata sau protejata).

O functie prietena a unei clase poate accesa toti membrii clasei. Daca o clasa este prietena cu alta clasa, membrii ei pot accesa membrii celeilalte clase.


3. Modalitati de supraincarcare a operatorilor.

O functie operator supraincarcata poate fi introdusa ca functie membra (in general nestatica) sau functie prieten (functie nemembra).

Declararea unei functii membra nestatica specifica urmatoarele:

functia poate accesa partea privata a declaratiei clasei

functia este in domeniul clasei

functia trebuie apelata dintr-un obiect

O functie membra statica satisface numai primele doua conditii, in timp ce o functie prietena a unei clase satisface numai prima conditie.

O functie operator avand ca prim argument un tip primitiv nu poate fi functie membru.

Functiile care modifica reprezentarea unui obiect necesita acces la datele membri, deci trebuie sa apartina clasei. Ele sunt functii membrecu argumente referinte neconstante.

Daca se doresc conversii implicite pentru termenii functiei operator, aceasta va fi functie nemembra cu argumente referinte constante. Aceste functii implementeaza operatorii care nu necesita operanzi L-valori (adica se aplica tipurilor fundamentale). Acestia sunt in general operatorii binari. Necesitatea accesului la reprezentare determina definirea lor ca functii prieten.

Operatorii care produc o noua valoare din valorile argumentelor (de exemplu operatorul ) se definesc in afara clasei.

Daca nu sunt necesare conversii de tip, alegerea intre functie membru si functie prieten ramane la latitudinea programatorului.

O functie nemembra foloseste numai argumente explicite, in timp ce o functie membra foloseste argumentul implicit this.

Argumentele clase, transmise prin valoare se copiaza in stiva neeconomic. Se prefera in acest caz argumentele referinte constante.

Daca valoarea intoarsa de functie este o referinta, atunci aceasta nu poate fi o variabila automatica (locala functiei). Ea nu poate fi nici o variabila statica locala, deoarece operatorul poate fi folosit de mai multe ori intr-o expresie. Valoarea de intoarcere trebuie sa fie alocata in memoria libera (heap) sau sa fie preluata dintr-un buffer de obiecte statice.

Intoarcerea unei referinte la obiectul modificat se realizeaza prin return *this

Se cauta minimizarea numarului de functii care au acces la reprezentarea interna a unei clase, prevazandu-se functii de acces.

In mod obligatoriu sunt functii membre: constructorii, destructorii, functiile virtuale, etc.

4. Operatori supraincarcati ca functii prieten.

Operatorii folositi in mod uzual pot fi unari sau binari. Utilizarea unui operator binar sub forma a#b este interpretata ca operator#(a,b)

Asadar, un operator binar va fi reprezentat printr-o functie nemembra cu doua argumente, iar un operator unar, printr-o functie nemembra cu un singur argument.

Argumentele se iau clase sau referinte constante la clase (pentru o preluare economica, asigurand protectia datelor)

Vom exemplifica pentru clasa Cplx:

class Cplx;

//definitii operatori in afara domeniului clasei

Cplx operator+(const Cplx& s, const Cplx& d);

Cplx operator-(const Cplx& s, const Cplx& d);

Cplx operator*(const Cplx& s, const Cplx& d);

Cplx operator/(const Cplx& s, const Cplx& d);


int operator==(const Cplx& s, const Cplx& d);

int operator!=(const Cplx& s, const Cplx& d);

Cplx operator-(const Cplx& z);

Cplx operator!(const Cplx& z);

Cplx& operator++(Cplx& z);

Cplx operator++(Cplx& z,int);

Pentru a face deosebirea intre semnaturile functiilor operatori de incrementare prefix si postfix s-a introdus un argument fictiv pentru cel din urma.

Incrementarea prefix intoarce valoarea incrementata, deci trebuie sa fie o L-valoare (rezultatul intors va fi o referinta), in timp ce postincrementarea intoarce valoarea dinaintea incrementarii.

5. Operatori supraincarcati ca functii membri.

Functiilor membru li se transmite un argument implicit (ascuns) this (adresa obiectului, care poate reprezenta primul termen), motiv pentru care un operator binar poate fi implementat printr-o functie membru nestatica cu un singur argument (termenul din dreapta operatorului). a#b este interpretat ca a.operator#(b)

O functie membru operator unar ca o functie membru nestatica fara argumente ( #a se interpreteaza ca a.operator#(); pentru operatorul postfixat a conventia este a.operator#(int)

In acest context, operatorii clasei Cplx se scriu:

Class Cplx;


Cplx Cplx::operator+(const Cplx& d);

Cplx Cplx::operator-(const Cplx& d);

Cplx Cplx::operator*(const Cplx& d);

Cplx Cplx::operator/(const Cplx& d);

Cplx& Cplx::operator+=(const Cplx& d);

return *this;


Cplx& Cplx::operator-=(const Cplx& d);

return *this;


Cplx& Cplx::operator*=(const Cplx& d);

return *this;


Cplx& Cplx::operator/=(const Cplx& d);

return *this;


int Cplx::operator==(const Cplx& d);

int Cplx::operator!=(const Cplx& d);

Cplx& Cplx::operator-();

Cplx& Cplx::operator!();

Cplx& Cplx::operator++();

Cplx Cplx::operator++(int);


6. Supraincarcarea operatorului de atribuire.

Operatia de atribuire simpla, daca nu este supraincarcata, realizeaza o copiere membru cu membru.

Pentru obiectele care nu contin date alocate dinamic la initializare, atribuirea prin copiere membru cu membru functioneaza corect, motiv pentru care nu se supraincarca operatorul de atribuire.

Pentru clasele ce contin date alocate dinamic, copierea membru cu membru, executata in mod implicit la atribuire conduce la copierea pointerilor la datele alocate dinamic, in loc de a copia datele.

Operatorul de atribuire poate fi redefinit numai ca functie membra, el fiind legat de obiectul din stanga operatorului =, o L-valoare, motiv pentru care va intoarce o referinta la obiect.

O prima cerinta la scrierea functiei operator= este evitarea autoatribuirii a=a. In acest scop se efectueaza testul this != &d (unde d este parametrul functiei obiectul din dreapta operatorului =

Urmeaza apoi curatirea" membrului stang (eliberarea memoriei alocate dinamic). Copierea propriu zisa este facuta de obicei folosind constructorul de copiere.

Functia operator returneaza o referinta la obiectul modificat (return *this

Exemplificam pentru clasa String, definita astfel:

class String

//ctor de copiere

String::String& operator=(const String& d);

return *this; //intoarce obiectul modificat


//ctor de initializare (cu un sir tip C)

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

7. Supraincarcarea operatorului de indexare.

Operatorul de indexare este un operator binar, avand ca prim termen obiectul care se indexeaza, iar ca al doilea termen indicele: obiect [ indice ] si este interpretat ca: obiect.operator[ ](indice)

Functia operator de indexare trebuie sa fie functie membra nestatica.

Primul termen, transmis implicit prin this este obiectul asupra caruia se executa indexarea.

Argumentul functiei reprezinta indicele, care poate fi de orice tip, spre deosebire de indicii predefiniti si este al doilea termen din operator.

Valoarea intoarsa de functia operator este o referinta la elementul indexat din obiect. Exemplificam cu operatorul de indexare pentru clasa String:

class String;

char& String:: operator[](int i);

8. Supraincarcarea operatorilor new si delete.

Operatorii new si delete pot fi supraincarcati ca functii operatori membre statice.

Functia operator new are semnatura: void* operator new(size_t); Operatorul redefinit apeleaza constructorul clasei dupa alocarea dinamica pe care o realizeaza.

Functia operator delete are semnatura: void operator delete(void*); unde parametrul este un pointer la obiectul eliminat. Operatorul redefinit delete apeleaza intotdeauna destructorul clasei inainte de a elibera memoria alocata dinamic.

Daca in clasa C se supraincarca operatorul new, atunci versiunea furnizata de sistem se obtine prin C *p = ::new C();

Exemplu1:Supraincarcati operatorul new, astfel incat sa initializeze memoria alocata la 0.

void* C::operator new(size_t dim)

Exemplu1:Supraincarcati operatorul new[], astfel incat sa initializeze memoria alocata la o valoare data ca parametru.

void* C::operator new (size_t dim, unsigned v)

9. Supraincarcarea operatorului apel de functie.

Apelul unei functii este o constructie de forma

nume_functie(lista_argumente);

desemnand operatorul binar() aplicat celor doi termeni nume_functie si lista_argumente

Numele functiei poate fi inlocuit printr-un pointer la functie:

(*pf)(lista_argumente);

Functia operator redefinit apel de functie va avea asadar 2 parametri: un obiect si o lista de argumente. Implementata ca functie membra nestatica, primul parametru este transmis implicit, astfel ca un apel de forma:

obiect(lista_argumente);

este interpretat ca:

obiect.operator()(lista_argumente);

Supraincarcarea operatorului () se utilizeaza la definirea functorilor (obiecte functii). Un functor este un obiect pentru care se supraincarca operatorul apel de functie (operator()()) si care se comporta ca o functie.

In mod uzual obiectele functii se folosesc in locul pointerilor la functii. Functiile inline nu pot folosi ca parametri pointeri la functii (care sunt apelati indirect), ci obiecte functii.

Operatorul apel de functie asigura o sintaxa uniforma pentru obiectele care se comporta ca si functiile.

Algoritmii generici din STL au printre argumente si o biecte functii. Acestea pot fi:

- generatori = functori fara argumente

- functii unare = functori cu un argument

- functii binare = functori cu doua argumente.

O functie unara booleana este un predicat, in timp ce o functie binara booleana este un predicat binar.

De exemplu, pentru o dreapta, definita prin taietura in origine si panta putem defini clasa:

class Dreapta //ctor

double operator()(double x) //functor


Clasa va fi folosita intr-o functie main() astfel:

Dreapta d1;

Dreapta d2(2., 3.);

double y1=d1(5.5); //y1=5.5

double y2=d2(1.5); //y2=2*1.5+3=6

Definiti un obiect functie (functor) care genereaza termenul de rang n din sirul lui Fibonacci.

class Fibo;        //constructor

long operator()(int n); //supraincarcare operator functie

private:

long x, y;


long Fibo::operator ()(int n);

return x;


10. Supraincarcarea operatorilor de conversie.

In C++ la evaluarea unei expresii se efectueaza conversii implicite pentru tipurile predefinite. Deoarece nu exista conversii implicite de la o clasa la un tip predefinit, programatorul isi poate defini conversii explicite prin supraincarcarea unui operator de conversie al clasei. Astfel pentru clasa C, functia membru nestatica de conversie C::operator T() unde T este un nume de tip primitiv realizeaza conversia de la tipul C la tipul T. Aceasta nu specifica nici un tip de rezultat intors, deoarece se returneaza implicit valoarea obiectului convertita la tipul pentru care este definita conversia si nu are parametri.

Functia operator primeste ca prim parametru implicit adresa obiectului si intoarce valoarea convertita de tipul numelui functiei operator de conversie.

Apelul explicit al functiei de conversie de la un obiect din clasa C la tipul primitiv T se specifica prin T(obiect) sau (T) obiect.

Pentru conversia unui obiect intre doua clase C1 si C2,C1->C2 se defineste functia membru operator de conversie C1::operator C2(); Pentru ca aceasta functie sa aiba acces la membrii clasei C2, se declara functie prieten clasei C2.

Sunt premise astfel conversii intre o clasa si un tip predefinit sau intre doua clase, dar nu de la un tip predefinit la o clasa.

Constructorii cu un singur argument pot fi folositi ca functii de conversie de la tipul argumentului la clasa constructorului. Acest efect nu este intotdeauna dorit, si pentru a-l evita, constructorul se declara precedat de cuvantul cheie explicit.

Daca o metoda a unei clase foloseste parametri care sufera conversii implicite, metoda se va defini ca functie prietena, nu ca functie membra.

Definim ca exemplu clasa Inch:

class Inch //ctor

void Inch_cm();

operator int() const ; //fctie conversie



11. Supraincarcarea operatorilor << si >>.

Operatorii de intrare / iesire pot fi supraincarcati. Operatorul de extractie >>, membru al clasei istream serveste pentru extragerea datelor de tipuri predefinite din fluxul de intrare cin. Prin supraincarcarea operatorului putem extrage din fluxul de intrare f, obiecte ob, scriind f >> ob;

Functia operator corespunzatoare are semnatura:

istream& operator >> (istream& f, clasa & ob);

Operatorul de insertie <<, membru al clasei ostream serveste pentru depunerea datelor de tipuri predefinite in fluxul de iesire cout. Supraincarcarea operatorului permite depunerea de obiecte ob in fluxul de iesire f cu f << ob;

ostream& operator << (ostream& f, const clasa & ob);

Intrucat ambele functiile operatori intorc referinte la fluxuri (prin return f), operatorii pot fi inlantuiti.(f << o1 << o2;)

Functiile operator pentru supraincarcarea operatorilor de intrare / iesire se declara functii prieten al clasei care interactioneaza cu fluxul.

Exemplificam cu clasele Cplx si String:

class Cplx;


ostream& operator<<(ostream& os, const Cplx& z);

istream& operator>>(istream& is, Cplx& z);

class String;


ostream& operator<<(ostream& os,const String& w);

istream& operator>>(istream& is, String& w);


12. Probleme.

O expresie patratica de o variabila are forma: ax2+bx+c in care numerele a,b,c (coeficientii) au valori fixate, iar variabila x poate lua diferite valori.

Specificati,proiectati si implementati clasa Patrat, care poate pastra informatii

asupra unei expresii patratice.

Un constructor implicit seteaza cei 3 coeficienti la zero.

Se vor prevedea functii membru pentru:

- schimbarea coeficientilor

- aflarea valorii curente a coeficientilor

- evaluarea unei expresii patratice pentru un x dat

- determinarea numarului de radacini reale a unei expresii patratice

Se vor redefini operatorii + si * ca functii nemembre pentru: adunarea a doua expresii patratice:

Patrat operator +(const Patrat &p1, const Patrat &p2);

- inmultirea unei expresii patratice cu o constanta

Patrat operator *(double k, const Patrat &p);

Proiectati si implementati clasa Complex care sa permita lucrul cu numere complexe.

Constructorul clasei va avea ca argumente partea reala, respectiv imaginara a numarului complex (in mod implicit aceste valori se iau 0).

Se va asigura un constructor de copiere.

Se vor prevedea functii membri pentru:

- accesul la partea reala, respectiv imaginara a numarului complex

- supraincarcarea operatorilot +=, -=, *=, /= pentru adunarea, scaderea, inmultirea si impartirea numarului complex cu un alt numar complex dat ca argument

- modulul numarului complex

- argumentul numarului complex

Se va redefini operatorul >> ca functie prieten pentru citirea unui numar complex de la intrarea standard

Se vor asigura functii nemembru pentru:

- testul de egalitate a doua numere complexe (supraincarcarea operatorului ==)

- scrierea unui numar complex la iesirea standard (supraincarcarea operatorului <<)

- supraincarcarea operatorilor +,-,*,/ pentru a permite operatii cu doua argumente numere complexe

- supraincarcarea operatorului de atribuire


Proiectati si implementati clasa Rational care sa permita lucrul cu numere rationale.

Constructorul clasei va avea doua argumente: numaratorul, respectiv numitorul numarului rational (constructorul poate avea si un singur argument,caz in care al doilea se ia implicit 1,sau nici un argument, caz in care se iau valorile implicite 0 si 1).

Se va asigura un constructor de copiere.

Se vor prevedea functii membri pentru:

- accesul la numaratorul, respectiv numitorul numarului rational

- supraincarcarea operatorilot +=, -=, *=, /= pentru adunarea, scaderea, inmultirea si impartirea numarului rational cu un alt numar rational dat ca argument

Se va redefini operatorul >> ca functie prieten pentru citirea unui numar rational de la intrarea standard

Se vor asigura functii nemembre pentru:

- testul de egalitate a doua numere rationale (supraincarcarea operatorului ==)

- scrierea unui numar rational la iesirea standard (supraincarcarea operatorului <<)

- supraincarcarea operatorilor +,-,*,/ pentru a permite operatii cu doua argumente numere rationale.

- supraincarcarea operatorului de atribuire.

4. Proiectati si implementati clasa Vector care sa permita lucrul cu vectori de elemente reale.

Constructorul clasei va avea un argument - dimensiunea vectorului si va aloca emorie

pentru vector (in lipsa argumentului se ia implicit dimensiunea 10)

Se va asigura un destructor si un constructor de copiere.

Se vor prevedea functii membri pentru:

- determinarea dimensiunii vectorului

- determinarea lungimii vectorului

- supraincarcarea operatorilor +=, -=, pentru adunarea si scaderea vectorului cu un alt vector dat ca argument

Se va redefini operatorul >> ca functie prieten pentru citirea unui vector de la intrarea standard

Se vor asigura functii nemembre pentru:

- testul de egalitate a doi vectori (supraincarcarea operatorului ==)

- scrierea unui vector la iesirea standard (supraincarcarea operatorului <<)

- supraincarcarea operatorilor +,- pentru a permite operatii cu doua argumente vectori

- supraincarcarea operatorului * pentru a permite calculul produsului scalar a doi vectori

Proiectati si implementati clasa Matrice care sa permita lucrul cu matrice patrate de elemente reale.

Constructorul clasei va avea un argument - dimensiunea, adica numarul de linii si de coloane al matricei, va aloca memorie pentru matrice (in lipsa argumentului se ia implicit dimensiunea 10) si va permite accesul la elementele individuale prin indexare.

Se va asigura un destructor si un constructor de copiere.

Se vor prevedea functii membre pentru:

- determinarea dimensiunii matricei

- calculul determinantului matricii

- supraincarcarea operatorilor +=, -=, *=, pentru adunarea, scaderea, si inmultirea unei matrice cu o alta matrice data ca argument

- supraincarcarea operatorului /= pentru calculul inversei matricei

Se va redefini operatorul >> ca functie prieten pentru citirea unei matrici de la intrarea standard

Se vor asigura functii nemembre pentru:

- testul de egalitate a doua matrice (supraincarcarea operatorului ==)

- scrierea unei matrice la iesirea standard (supraincarcarea operatorului <<)

- supraincarcarea operatorilor +,-,* pentru a permite operatii cu doua argumente matrice.

6. Proiectati si implementati clasa String care sa permita lucrul cu siruri de caractere terminate cu nul.

Constructorul clasei va avea un argument-dimensiunea adica numarul de caractere al sirului si va aloca memorie pentru sir (in lipsa argumentului se ia implicit dimensiunea 80).

Se va asigura un destructor si un constructor de copiere.

Se vor prevedea functii membre pentru:

- determinarea lungimii sirului

- supraincarcarea operatorului += pentru concatenarea sirului cu un alt sir dat ca argument

- determinarea pozitiei primei aparitii a unui sir dat ca argument in sirul dat

Se va redefini operatorul >> ca functie prieten pentru citirea unui sir de caractere de la intrarea standard

Se vor asigura functii nemembre pentru:

- testul de egalitate a doua siruri (supraincarcarea operatorului ==)

- comparatia lexicografica a doua siruri date ca argumente (rezultat -1, 0 sau 1)

- scrierea unui sir la iesirea standard (supraincarcarea operatorului <<)

- supraincarcarea operatorului + pentru a permite operatia de concatenare a doua siruri date ca argumente

- supraincarcarea operatorului de atribuire.

- selectarea dintr-un sir a unui alt sir definit prin pozitie de inceput si lungime

- stergerea dintr-un sir a unui numar de caractere incepand cu o pozitie data.




Contact |- ia legatura cu noi -| contact
Adauga document |- pune-ti documente online -| adauga-document
Termeni & conditii de utilizare |- politica de cookies si de confidentialitate -| termeni
Copyright © |- 2024 - Toate drepturile rezervate -| copyright