explicit



  • Hi,

    gibt es irgendeine Faustregel, wann man seinen Konstruktor explicit setzen sollte?
    Die Funktionsweise ist mir bekannt, allerdings ist mir nicht so ganz klar wann das von Nutzen ist.



  • Wenn du keine implizite Konvertierung willst. Das ist meistens der Fall -- du musst einen speziellen Grund haben, um implizite Konvertierung zu erlauben, nicht um sie zu verbieten.

    Es ist gar keine so schlechte Idee, explicit immer hinzuschreiben (ausser bei Kopierkonstruktoren). Erstens wird es dann zur Gewohnheit, die man nicht vergisst, und zweitens kann man auch refactoren, z.B. Parameter entfernen oder Default-Werte vergeben, ohne dass man ständig explicit hinzufügen/entfernen muss (und wieder vergisst).



  • Und früher (vor C++11) war es so, dass explicit für Konstruktoren, denen man beim Aufruf mehr als ein Parameter übergeben muss, überflüssig war. Heute ist explicit auch für Konstruktoren interessant, die mehrere Parameter entgegen nehmen. Die Frage, die man sich generell stellen muss, ist: Möchtest Du den Konstruktor über eine "Kopierinitialisierung" erreichen können?

    class foo {
      foo(int) {}
      foo(void*,void*) {}
    };
    
    class bar {
      explicit bar(int) {}
      explicit bar(void*,void*) {}
    };
    
    int main() {
      foo a(0);                  // direct    initialization: ok
      foo a(nullptr,nullptr);    // direct    initialization: ok
      foo b = 0;                 // copy      initialization: ok
      foo b = {nullptr,nullptr}; // copy list initialization: ok
    
      bar a(0);                  // direct    initialization: ok
      bar a(nullptr,nullptr);    // direct    initialization: ok
      bar b = 0;                 // copy      initialization: FEHLER!
      bar b = {nullptr,nullptr}; // copy list initialization: FEHLER!
    }
    

    Die "Kopierinitialisierung" ist auch die Art von Initialisierung, die für Funktionsparameter verwendet wird:

    void foo_func(foo f) {}
    void bar_func(bar b) {}
    
    int main() {
      foo_func(1);                 // klappt so
      foo_func({nullptr,nullptr]); // klappt so
    
      bar_func(1);                 // FEHLER
      bar_func({nullptr,nullptr}); // FEHLER
    }
    

    (ungetestet, Angaben ohne Gewähr)

    Meistens will man das mit den impliziten Konvertierungen nicht haben, weil das böse Überraschungen geben kann. Manchmal ist das aber ganz praktisch, z.B. wenn Du etwas nur von einer Form in eine andere konvertieren willst, was aber immer noch dieselbe Bedeutung hat. Zum Beispiel ist die implizite Konvertierung von double zu complex<double> in Ordnung, weil das Resultat immer noch denselben Wert repräsentiert. Im Gegensatz dazu, willst Du, dass folgendes nicht kompiliert:

    vector<string> v = 20;
    

    Um einen Vektor der Größe 20 zu erzeugen, musst Du die direkte Initialisierung verwenden:

    vector<string> v(20);
    


  • hab da oben zweimal public: vor den Konstruktordeklarationen vergessen.



  • was willst du damit sagen?

    Und früher (vor C++11) war es so, dass explicit für Konstruktoren, denen man beim Aufruf mehr als ein Parameter übergeben muss, überflüssig war.


Anmelden zum Antworten