0% found this document useful (0 votes)
26 views20 pages

C++ - Experimente ... : 2009/2010 - Suceava

The document discusses overloading operators in C++ classes. It explains that C++ allows operators to be redefined for user-defined data types to change the meaning of standard operators. Operators can be overloaded to have different behavior for class types than for fundamental data types. Overloaded operators are defined either as member functions or non-member global functions. The document provides an example of overloading the + operator for a Complex class type in three different ways to demonstrate the techniques.

Uploaded by

DanaMihaela
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
26 views20 pages

C++ - Experimente ... : 2009/2010 - Suceava

The document discusses overloading operators in C++ classes. It explains that C++ allows operators to be redefined for user-defined data types to change the meaning of standard operators. Operators can be overloaded to have different behavior for class types than for fundamental data types. Overloaded operators are defined either as member functions or non-member global functions. The document provides an example of overloading the + operator for a Complex class type in three different ways to demonstrate the techniques.

Uploaded by

DanaMihaela
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 20

C++ . Experimente ...

2009/2010 - Suceava

#include <iostream>
#include <math.h>
using namespace std;
class Test
{
public:
int x;
static int y;
//private:
Test( void )
{
cout<<"\nCONSTRUCTOR: [ "<<this<<" ]"<<endl; }
~Test( )
{
cout<<"\nDESTRUCTOR: [ "<<this<<" ]"<<endl; }
void Functie( void ) {}
};
int Test::y = 0;
int main()
{
cout << "-[ START ]------------------" << endl;
Test ob;
void (Test::*pf)( void );
cout<<"\nDimensiune clasa: "<< sizeof( Test )<<endl;
cout<<"\nAdresa obiect \'ob\': [ "<< &ob <<" ]"<<endl;
cout<<"\nDimensiune obiect: "<< sizeof( ob )<<endl;
cout<<"\n\t- Adresa \'ob.x\': "<< &ob.x <<endl;
cout<<"\n\t- Dimensiune \'ob.x\': "<< sizeof( ob.x )<<endl;
cout<<"\n\t- Adresa \'ob.y\': "<< &ob.y <<endl;
cout<<"\n\t- Dimensiune \'ob.y\': "<< sizeof( ob.y )<<endl;
ob.Functie();
cout<<"\nAdresa SIN(): [ "<< (void*)sin <<" ]"<<endl;
//cout<<"\nob.Functie: [ "<< ob.Functie <<" ]"<<endl;
cout << "-[ END ]--------------------" << endl;
return 0;
}

[ class :: objects :: methods ]

http://en.cppreference.com/w/cpp/language/types

2009/2010 - Suceava

C++ . Experimente ...

#include <iostream>
using namespace std;
class Test
{
public:
int x;
Test( ){cout<<"\nConstructor"<<endl;}
~Test( ){cout<<"\nDestructor"<<endl;}
};
int main (void)
{
Test b;
// apel ddestructor: este obligatoriu prefixul "Test::"
b.Test::~Test();
b.x = 2;
return 0;
}

[ class :: objects :: methods ]

2009/2010 - Suceava

C++ . Experimente ...

#include <iostream>
using namespace std;
class MyClass
{
char *sir;
public:
MyClass(char *_sir="zona statica"):sir(_sir)
{
std::cout << "ctor: [" << this<<"] "<<sir<<std::endl;
}
~MyClass()
{
std::cout << "dtor: [" << this<<"] "<<sir<<std::endl;
}
};

[ class :: objects :: methods ]

C++ . Experimente ...

2009/2010 - Suceava

int main(int argc, char *argv[])


{
std::cout << "\nZONA I - alocare statica OBIECTE"<< std::endl;
// Alocare statica a memoriei pt. un obiect
MyClass myObj;
// Alocare statica a memoriei pt. un sir
char s[100];
std::cout << "\nZONA II - afisarea adresa sir[]"<< std::endl;
// Afisarea adresei zonei de memorie a sirului
std::cout << "s[]: " << &s<< std::endl;
std::cout << "\nZONA III - alocare dinamica OBIECTE"<< std::endl;
//Alocare dinamica a memoriei pt. un obiect
MyClass *p1=new MyClass("zona dinamica");
//Alocare dinamica a memoriei pt. un obiect - in zona sirului
MyClass *p2=new (s) MyClass("zona s[]");
std::cout << "\nZONA IV- apel explicit a destructorilor"<< std::endl;
//Apelare explicita a destructorilor
myObj.MyClass::~MyClass();
p1->MyClass::~MyClass();
p2->MyClass::~MyClass();
std::cout << "\nZONA V - dealocare \
dinamica OBIECTE"<< std::endl;
//Dealocare pt. cei doi pointeri
delete p1;
delete p2;
}

[ class :: objects :: methods ]

C++ . POINTERI LA MEMBRII UNEI CLASE

2009/2010 - Suceava

Dei o funcie nu este o variabil, ea are o localizare n memorie, care


poate fi atribuit unui pointer.

Adresa funciei respective este punctul de intrare n funcie; ea


poate fi obinut utilizndu-se numele funciei, fr nici un
argument (similar cu obinerea adresei unei matrici).

Un pointer la metod desemneaz adresa unei funcii membru m.


Metodele unei clase au implicit un parametru de tip pointer la
obiect, care se transmite ascuns.

Observatie

Din acest motiv, parametrul n cauz nu apare in lista de parametri a


funciei desemnate de pointer.
Sintaxa general pentru declararea unui pointer la o data mebra este :
<tip> <nume_cl>::*<pointer_data_membra>;
i respectiv pentru obinerea adresei unei funcii membre :
<tip> (<nume_cl>::*<pointer_metoda>)(<lista_parametri>);

[ class :: objects :: methods ]

C++ . POINTERI LA MEMBRII UNEI CLASE

2009/2010 - Suceava

Sunt introdusi doi noi operatori in C++:


.* - acces prin pointer la un membru al clasei ( cazul unui obiect )
->* - acces prin pointer la un membru al clasei ( cazul unei adrese de obiect )

Sintaxa general pentru initializarea unui pointer la o data membra este :


<pointer_data_membra> = &<nume_cl>::<nume_membru>
i respectiv pentru initializarea unui pointer la o funcie membra :
<pointer_metoda> = &<nume_cl>::<nume_metoda>

Sintaxa general pentru accesul la datele membre este :


<obiect> .* <pointer_data_membra> = ...
<adresa_obiect> ->* < pointer_data_membra> = ...
i respectiv pentru accesul la o funcie membra :
(<obiect> .* <pointer_metoda>)( <parametri_reali> )
(<adresa_obiect> ->* <pointer_metoda>) ( <parametri_reali> )

[ class :: objects :: methods ]

2009/2010 - Suceava

C++ . POINTERI LA MEMBRII UNEI CLASE


#include <iostream>
#include <math.h>
using namespace std;
class Test
{
int contor;
public:
void init (int nr = 0)
{
contor = nr;
}
int increment (void)
{
return contor++;
}
};
/*
* tipul PM" este un pointer la o metoda a clasei Test,
* metoda care nu are parametri si care returneaza "int"
*/
typedef int (Test::*PM)(void);
int main(void)
{
cout << "-[ START ]------------------" << endl;
Test c1, *pc1 = &c1;
PM pM = &Test :: increment;
c1.init ( 1 );
pc1->init( 2 );
cout<<"\nApel (c1.*pM)(): "<< (c1.*pM)()<<endl;
cout<<"\nApel (pc1->*pM)(): "<< (pc1->*pM)()<<endl;
cout << "-[ END ]--------------------" << endl;
return 0;
}

[ class :: objects :: methods ]

2009/2010 - Suceava

C++ . POINTERI LA MEMBRII UNEI CLASE


#include <iostream>
#include <math.h>
using namespace std;
class Test
{
//. . .
public:
int x;
int functie(int a, int b)
{
cout<<"\nFunctie( "<<a<<", "<<b<<" )."<<endl;
};
//. . .
};
/* Declarare pointeri la membri
*/
int (Test::*pf)( int, int );
int Test::*px;

[ class :: objects :: methods ]

int main(void)
{
cout << "-[ START ]------------------" << endl;
//Declarare pointeri la membri
px = &Test :: x;
pf = &Test ::functie;
//Declarare obiecte
Test a, *pa; pa = &a; //pa=adresa lui a
//Acces la membri prin pointeri la membri
a.*px = 3;
pa->*px = 2;
(a.*pf)( 2, 2 );
(pa->*pf)( -1, -1 );
cout << "-[ END ]--------------------" << endl;
return 0;
}

C++ . SUPRAINCARCAREA OPERATORILOR

2009/2010 - Suceava

Limbajul C++ ne permite ca pentru tipurile abstracte de date (create de


ctre utilizator ) s schimbm semnificaia operatorilor standard cunoscui
astfel nct aceti operatori suprancrcai n cadrul clasei noastre s aib
alt comportament dect cel cunoscut pentru tipurile fundamentale de
date.
Astfel avem posibilitatea s suprancrcm toi operatorii limbajului C++
cunoscui mai puin operatorii: . ; . * ; :: ; ?: .
Observaii
1. operatorii urmatori nu pot fi supradefinii:

2.
3.
4.
5.

.*
::
?:

Nu putem prin supradefinire s schimbm pluraritatea operatorilor adic


un operator unar s devin binar i viceversa;
Nu poate fi schimbat prioritatea i asociativitatea operatorilor prin
supraincarcare;
In cazul redefinirii urmtorilor operatori : [ ], new, delete, funciile
asociate nu pot fi funcii membre statice;
Un operator poate fi redefinit de mai multe ori n cadrul unei clase dar
atunci cnd primul operand al su nu este un obiect aparinnd clasei
atunci redefinirea nu se poate face dect utiliznd funcii prietene.

[ class :: objects :: methods ]

C++ . SUPRAINCARCAREA OPERATORILOR

2009/2010 - Suceava

TEHNICI DE REDEFINIRE A OPERATORILOR


Avem posibilitatea s redefinim operatorii folosind funcii membre ale clasei
sau funcii globale prietene clasei.
n cazul n care am redefinit un operator folosind funcii membre atunci
primul su operand este chiar obiectul curent ce apare de obicei n stnga
operatorului (atunci cnd sunt doi) i a apelat funcia operator.
- n acest caz cellalt operand este transmis ca argument.
Atunci cnd redefinim operatorul folosind funcii prietene globale toi
operanzii asociai operatorului vor fi transmii ca argumente, ca parametrii
funciei operator.
Redefinirea funciei operator este tratat de C++ ca o funcie membr, sau
prieten oarecare, doar dac numele ei este o combinaie ntre cuvntul
operator i simbolul asociat operatorului.
Pentrru exemplificarea acestei noiuni vom da exemplul clasei Complex n
care vom redefini operatorul + de trei ori utiliznd cele dou modaliti
posibile.

[ class :: objects :: methods ]

2009/2010 - Suceava

C++ . SUPRAINCARCAREA OPERATORILOR

#include <iostream>
using namespace std;
class Complex
{
float re, im;
char name[20];
public:
Complex( char *_name = "_DEFAULT_", float _r = 0,
float _i = 0 ) : re(_r), im(_i)
{
strcpy( name, _name );
}
Complex operator +( Complex &b );
Complex operator +( float b );
void Print( void )
{
cout.width(10);
cout<<name<<": "<<re<<(im<0 ? " -i ":" +i ");
cout<<fabs( im )<<endl;
};
friend Complex operator +( float a, Complex &b );
};

[ class :: objects :: methods ]

C++ . SUPRAINCARCAREA OPERATORILOR

2009/2010 - Suceava

Complex Complex :: operator +( Complex &b )


{
Complex r( "Rez", re + b.re, im + b.im );
return r;
}
Complex Complex :: operator +( float b )
{
Complex r("Rez", re + b,im);
return r;
}
Complex operator +( float a, Complex &b)
{
Complex r( "Rez", a + b.re, b.im );
return r;
}

[ class :: objects :: methods ]

C++ . SUPRAINCARCAREA OPERATORILOR

2009/2010 - Suceava

int main( void )


{
Complex a, b("B", 1, 1), c("C");
a.Print(); b.Print(); c.Print();
c = a + b;
// c=a.operator+(b);
c.Print();
c = c + 3;
// c=c.operator+(3);
c.Print();
c = a + b + c; // c=a.operator+(b.operator+(c));
c.Print();
c = 3 + a;
// c=operator+(3,a); Atribuire
c.Print();
return 0;
}

[ class :: objects :: methods ]

2009/2010 - Suceava

C++ . SUPRAINCARCAREA OPERATORILOR

Sintaxa de supradefinire a operatorilor binari:


A. Prin functii membre
operator <simbol> ( <tip> <parametru2> );
B.

Prin functii prietene


operator <simbol> ( <tip> <parametru1>, <tip> <parametru2> );

Exemplu
class Test
{
void operator *( float y );
friend void operator /( float y, Test &x );
};
void Test::operator *( float y )
{
}
void operator /( float y , Test &x )
{
}

[ class :: objects :: methods ]

C++ . SUPRAINCARCAREA OPERATORILOR

2009/2010 - Suceava

Apelul functiilor operator supradefinite:


A. Prin functii membre
Test ob1;
ob1 * 3;
// ob1.operator*( 3 );
B.

Prin functii prietene


Test ob2;
2 / ob2;
// operator / ( 2, ob2 );

Concluzie

Atunci cand primul operand nu este de tipul clasei ( 2 / ob2 ) suntem nevoiti sa
supradefinim operatorul doar prin functie PRIETENA friend

Atunci cand primul operand este de tipul clasei ( ob1 * 3 ) putem adopta mabele
metode

In privinta tipului returnat nu avem restrictii. Suntem obligati sa returnam o valoare


doar atunci cand folosim operatorul supradefinit in expresii de tipul:

Test ob;
ob2 = ob1 * 3;
( EXPLICATI )

[ class :: objects :: methods ]

C++ . SUPRAINCARCAREA OPERATORILOR

2009/2010 - Suceava
OPERATORII DE ASIGNARE
Operatori utilizai :

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

Atunci cnd dorim ca printr-o atribuire ntre dou obiecte s realizam un tratament special
asupra datelor membre i nu numai o copiere bit cu bit, suntem nevoii s redefinim acei
operatori de atribuire utilizai de obiectul clasei respective.
Dac o clas nu are redefinit nici un operator de atribuire, compilatorul i va genera unul,
implicit ce va realiza o copiere bit cu bit.

Ca i n cazul constructorului de copiere printr-o copiere bit cubit a datelor de tip pointer
are loc o partajare a celeiai zone de memorie indicat de pointerul membru ntre cele
dou obiecte (pentru c a fost copiat adresa i nu a fost multiplicat zona).

Primul obiect care dispare va dealoca zona de memorie comun i (celorlalte) celuilalt
obiect.

Soluia const n redefinirea operatorului de atribuire i n interiorul su s realizm


operatorii de copiere a zonei de memorie surs ntr-o alt zon nou alocat.
Operatorul de atribuire poate fi redefinit i pentru alte tipuri de date, ca operand secund (ca
cel de-al doilea operand) . Astfel putem avea atribuiri nu numai ntre dou obiecte ci i ntre
un obiect i o alt dat.
Atunci cnd dorim s realizm operaii nlnuite cu un anumit operator de asignare suntem
nevoii s returnm ca tip de dat din funcia operator o referin sau chiar un obiect
aparinnd clasei n discuie.

Atunci cnd rezultatul operatorului este calculat ntr-o variabil local lui vom returna un
obiect iar cnd rezultatul este chiar obiectul curent putem returna o referin.

[ class :: objects :: methods ]

2009/2010 - Suceava

C++ . SUPRAINCARCAREA OPERATORILOR

OPERATORII DE ASIGNARE

Sintaxa de redefinire :
<tip_ret>operator= ( <tip_arg> <arg> );
Observatie
n loc de = putem utiliza unul din simbolurile + =, - = , * = , % =, ... . Acestea sunt
tratate ca fiind un singur operator i nu combinaii de simboluri.
Atunci cnd avem atribuiri de forma : a=b=c; i cnd funcia operator este funcie
membr, scrierea expandat va fi de forma :
a.operator=( b.operator= ( c ) );
Atunci cnd funcia operator este funcie prieten scrierea expandat este de forma :
operator=( a, operator= ( b,c ) );
Operatorii care se execut de obicei n cadrul funciei operator = pot fi sintetizai n
forma urmtoare:

[ class :: objects :: methods ]

C++ . SUPRAINCARCAREA OPERATORILOR

2009/2010 - Suceava

#include <iostream>
using namespace std;
class Test
{
char *p;
int x;
public :
Test& operator= (Test &b );
};
Test& Test :: operator= ( Test& b )
{
if( this == &b )//autocopiere pt. a=a
// in cazul *this= =b comparam doua
// obiecte iar daca, clasa respectiv
// nu are redefinit operatorul
// == se returneaza eroare
return *this;
// se dealoca vechea zona de memorie
// se calculeaza dimensiunea pentru zona de alocat
// se aloc memorie pentru p
// se copie informatia din b.p n p
// se face x= b.x
return *this;
};

[ class :: objects :: methods ]

2009/2010 - Suceava

C++ . SUPRAINCARCAREA OPERATORILOR

Vom da un exemplu n care vom redefini din nou ecelai operator i vom utiliza funcia
prieten.

#include <iostream>
using namespace std;
class Test
{
char *p;
int
x;
public:
//Test& operator= (Test& b);
friend Test& operator=( Test& a, char *s );
};
Test& operator=( Test& a, char *s )
{
//nu este necesar testul deoarece avem obiecte diferite
if( a.p )
delete a.p;
a.p = new char[ strlen(s) + 1 ];
strcpy( a.p, s );
a.x = atoi( s ); // x=0;
return a; // nu am facut *this deoarece nu este o membra
}

[ class :: objects :: methods ]

2009/2010 - Suceava

C++ . SUPRAINCARCAREA OPERATORILOR

OPERATORUL de INDEXARE []
Acest operator poate fi utilizat n asocier cu un obiect, realiznd anumite operaii
specifice asupra datelor membre, de exemplu returnnd valoarea unui element de pe
o anumit poziie.
Nu sunt restricii la tipul de dat returnat i nici la tipul de dat primit ca argument.
#include <iostream>
using namespace std;
class Test
{
public:
char s[20], _err;
char& operator []( int i );
};
char& Test :: operator [] (int i)
{
return i >=0 && i<20 ? s[i] : _err ;
// returneaza un anumit element de pe o
// anumit poziie cu verificarea poziiei i a indexului
}
int main( void )
{
Test ob;
ob[ 0 ] = 'P'; ob[ 1 ] = 'O'; ob[ 2 ] = 'O'; ob[ 3 ] = '\0';
cout<< "Continutul: "<< ob.s <<endl;
return 0;
}

[ class :: objects :: methods ]

You might also like