explicit în C++

Clase și obiecte C++98 (operatori de conversie: C++11)

Interzice folosirea unui constructor sau a unui operator de conversie pentru conversii automate, ascunse.

Sintaxă
explicit Nume(int valoare);
explicit operator bool() const;

Ce face explicit

Un constructor cu un singur parametru este și o regulă de conversie: dacă Metri are constructorul Metri(double), atunci compilatorul transformă singur un double în Metri oriunde e nevoie, de exemplu la apelul f(5.0). Asta poate ascunde greșeli.

Cu explicit, conversia trebuie scrisă de tine: f(Metri{5.0}). Regula practică: pune explicit pe toți constructorii cu un singur argument, cu excepția celor pentru care conversia automată chiar are sens.

Același lucru pentru operatorii de conversie: explicit operator bool() permite if (obiect), dar nu și int x = obiect; sau obiect + 1.

Exemple

Exemplul 1: Constructor explicit

afiseaza_distanta(12.5) nu s-ar compila, pentru că nu mai există conversie automată din double. Trebuie scris tipul: Metri{12.5}.

#include <print>

class Metri {
public:
    explicit Metri(double valoare) : valoare_(valoare) {}
    double valoare() const { return valoare_; }
private:
    double valoare_;
};

void afiseaza_distanta(Metri m) {
    std::println("Distanța: {} m", m.valoare());
}

int main() {
    afiseaza_distanta(Metri{12.5});
    // afiseaza_distanta(12.5);  // eroare: constructorul este explicit
}

Rezultat

Distanța: 12.5 m

Exemplul 2: explicit operator bool

Obiectul poate fi folosit într-un if sau cu !, dar nu poate fi adunat sau atribuit unui int din greșeală.

#include <print>
#include <string>
#include <utility>

class Rezultat {
public:
    explicit Rezultat(std::string eroare = "") : eroare_(std::move(eroare)) {}
    explicit operator bool() const { return eroare_.empty(); }
    const std::string& eroare() const { return eroare_; }
private:
    std::string eroare_;
};

int main() {
    Rezultat ok;
    Rezultat esec("fișierul lipsește");
    if (ok) std::println("Prima operație a reușit");
    if (!esec) std::println("A doua a eșuat: {}", esec.eroare());
}

Rezultat

Prima operație a reușit
A doua a eșuat: fișierul lipsește

Greșeli frecvente

  • Lași fără explicit un constructor ca Vector(int marime). Atunci Vector v = 10; sau apelul f(10) creează în tăcere un vector cu 10 elemente.
  • Pui explicit pe constructorul de copiere. Copierea „obișnuită” nu mai merge: Tip b = a; și transmiterea prin valoare nu se mai compilează. Nu-l pune pe constructorii de copiere și mutare.

Comenzi înrudite

  • class: Definește un tip nou care grupează date (membri) și funcțiile care lucrează cu ele (metode); baza programării orientate pe obiecte.
  • operator: Definește ce face un operator (+, ==, <<, [], () etc.) pentru tipurile tale, ca obiectele să se folosească la fel de natural ca numerele.
  • static_cast, dynamic_cast, const_cast, reinterpret_cast: Cele patru conversii explicite: static_cast (obișnuite), dynamic_cast (clase), const_cast (const) și reinterpret_cast (biți).