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ändigexplicit
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
zucomplex<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.