Un operator supraincarcat este o functie a carui nume este operatorul respectiv, precedat de cuvantul cheie operator.
Exemplul 1:

class Book{
	long ISBN;
	public:
	long get() const{ return ISBN; }
};
bool operator < (const Book& b1, const Book& b2){
	return b1.get() < b2.get();
}
Operatorii pot fi incarcati cu functii membru ale clasei sau cu functii ne-membru. Rob Murray recomanda in C++ Strategies & Tactics (1993, Addison-Wesley):
toti operatorii unari recomandabil cu functii membru
= () [] -> ->* obligatoriu cu functii membru nestatice(ceea ce asigura ca primul operand este lvalue)
+= -= /= *= ^= &= |= %= >>= <<= recomandabil cu functii membru
ceilalti operatori binari recomandabil cu functii ne-membru
Se recomanda pastrarea caracteristicilor de interfata ale operatorilor. Operatorul ++ poate fi supraincarcat sa "decrementeze" un obiect, rezultand insa un cod criptic, neinteligibil.

Observatii:
  1. Supraincarcarea operatorilor se mosteneste.
  2. Deoarece este foarte utilizat, compilatorul creeaza, in mod automat, pentru fiecare clasa, o functie care supraincarca operatorul de atribuire. Un astfel de operator simuleaza constructorul de copiere (si el creat in mod automat pentru fiecare clasa!)
    Daca clasa contine obiecte sau este mostenita, se apeleaza recursiv =.
    Generandu-se in mod automat pentru fiecare clasa, operatorul = al clasei de baza este ascuns in clasa derivata!
  3. Un operator supraincarcat trebuie sa ia cel putin un argument de un tip definit de utilizator (nu se poate altera intelesul expresiilor ce contin doar tipuri fundamentale!)
  4. Nu se pot introduce operatori noi in limbaj!
  5. Nu pot fi supraincarcati operatorii: . .* :: sizeof ?:: # ## static_cast<> dynamic_cast<> const_cast<> reinterpret_cast<>
  6. Nu se pot modifica nici precedenta, nici numarul de operanzi ai nu unui operator.
  7. Daca nu este necesara modificarea argumentelor, se recomanda utilizarea referintelor const.
  8. Operatorii de atribuire modifica operandul stang (care trebuie sa fie lvalue) si sunt permise constructii de genul a=b=c. O astfel de constructie este parsata de la dreapta la stanga si, in principiu, s-ar putea returna referinte const. Insa este legala si o constructie de tip (a=b).func(), ceea ce face necesara returnarea unei referinte ne-const!
  9. Conversiile standard de tip au precedenta fata de conversiile utilizator!
    
    class Numeric{
    	float f;
    	public:
    	Numeric(float ff): f(ff){} //constructorul se comporta ca un operator de conversie din float in Numeric
    };
    void f(Numeric);
    void f(double);
    f(5.0f);	// f(double) sau f(Numeric) ???
    
    Prin conversie standard, float este promovat la double si se apeleaza a doua versiune a functiei f! Daca aceasta ar lipsi, se construieste un obiect de tip Numeric si se apeleaza prima versiune a functiei!
  10. Pentru tipurile predefinite se face distinctie intre pre si post incrementare. Operatorii postfixati se declara cu un argument de tip int, neutilizat; astfel:
    ++a apeleaza operator++(a)
    a++ apeleaza operator++(a, int)
    Exemplu:
    
    class Date{
        public:
        Date& operator++();
        Date& operator--();
        const Date operator++(int);
        const Date operator--(int);
    }
    Date d, d1;
    d1 = ++d; 
    d1 = d++;
    d++++; 		//eroare la compilare
    
TIPRETURN VALUE OPTIMIZATION

Atunci cand o functie returneaza obiecte prin valoare, varianta clasica:
    Number tmp(left.i + right.i); 	//constructor tmp
    return tmp;			  	//constructor de copie si destructor tmp
poate fi imbunatatita cu:
    return Number(left.i + right.i);	//se creeaza obiectul direct in locatia rezervata
Operatorii NEW si DELETE


new nume_tip //returneaza nume_tip*
New se poate utiliza si pentru a initializa: int* p = new int(10);
New se poate utiliza si pentru a aloca tablouri: int* p = new int[10]; //nu se pot face initializari!
//varianta globala

void* operator new (size_t dimensiune){/**/}
//varianta specifica unei clase; functie membru statica

void* nume_clasa::operator new (size_t dimensiune){/**/}
La aplicare nu se indica nici o valoare parametrului formal dimensiune deoarece compilatorul calculeaza, automat, dimensiunea obiectului si ii atribuie aceasta valoare. Varianta globala se poate apela cu ::new nume_clasa din interiorul noii definitii a lui new.

void operator delete (void* p);
void nume_clasa::operator delete (void* p);
Opetatorii new si delete supraincarcati de utilizator nu se folosesc la alocarea/dealocarea tablourilor de obiecte!

Operatorul de atribuire =


nume_clasa& nume_clasa::operator = (const nume_clasa& operand);
Deoarece o instructiune obiect1 = obiect1 nu trebuie sa aiba, in mod logic, efect, implementarea trebuie sa contina:

if (this != &operand){...} else return (*this);
Operatorul de indexare []

tip& nume_clasa::operator [] (tip_indice i){/**/};
Trebuie sa existe doua versiuni, una const (pentru obiectele constante) si una ne-const.