operator în C++

Funcții și lambda C++98 (operator<=>: C++20)

Definește ce face un operator (+, ==, <<, [], () etc.) pentru tipurile tale, ca obiectele să se folosească la fel de natural ca numerele.

Sintaxă
Tip operator+(const Tip& a, const Tip& b);
bool operator==(const Tip&) const = default;     // C++20
auto operator<=>(const Tip&) const = default;     // C++20
Rezultat operator()(Argumente...);               // obiect apelabil

Ce face operator

Supraîncărcarea operatorilor (operator overloading) îți permite să scrii a + b pentru două obiecte Bani, std::cout << produs sau matrice[2]. Pentru compilator, a + b devine un apel de funcție operator+(a, b), pe care tu îl definești.

Un operator poate fi metodă a clasei (primul operand este obiectul: a.operator+(b)) sau funcție liberă. Operatorii care primesc alt tip în stânga, ca std::ostream& operator<<(std::ostream&, const T&), trebuie să fie funcții libere.

Din C++20, operator== și operator<=> (comparația în trei sensuri, „nava spațială”) pot fi cerute cu = default: compilatorul generează toate cele șase comparații, membru cu membru. operator() face un obiect apelabil ca o funcție (un „functor”).

Exemple

Exemplul 1: Adunare și afișare pentru o clasă Bani

#include <iostream>

struct Bani {
    long bani;  // suma în bani (1 leu = 100 bani)

    Bani operator+(const Bani& alt) const { return {bani + alt.bani}; }
    Bani& operator+=(const Bani& alt) {
        bani += alt.bani;
        return *this;
    }
};

std::ostream& operator<<(std::ostream& out, const Bani& b) {
    return out << b.bani / 100 << "," << (b.bani % 100 < 10 ? "0" : "") << b.bani % 100 << " lei";
}

int main() {
    Bani paine{450};
    Bani lapte{719};
    Bani total = paine + lapte;
    std::cout << "Total: " << total << '\n';
    total += Bani{1205};
    std::cout << "Cu cafea: " << total << '\n';
}

Rezultat

Total: 11,69 lei
Cu cafea: 23,74 lei

Exemplul 2: Comparații generate cu = default (C++20)

Membrii sunt comparați în ordinea declarării: întâi major, apoi minor. O singură linie generează <, >, <=, >=, == și !=.

#include <compare>
#include <print>

struct Versiune {
    int major;
    int minor;
    auto operator<=>(const Versiune&) const = default;
};

int main() {
    Versiune a{2, 5}, b{2, 10}, c{2, 5};
    std::println("2.5 < 2.10: {}", a < b);
    std::println("2.5 == 2.5: {}", a == c);
    std::println("2.10 >= 2.5: {}", b >= a);
}

Rezultat

2.5 < 2.10: true
2.5 == 2.5: true
2.10 >= 2.5: true

Exemplul 3: operator[] și operator()

#include <print>
#include <string>

class Saptamana {
public:
    const std::string& operator[](int zi) const { return zile_[zi - 1]; }
private:
    std::string zile_[7] = {"luni", "marți", "miercuri", "joi", "vineri", "sâmbătă", "duminică"};
};

struct Reducere {
    double procent;
    double operator()(double pret) const { return pret * (1 - procent / 100); }
};

int main() {
    Saptamana s;
    std::println("Ziua 3: {}", s[3]);
    Reducere black_friday{40};
    std::println("1000 lei cu reducere: {} lei", black_friday(1000));
}

Rezultat

Ziua 3: miercuri
1000 lei cu reducere: 600 lei

Greșeli frecvente

  • Dai unui operator un sens surprinzător (de exemplu + care scade). Operatorii trebuie să facă ce se așteaptă oricine de la ei.
  • Returnezi prin valoare din operator+= sau operator<<. Convenția este să returnezi o referință (*this, respectiv fluxul), ca operațiile să se poată înlănțui.
  • Definești operator== dar nu și operator!= în cod mai vechi de C++20. Înainte de C++20, fiecare operator trebuia scris separat; din C++20, != este dedus din ==.

Comenzi înrudite

  • friend: Dă unei funcții sau altei clase acces la membrii privați și protejați ai clasei.
  • class: Definește un tip nou care grupează date (membri) și funcțiile care lucrează cu ele (metode); baza programării orientate pe obiecte.
  • lambda ([](){}): O funcție fără nume, scrisă direct acolo unde e folosită; poate „captura” variabile din jur.
  • explicit: Interzice folosirea unui constructor sau a unui operator de conversie pentru conversii automate, ascunse.