1.SUPRAINCARCAREA OPERATORULUI = 1

2.SUPRAINCARCAREA OPERATORULUI CAST 1

3.SUPRAINCARCAREA OPERATORULUI [ ] 1

4.SUPRAINCARCAREA OPERAT. NEW SI DELETE 1

5.SUPRAINCARCAREA OPERATORILOR ++ si -- 1

6.SUPRAINCARCAREA OPERATORULUI + 1

7.FUNCTII SUPRAINCARCATE 1


 

SUPRAINCARCAREA OPERATORULUI DE ASIGNARE =

-functia operator=( ) nu poate fi functie membra statica

-nu se mosteneste in clasele derivate

-exista diferenta intre atribuire si initializare(initializarea /instantierea se realizeaza cu ajutorul constructorilor). Aceste doua operatii desi asemanatoare ca forma difera ca actiune.

ex.

persoana s(80);

persoana t=s; //INITIALIZARE

persoana u(30);

s=u; //ATRIBUIRE

Ca diferenta majora dintre cele doua operatii se observa ca initializarea declara tipul valorii ce urmeaza a fi atribuita unui obiect ,in timp ce atribuirea nu o face .

ex.

int k=17 ; //initializare

u=42 ; //atribuire

ex.atribuire intre obiecte de acelasi tip

#include<iostream.h>

#include<string.h>

class persoana{

private :

char nume[40];

long int telefon;

int varsta;

public:

persoana(char *n, long tel,int v) :telefon(tel),varsta(v){strcpy(nume,n);}

int get_varsta( ){return varsta;}

int set_varsta(int v ){return varsta=v;}

void operator =(persoana &p);

void afisare(){cout<<nume<<" "<<telefon<<" "<<varsta<<endl;}

~persoana(){cout<<"apelat destructor"<<endl;}

};

void persoana::operator =(persoana &p)

{

set_varsta(p.get_varsta());

strcpy(nume,p.nume);

telefon=p.telefon;

}

void main()

{

persoana p1("POP",321778,28),p2("VASILE",321779,30);

p1.afisare();

p2.afisare();

p1=p2; //echivalent cu p.operator=(s); APEL FUNCTIA OPERATOR =( )

p1.afisare();

p2.afisare();

}

va afisa : POP 321778 28

VASILE 321779 30

VASILE 321779 30

VASILE 321779 30

apelat desructor

apelat destructor

 

-ex.Cel mai simplu mod de a efectua atribuirea intre obiecte este de a lasa in seama compilatorului executia intregii operatii de atribuire :

#include<iostream.h>

#include<string.h>

class persoana{

private :

char nume[40];

long int telefon;

int varsta;

public:

persoana(char *n, long tel,int v) :telefon(tel),varsta(v){strcpy(nume,n);}

int get_varsta( ){return varsta;}

int set_varsta(int v ){return varsta=v;}

//void operator =(persoana &p);

void afisare(){cout<<nume<<" "<<telefon<<" "<<varsta<<endl;}

~persoana(){cout<<"apelat destructor"<<endl;}

};

/*void persoana::operator =(persoana &p)

{

set_varsta(p.get_varsta());

strcpy(nume,p.nume);

telefon=p.telefon;

}*/

void main()

{

persoana p1("POP",321778,28),p2("VASILE",321779,30);

p1.afisare();

p2.afisare();

p1=p2; //atribuire facuta de compilator ; nu este apelata functia operator=( )

p1.afisare();

p2.afisare();

}

va afisa : POP 321778 28

VASILE 321779 30

VASILE 321779 30

VASILE 321779 30

apelat destructor

apelat destructor

ex.Nedefinind operatorul de atribuire = in cazul atribuirii :

persoana a(40) , b(80);

a=b;

se vor efectua asignarile :

a.nume=b.nume;

a.varsta=b.varsta ; unde nume si varsta sunt declarate in zona public.

Se observa ca obiectele ocupa aceeasi locatie de memorie deoarece se copiaza pointeri/adrese si nu continuturi ale memoriei .Eliberarea memoriei va duce la coruperea memoriei heap.Deci se impune redefinirea operatorului de asignare in vederea manevrarii corecte a memoriei.

ex.

#include <iostream.h>

#include<string.h>

class persoana {

int varsta;

char *pnume;

public:

//constructor de clasa

persoana () {pnume=NULL;varsta=0;}

persoana (char *n,int v) : varsta(v)

{

pnume=new char[strlen("ANONIM")+1];

strcpy(pnume,n);

}

//constructor de copiere

persoana(persoana &pers ):varsta(pers.varsta)

{

pnume=new char[strlen(pers.pnume)+1];

strcpy(pnume,pers.pnume);

}

//supraincarcare operator =

//va returna o referinta catre un obiect

persoana &operator =(persoana &pers)

{

delete [ ] pnume;

pnume=new char[strlen(pers.pnume)+1];

varsta=pers.varsta;

strcpy(pnume,pers.pnume);

return *this;

}

char &operator [ ](int i) {return pnume[i];}

//destructor inline

~persoana (){cout<<"apel destructor "<<endl;delete [] pnume;}

int spune_varsta(){return varsta;}

char *spune_nume(){return pnume ;}

void adresa (){cout<<"adresa fizica a obiectului este "<<this<<endl;}

};

void main ()

{

persoana p1("pop",28);

persoana p2=p1; //initializare apel constructor de copiere

cout<<p1.spune_nume()<<"are"<<' '<<p1.spune_varsta()<<"ani"<<"\n";

cout<<p2.spune_nume()<<"are"<<p2.spune_varsta()<<"ani"<<"\n";

p1.adresa();

p2.adresa();

persoana p3,p4=persoana(p1.spune_nume(),5);

p3=p4; //atribuire apel functia operator =( )

cout<<p3.spune_nume()<<"are"<<' '<<p3.spune_varsta()<<"ani"<<"\n";

p3.adresa();

p4.adresa(); //obiectele au locatii de memorie diferite

p1.operator =(p3); //functia este membra echivalent cu apelul p1=p3;

cout<<p1.spune_nume()<<p1.spune_varsta()<<endl;

}

va afisa : popare 28ani

popare 28ani

adresa fizica a obiectului este …

adresa fizica a obiectului este …

pop are 5ani

pop5

apel destructor

apel destructor

apel destructor

apel destructor

Comparand constructorul de copiere cu operatorul =( ) se obs.ca seamana foarte mult singura diferenta dintre cele doua functii aparand in cazul constructorului caz in care nu este necesara eliberarea memorie aceasta nefiind ocupata anterior .

 


SUPRAINCARCAREA OPERATORULUI DE CAST (operator unar )

- Functiile de conversie de tip trebuie sa fie functii membre .

ex:

operator double ( ) { return ;}

ex.operatorii aritmetici :

+ adunare

- scadere

* inmultire

/ impartire (aplicat unui intreg sau unui caracter va elimina restul )

% operator modulo (retine restul unei impartiri de intregi )

ex.5/2 va fi egal cu 2

ex.5%2 va fi egal cu 1

ex.

float b;

b=3/(float)2;

Folosind operatorul de casting (), b va avea valoarea 1.5. Īn absenta acestui operator, la īmpartirea lui 3 la 2, ambele valori fiind īntregi, rezultatul ar fi fost trunchiat la 1, dupa care ar fi fost atribuit variabilei b.

#include<iostream.h>

#include<string.h>

class persoana {

public:

char nume[20];

double salar ;

persoana () {};

persoana (char *n,double s) {strcpy(nume,n);salar=s;}

persoana (persoana &p){p.salar=0;} //constructor de copiere

operator double (){return salar;} //supraincarcare operator de cast ()

double cumul (double s) {return s+ salar;}

};

main ()

{

persoana p1("pop ionel",85),p2("pop claudia",50),p3("alina ",111);

cout<<p3.nume<<" are "<<(double)p3<<"lei \n";

cout<<"familia "<<p1.nume<<"are "<<p1.cumul(p2)<<"lei \n"; //sau

double s;

s=p1+p2;

cout<<"familia "<<p1.nume<<"are "<<s <<"lei \n";

cout<<"cele trei persoane au salariul "<<p1+p2+p3<<"lei\n"; //sau

cout<<"cele trei persoane au salariul "<<p1.cumul(p2)+p3<<"lei\n";

cout<<"le lipsesc 100 pentru a avea impreuna "<<p1+p2+p3+100<<"lei \n";

return 0;

}

atentie !

Se poate pune in clasa persoana si un membru int varsta care ne-ar permite o supraincarcare a operatorului cast astfel :

oprator int ( ) { return varsta ;}

care atunci cand se cauta un int in loc de persoana directioneaza conversia catre int .

Ce se intampla la evaluari de tipul p1+p2 ?

Neexistand supraincarcari pentru adunari de persoane se vor cauta cast-urile date de programator .Din nefericire se vor gasi doua (pentru double si pentru int ) ceea ce nu e corect sa fie asa .

Pentru a rezolxa problema putem scrie explicit (nu p1+p2):

s=(double)p1 + (int)p2 caz in care nu rezolva problema logic pentru ca aduna salariul cu varsta .

Deoarece prototipul lui cumul este scris cu double duce la directionarea automata a compilatorului catre cast-ul spre double .

#include<iostream.h>

#include<string.h>

class persoana {

public:

char nume[20];

double salar ;

int varsta ;

persoana () {};

persoana (char *n,double s ,int v) {strcpy(nume,n);salar=s;varsta=v;}

persoana (persoana &p){p.salar=0;p.varsta=0;} //constructor de copiere

operator double (){return salar;} //supraincarcare operator de cast ()

double cumul (double s) {return s+ salar;}

 

operator int (){return varsta;}

int cumulare(int m){return m+varsta ;}

};

main ()

{

persoana p1("pop ionel",85,20),p2("pop claudia",50,30),p3("alina ",111,20);

cout<<p3.nume<<" are "<<(double)p3<<"lei \n";

cout<<p3.nume<<"are"<<(int)p3<<"ani\n";

cout<<"familia "<<p1.nume<<"are "<<p1.cumul(p2)<<"lei \n"; //sau

double s;

s=(double)p1+(double )p2;

cout<<"familia "<<p1.nume<<"are "<<s <<"lei \n";

int v;

v=(int)p1 +(int)p2;

cout<<"familia "<<p1.nume<<"are cumulat varsta de "<<v<<"ani\n";

cout<<"cele trei persoane au salariul "<<(double)p1+(double)p2+(double)p3<<"lei\n"; //sau

cout<<"cele trei persoane au salariul "<<p1.cumul(p2)+(double)p3<<"lei\n";

cout<<"cele trei persoane au varsta cumulata de "<<p1.cumulare(p2) +(int) p3<<"ani\n";

cout<<"le lipsesc 100 pentru a avea impreuna "<<(double)p1+(double)p2+(double)p3+100<<"lei \n";

return 0;

}


SUPRAINCARCAREA OPERATORULUI [ ]

-operatorul [ ]( numit si subscript sau indice )este considerat in C++ operator binar

-se supraincarca prin functie membra care nu sunt de tip static;

-nu poate fi functie operator friend ;

-adreseaza un element in cadrul unui vector de obiecte

-functia supraincarcata primeste un int folosit pentru reperarea elementului si returneaza referinta la un obiect pentru al putea localiza intr-un vector de obiecte furnizand deci o l-valoare si sa poata fi folosit in ambele parti ale atribuirii :

tip &nume_clasa :: operator [ ](int i)

{

//corpul functiei

}

ex.

#include<iostream.h>

class tip{

int a[3];

public:

tip(int i,int j,int k){ a[0]=i; a[1]=j; a[2]=k;}

int &operator[ ](int i) {return a[i];}

};

main( )

{

tip ob(111,992,333);

cout<<ob[1]<<endl; //va afisa 992

ob[1]=25; //[ ] este in stanga lui =

cout<<ob[1]; //va afisa acum 25

return 0;

}

Deoarece operator[ ] ( ) returneaza referinta catre elementul matricei cu indice i ,el poate fi folosit in partea stanga a unei atribuiri pt. a modifica un element a matricei (poate fi fol.si pe dreapta ).

ex.

Este posibil in C++ sa depasim in sus sau in jos limitele matricei in timpul rularii fara sa primim un mesaj de eroare .

Se supraincarca operatorul [ ] pt. a verifica incadrarea indicelui in domeniu .

#include <iostream.h>

#include<stdlib.h> //pt.exit( )

class tip {

int a[3];

public:

tip(int i,int j,int k){ a[0]=i; a[1]=j; a[2]=k;}

int &operator[ ](int i) ;

};

int & tip::operator [ ](int i)

{

//se verifica incadrarea in limite a indicelui

if(i<0 || i>2) {

cout<<"EROARE DE LIMITA ";

exit(1);

}

return a[i];

}

main( )

{

tip ob(1,2,3);

cout<<ob[1]; //va afisa 2

ob[1]=25 ;

cout<<ob[1]; // va afisa 25

ob[3]=44; //determina eroare deoarece 3 este in afara limitei

return 0;

}

Eroarea de depasire a limitelor este depistata de operator [ ]( ).

ex.

Presupunem ca avem o clasa care gestioneaza un vector de double memorat dinamic clasa ocoleste astfel restrictia din limbaj de a lucra numai cu variabile masiv cu dimesiuni constante .

Dimensiunea fiind variabila furnizata constructorului si pastrata ca membru in clasa ar trebui sa verificam incadrarea indicelui in dimensiunea vectorului .

#include<iostream.h>

class vector {

double *v;

int dim;

static double err;

public:

vector (int n=1){dim=n; v=new double[n];}

~vector(){delete [] v;}

double &operator [](int i) {

if(i>=0 && i<dim) return v[i];

else { cout<<"EROARE INDICE "<<i<<endl;

return err; //adica zero

}

}

};

double vector ::err=0;

main()

{

vector v1(3); //?

vector v2[10]; //?

v1[2]=10; //aici actioneaza operatorul

cout<<v1[2]<<endl; //va afisa 10

v2[1][0]=9999;

cout<<v2[1][0]<<endl; //va afisa 9999

return 0;

}


SUPRAINCARCAREA OPERATORILOR NEW SI DELETE

-Operatorii new si delete sunt operatori unari

-operatorii new si delete realizeaza gestiunea memoriei dinamice intr-o maniera specifica programarii pe obiecte

-pot fi supraincarcati prin functii membre ale clasei sau prin functii independente

-functiile membre ce supradefinesc acesti operatori fiind de interes general pt.clasa respectiva sunt automat statice chiar daca nu s-a precizat explicit acest lucru ;oricum operatorul new nu ar putea fi supraincarcat prin functie nestatica deoarece el nu ar putea apartine unui obiect pe care tot el sa-l si aloce .

-chiar si supraincarcat operatorul new va conlucra cu constructorul clasei in alocarea si eventual initializarea unui obiect dinamic .La supradefinire functia operator va primi dimensiunea zonei de alocat si va returna adresa memoriei alocate .

ex. void *operator new (size_t dim) void *operator new (unsigned dim)

{ {

//efectueaza alocarea //efectueaza alocarea

return pointer_la _memorie ; return pointer_la _memorie ;

} }

size_t este definit ca un tip apt sa contina cea mai mare portiune de memorie contigua care poate fi alocata .

size_t este de tip intreg fara semn alt ex.corect este tipul unsigned.

Parametrul dim va contine numarul de octeti necesar pt.a memora obiectul pt.care se face alocarea .

-obligatoriu functia new supraincarcata trebuie sa returneze un pointer spre memoria alocata sau zero( NULL) daca apare o eroare de alocare

-Functia delete primeste un pointer spre regiunea de memorie pe care trebuie sa o elibereze si elibereaza sistemului memoria alocata anterior ;

ex. void operator delete(void *p) void operator delete(void *p)

{ {

delete p; free( p);

} }

-Cand new si delete sunt functii membre ale unei clase operatorii astfel supraincarcati vor fi folositi numai pentru obictele clasei , iar cand se utilizeaza operatorii new si delete pentru alte tipuri de date se va apela new si delete impliciti din C++;

ex.in care functiile supraincarcate new si delete sunt membre si vor invoca functiile malloc( ) si free( )

#include<iostream.h>

#include<stdlib.h>

class loc{

int longitud,latitud;

public:

loc(int lg,int lt){longitud=lg; latitud=lt;}

void arata(){cout<<longitud<<" "<<latitud<<endl;}

void *operator new (size_t dim)

{

return malloc(dim);

}

void operator delete(void *p)

{

free(p);

}

};

void main()

{

loc *p1,*p2;

p1=new loc(20,99); //apel new supraincarcat

if(!p1){

cout<<"EROARE DE ALOCARE "<<endl;

exit(1);

}

p2=new loc(50,1); //apel new supraincarcat

if(!p2){

cout<<"EROARE DE ALOCARE "<<endl;

exit(1);

}

p1->arata(); //20 99

p2->arata(); //50 1

delete p1; //apel delete supraincarcat

delete p2; //apel delete supraincarcat

int *f=new int[10]; //apel new implicit din C++ nu cel supraincarcat

delete f; //apel delete implicit din C++ nu cel supraincarcat

}

-se poate redefini global new si delete prin supraincarcarea acestor operatori in afara oricarei declaratii de clasa .

Cand sunt supraincarcati prin functie independenta declarata global definitia initiala a operatorului new si delete nu mai este recunoscuta pt.nici un tip de baza sau clasa , alocarea si gestionarea memorie dinamice revenindu-i in exclusivitate programatorului.Deci sunt ignorati new si delete impliciti din C++.

ex.

#include<iostream.h>

#include<stdlib.h>

class loc{

int longitud,latitud;

public:

loc(int lg,int lt){longitud=lg; latitud=lt;}

void arata(){cout<<longitud<<" "<<latitud<<endl;}

};

//new global (independent)

void *operator new (unsigned dim)

{

return malloc(dim);

}

//delete global(independent)

void operator delete(void *p)

{

free(p);

}

void main()

{

loc *p1,*p2;

p1=new loc(20,99);

if(!p1){

cout<<"EROARE DE ALOCARE "<<endl;

exit(1);

}

p2=new loc(-50,-1);

if(!p2){

cout<<"EROARE DE ALOCARE "<<endl;

exit(1);

}

p1->arata(); //20 99

p2->arata(); //-50 -1

delete p1;

delete p2;

//foloseste de asemenea new supraincarcat nu pe cel implicit

double *f=new double;

if(!f){

cout<<"EROARE DE ALOCARE "<<endl;

exit(1);

}

*f=10.111;

cout<<*f<<endl; //10.111

delete f; //foloseste delete supraincarcat nu pe cel implicit

}

ex.

//se aloca memorie unei matrice de obiecte

//este apelat automat functia constructor a fiecarui obiect al matricei

void *operator new [ ](size_t dim) void *operator new [ ](unsigned dim)

{ {

//efectueaza alocarea //efectueaza alocarea

return pointer_la _memorie ; return pointer_la _memorie ;

} }

//delete pentru o matrice de obiecte

// operatorul delete apeleaza repetat destructorul clasei pentru fiecare membru al masivului ;

ex void operator delete [ ] (void *p)

{

free( p);

}

ex.

#include<iostream.h>

#include<stdlib.h>

class loc{

int longitud,latitud;

public:

loc(int lg=0 , int lt=0 ){ longitud=lg ; latitud=lt;}

void arata(){cout<<longitud<<" "<<latitud<<endl;}

void *operator new (size_t dim)

{

return malloc(dim);

}

void operator delete(void *p)

{

free(p);

}

void *operator new [ ](size_t dim);

void operator delete [ ] (void *p);

};

void *loc::operator new[ ](size_t dim)

{

return malloc(dim);

}

void loc::operator delete[ ](void *p)

{

free(p);

}

void main()

{

loc *p1,*p2;

p1=new loc(20,99);//aloca memorie pt.un obiect

if(!p1){

cout<<"EROARE DE ALOCARE "<<endl;

exit(1);

}

p1->arata(); //20 99

p2=new loc[3]; //aloca memorie pt.o matrice

if(!p2){

cout<<"EROARE DE ALOCARE "<<endl;

exit(1);

}

for(int i=0;i<3;i++) p2[i].arata(); //0 0 0 0 0 0

delete p1; //elibereaza un obiect

delete [ ] p2; //elibereaza o matrice

}

-nu este permisa mixarea celor doua mecanisme de alocare si eliberare de memorie (cu functii malloc( ) si free( ),respectiv cu operatorii new si delete )adica alocare cu malloc( ) si dezolocare cu delete( ) sau alocare cu new si dezalocare cu free( ) .


SUPRAINCARCAREA OPERATORILOR ++ si --

-Operatorii unari ++ si – pot fi supraincarcati atat prin functii membre cat si prin functii independente .

-Fata de ceilalti operatori unari ei au o particularitate : pot fi atat prefixati cat si postfixati ,avand efecte diferite .

Efectul se manifesta diferit numai :

1.cand operatorul intra in compunere cu un alt operator

2.cu o instructiune

3.sau cu o functie

altfel expresiile p++ si ++p au acelasi efect .

Expresia : p1=p2++ intai copiaza pe p2 in p1 si apoi incrementeaza pe p2(ex.varsta lui p2);

ex.

#include<iostream.h>

class persoana{

public:

int varsta;

persoana(int v=0) :varsta(v) {};

friend persoana operator++(persoana &p); //prefixat

friend persoana operator ++(persoana &p,int); //postfixata

};

persoana operator++(persoana &p)

{

p.varsta++;

//functia returneaza referinta obiectului primit si incrementat

return p ;

}

persoana operator ++(persoana &p,int)

{

persoana aux=p; //conservarea starii initiale

//sau persoana aux(p);

p.varsta++;

//functia returneaza obiectul prin valoare

return aux;

}

main()

{

persoana p1(25),p2,p3;

p2=++p1;

cout<<p2.varsta<<endl; //va afisa 26

p2=p1++;

cout<<p2.varsta<<endl; //va afisa 26

cout<<p1.varsta<<endl; //va afisa 27

p3=++++p1;

cout<<p3.varsta<<endl; //va afisa 29

++++p3;

cout<<p3.varsta<<endl; //va afisa 30

return 0;

}


SUPRAINCARCAREA OPERATORULUI +

ex.

#include<iostream.h>

class loc{

int longitud,latitud;

public:

loc() {} ;

loc(int lg,int lt)

{

longitud=lg;

latitud=lt;

}

void arata (){

cout<<longitud<<" ";

cout<<latitud<<"\n";

}

loc operator +(loc op2); //este o functie membru

};

loc loc ::operator +(loc op2) //obigatoriu va avea un parametru

{

loc aux;

aux.longitud=longitud +longitud ;

aux.latitud=latitud +latitud;

return aux;

}

main()

{

loc ob1(10,20),ob2(5,30),ob3;

ob1.arata(); //afiseaza 10 20

ob2.arata(); //afiseaza 5 30

ob3=ob1+ob2; //apel

ob3.arata(); //afiseaza 15 50

return 0;

}

Dupa cum se observa loc operator +(loc op2);are un singur parametru chiar daca el supraincarca operatorul binar + .Motivul pt.care loc operator +(loc op2);are un parametru este acela ca operandul din stanga (primul) lui + este pasat implicit functiei folosind pointerul this .Operandul din dreapta este pasat in parametrul op2 .

Cand exista operatori binari supraincarcati cel care genereaza apelarea functiei operator este obiectul din stanga .

Functia loc operator +(loc op2);returneaza un obiect din clasa asupra careia opereaza (loc).

Daca functia loc operator +(loc op2); ar returna alt tip (o functie operator poate returna orice tip valid) aceasta expresie nu ar fi valida :

ex. ob1=ob1+ob2;

pt. ca suma lui ob1 si ob2 sa fie atribuita lui ob1 rezultatul acestei operatii trebuie sa fie un obiect de tip loc.

Returnand un obiect de tip loc este posibila si instructiunea :

(ob1+ob2).afisare( ); //afiseaza rezultatul lui ob1+ob2

cand se genereaza un obiect temporar care inceteaza sa mai existe dupa ce se termina apelarea pentru afisare( ).

ex.

#include<iostream.h>

class loc {

int lg ,lt ;

public :

loc () {};

loc(int longitudine ,int latitudine ){lg=longitudine ; lt=latitudine; }

void afiseaza (){cout<<lg<<" ";cout<<lt<<"\n";}

loc operator +(loc op2);

loc operator -(loc op2);

loc &operator =(loc op2);

loc &operator ++();

};

loc loc :: operator +(loc op2)

{

loc aux ;

aux.lg=lg+op2.lg;

aux.lt=lt+op2.lt;

return aux ;

}

loc loc ::operator -(loc op2)

{

loc aux ;

aux.lg=lg-op2.lg;

aux.lt=lt-op2.lt;

return aux ;

}

loc &loc :: operator =(loc op2)

{

//nu mai avem aux

lg=op2.lg;

lt=op2.lt;

return *this; //returneaza *this care este obiectul care a generat apelarea (operandul stang)

}

loc &loc :: operator ++()

{

lg++;

lt++;

return *this; //returneaza *this care este obiectul care a generat apelarea (operandul stang)

}

main ()

{

loc ob1(10,20),ob2(5,30),ob3(90,90);

ob1.afiseaza();

ob2.afiseaza();

 

loc ob4=ob1-ob2;

ob4.afiseaza();

loc ob5=ob1+ob2;

ob5.afiseaza();

++ob1;

ob1.afiseaza();

ob2=++ob1;

ob1.afiseaza();

ob2.afiseaza();

ob1=ob2=ob3; //atribuire multipla

ob1.afiseaza();

ob2.afiseaza();

return 0;

}

va afisa :

  1. 20
  1. 30

5 -10

15 50

11 21

12 22

12 22

90 90

90 90

In C++ daca operatorul de atribuire = nu este supraincarcat pentru fiecare clasa pe care o definim se creeaza automat (de catre compilator)o operatie implicita de atribuire .

Atribuirea implicita este o simpla copiere membru cu membru .Totusi supraincarcand = putem stabili cu explicit ce atribuire va face pt. o anumita clasa .In ex.de mai sus = supraincarcat face exact acelasi lucru ca in varianta initiala (ca si operatia facuta de compilator )dar in alte situatii el poate efectua alte operatii.

Functia loc &operator =(loc op2); returneaza *this care este obiectul care a generat apelarea (operandul stang).

Acest lucru este necesar daca se folosesc instructiunile de atribuire multipla :

ex. ob1=ob2=ob3;

Functia loc &operator ++(); nu are parametrii deoarece ++este operator unar si functia este membra a clasei loc iar operandul sau este transmis implicit folosind pointerul this .

Functiile loc &operator =(loc op2); si loc &operator ++(); modifica valoarea unui obiect .Prima functie ii atribuie o noua valoare iar a doua incrementeza cu valoarea 1.


FUNCTII SUPRAINCARCATE

-un mod in care C++ realizeaza polimorfismul in timpul compilarii este acela de supraincarcare a functiilor(overloading)

-in C++ doua sau mai multe functii pot sa aiba acelasi nume atata timp cat difera tipul si/sau numarul de parametrii iar procesul este numit supraincarcarea functiilor

-in timpul compilarii ,compilatorul de C++ determina care functie trebuie apelata bazandu-se pe numarul si tipul parametrilor pe care instructiunea de apelare ii transmite functiei ;

ex.in care doua functii numite suma ( ) care returneaza suma elementelor dintr-o matrice

#include<iostream.h>

int suma (int *matrice,int nr_elem)

{

int rez=0;

for(int i=0;i<nr_elem;i++) rez=rez + matrice[i];

return rez;

}

double suma(double *matrice,int nr_elem)

{

double rez=0;

for(int i=0;i<nr_elem;i++) rez+=matrice[i];

return rez;

}

void main()

{

int A[5]={1,6,7,10,10};

cout<<suma(A,5)<<endl; //afisare 34

double B[3]={12.3,12.6,10.0};

cout<<suma(B,3)<<endl; //afisare 34.9

}

ex.include<iostream.h>

void interschimba(int *a,int *b)

{

int temp=*a;

*a=*b;

*b=temp;

}

void interschimba(int *a,int *b,int *c,int *d)

{

int temp=*a;

*a=*b;

*b=temp;

temp=*c;

*c=*d;

*d=temp;

}

void main()

{

int A=1,B=2,C=3,D=4;

interschimba(&A,&B,&C,&D);

cout<<A<<" "<<B<<" "<<C<<" "<<D<<endl; //2 1 4 3

interschimba(&A,&B);

cout<<A<<" "<<B<<endl; // 1 2

int AA=99,BB=100;

interschimba(&AA,&BB);

cout<<AA<<" "<<BB<<endl; //100 99

}

 

-Nu pot fi supraincarcate doua functii care difera DOAR prin tipul returnat deoarece tipul returnat de functia supraincarcata nu asigura suficiente informatii in toate cazurile pt.ca un compilator sa decida ce functie sa foloseasca;

ex.

#include<iostream.h>

int functie (int a);

double functie(int a);//NU ESTE CORECT

int functie(int a,int b);

void main()

{

cout<<functie(10)<<endl; //10

cout<<functie(4,5)<<endl; //20

}

int functie(int a)

{

return a;

}

int functie(int a,int b)

{

return a*b;

}

ex.functii supraincarcate gresit deoarece *p este acelasi lucru cu p[ ] pt.compilator

void functie(int *p);

void functie(int p[ ]);

-compilatorul considera functiile ambigue in situatia in care el este incapabil sa faca dinstinctia intre doua sau mai multe functii supraincarcate ; caz in care compilatorul nu va compila programul deci apare eroare

ex.

#include<iostream.h>

double functie(double i);

void main()

{

cout<<functie(1500.1)<<endl; //apel corect double functie(double i) va afisa 1500.1

cout<<functie(1500)<<endl; //corect face conversia va afisa 1500

cout<<functie('a')<<endl; // corect face conversia va afisa 97 in cod ASCII

}

double functie(double i){return i; }

explicatie :

C++ incearca sa converteasca automat argumentele care sunt folosite pt.a apela o functie in tipurile argumentelor asteptate de functie .In ex.face conversia caracterului a in echivalentul sau double ceea ce este corect .

ex.gresit

#include<iostream.h>

float functie(float i);

double functie(double i);

void main()

{

cout<<functie(1500.1)<<endl; //apel corect double functie(double i) va afisa 1500.1

cout<<functie(1500)<<endl; //gresit

cout<<functie('a')<<endl; //gresit

}

float functie(float i){return i;}

double functie(double i){return i; }

explicatie:

Ambiguitatea este generata la apelul functie(1500) si functie(‘a’) deoarece compilatorul nu are de unde sa stie daca acestea trebuie sa le converteasca in float sau in double (nu stie care sa o aleaga dintre ele nefiind nici una de tip char sau int ) .

ex.corect

#include<iostream.h>

char functie(unsigned char ch);

char functie(char ch);

void main()

{

cout<<functie('c')<<endl; //apel corect char functie(char ch) va afisa c+1 adica pe d

}

char functie(char ch )

{

return ch+1;

}

char functie(unsigned char ch)

{

return ch-1;

}

ex.gresit

#include<iostream.h>

char functie(unsigned char ch);

char functie(char ch);

void main()

{

cout<<functie('c')<<endl; //apel corect char functie(char ch) ar afisa c+1 adica pe d

cout<<functie(97)<<endl; //gresit

}

char functie(char ch )

{

return ch+1;

}

char functie(unsigned char ch)

{

return ch-1;

}

explicatie:97 trebuie convertit in char sau unsigned char ?compilatorul nu se poate decide .

ex.corect

#include<iostream.h>

char functie(unsigned char ch);

char functie(char ch);

int functie(int i) {return i;}

void main()

{

cout<<functie('c')<<endl; //apel corect char functie(char ch) va afisa c+1 adica pe d

cout<<functie(97)<<endl; //va afisa 97

}

char functie(char ch )

{

return ch+1;

}

char functie(unsigned char ch)

{

return ch-1;

}

ex.gresit

#include<iostream.h>

int functie (int a);

int functie(int a,int b=99);

void main()

{

cout<<functie(10)<<endl; //creaza ambiguitate

cout<<functie(4,5)<<endl; //prg.ar afisa 20 fara linia de mai sus

}

int functie(int a){ return a;}

int functie(int a,int b){return a*b;}

explicatie: O alta cale prin care se creaza ambiguitati este folosirea de argumente implicite in functiile supraincarcate .Compilatorul nu stie daca sa apeleze versiunea pentru functie( ) care are un singur argument sau sa aplice parametrul implicit versiunii care preia doua argumente de forma functie(10,0) sau functie(0,10).

ex.gresit

#include<iostream.h>

void f(int x);

void f(int &x);

void main()

{

int a=10;

f(a); //eroare care f( )?deoarece ambele se apeleaza asa

}

void f(int x)

{

cout<<"functia f(int x)"<<x<<endl;

}

void f(int &x)

{

cout<<"functia f(int &x)"<<x<<endl;

}

explicatie :nu exista nici o diferenta intre felul in care este specificat un argument cand este primit prin referinta sau de unul de tip valoare de aceea apare ambiguitatea .

-functiile membre respecta aceleasi reguli de supraincarcare ca si functiile independente (prezentate mai sus);

-o functie care efectueza prelucrari diferite de la un context la altul poarta numele de functie polimorfica .

 


Proiect realizat de MARTON (POP) CLAUDIA an IV Ianuarie 2005