Frage - Klasseninitialisierung
-
asc schrieb:
...Explizit bei einem Konstruktor heißt, das dieser keine impliziten Umwandlung vornehmen darf. Sprich wenn du einer Klasse nur einem expliziten Konstruktor mit einem int-Wert als Parameter gibst, kannst du diese nicht mit einem short-Wert konstruieren.
Explizite Konstruktoren sind in der Regel den impliziten vorzusehen wenn es um Typsicherheit geht......
Warum geht das hier dann?
#include <iostream> using namespace std; class Foo { public: explicit Foo(int a1_); ~Foo(); private: int m_a1; }; Foo::Foo(int a1_) :m_a1(a1_) { } Foo::~Foo() { } int main() { short x=13; Foo test=Foo(x); return 0; }MfG
Stromberg
-
Weil asc dort etwas falsches geschrieben hat - 'explicit' verhindert nicht die internen Typumwandlungen von C++, es verhindert nur die implizite Umwandlung von int nach foo (in deinem Beispiel), d.h. die Verwendung
foo x=10;oder die Verwendung eines int-Wertes für einen foo.@asc: Und es gibt zwar mitunter mehrere implizite Umwandlungen hintereinander, aber davon maximal eine benutzerdefinierte (Konstruktor oder Umwandlungsoperator).
-
Die explizite Typumwandlung verhindert (so wie CStoll schon schrieb) die automatische Typumwandlung bei benutzerdefineirten Typen.
Sie kommt erst dann wirklich zur Geltung, wenn mehrere Klassen im Spiel sind, z.B.class Foo { explicit Foo(int a); }; class Bar { public: Bar(const Foo &foo); }; int main() { Bar b = 42; // dies führt jetzt zu einem Fehler! }Ohne die Angabe von 'explicit' bei Foo würde die obere Anweisung vom Compiler als
Bar b = Bar(Foo(42)); // bzw. dies ist gleichwertig mit: Bar b(Foo(42))interpretiert.
P.S: Stroustrup gibt in seinem Buch auch noch als Beispiel:
// selbsterstellte Klasse class String { explicit String(int n); // Vorbelegung von n Zeichen }; String s(10); // Initialisierung mit 10 Zeichen String s('a'); // <- Fehler, ohne explicit würden 65 Zeichen vorbelegtEine sogenannte Promotion ist dagegen immer möglich, also von short<->int<->long.
-
Interessanterweise sollte das der Compiler auch ohne explicit abweisen - es ist maximal eine nutzerdefinierte implizite Umwandlung am Stück erlaubt. (Edit: Und so einen Ansatz habe ich schon als Workaround gesehen für Compiler, die nichts mit explicit anfangen können)
Hier mal ein Beispiel, wo es wirklich einen Unterschied macht:
class test { public: explicit test(int); private: ... }; void print(const test& value); ... print(4711); //verboten - Umwandlung ist explizit print(test(4711));//erlaubt ... //und hier der kleine, aber feine Unterschied: test i = 100; //verboten test i(100); //erlaubt
-
Das hier funktioniert bei mir nicht, mit "explicit" oder ohne "explicit":
#include <iostream> using namespace std; class Foo { public: explicit Foo(int a); private: int m_x; }; Foo::Foo(int a) :m_x(a) { } class Bar { public: Bar(const Foo &foo); private: Foo m_y; }; Bar::Bar(const Foo &foo) :m_y(foo) { } int main() { Bar b = 42; // dies führt jetzt zu einem Fehler! }Außerdem wäre für den Compiler "Bar b = 42" u. "Bar b = Foo(42)" immer --> Bar b = Bar(Foo(42));???
Und was ist jetzt eigentlich nochmal die Poente von "explicit"? Was soll damit verhindert bzw. bezweckt werden? Wo liegt der Sinn?
MfG
Stromberg
-
Stromberg schrieb:
Und was ist jetzt eigentlich nochmal die Poente von "explicit"? Was soll damit verhindert bzw. bezweckt werden? Wo liegt der Sinn?
class a_explicit { public: a_explicit() {} explicit a_explicit(int a){} }; class a_implicit { public: a_implicit() {} a_implicit(int a){} }; void foo_e(a_explicit const& ae) { } void foo_i(a_implicit const& ai) { } void bar() { foo_e(1); // geht nicht foo_i(1); // geht schon a_explicit ae; a_implicit ai; ae = 1; // geht nicht ai = 1; // geht schon }Der Sinn ist also implizite Konvertierungen zu "verbieten" wo sie sonst erlaubt wären. Und das ist meistens das was man möchte. -> einfach immer "explicit" vor jeden Ctor schreiben, ausser man möchte ganz bewusst implizite Konvertierungen erlauben (wie z.B. std::string::string(const char*) damit man String-Literale verwenden kann wo ein std::string erwartet wird).
-
Muss ich eigentlich eine implizite Initialisierung als "copy initialization" ansehen, oder kann ich das auch als "direct initialization" ansehen, weil eigentlich ist es doch so, das "(...)" == "=..." ist oder?
int a=10;
int a(10);
???
Also:class A; //Konstruktor implizit int main() { A=12; //Passiert da dann dass hier --> A=A(12) --> Kopierkonstruktor //oder dass hier --> A(12) --> normaler Konstruktor return 0; }Oder kann man das nicht so genau sagen, da es immer irgendwie als Konstruktor weg optimiert wird? Oder wie läuft das nochmal ab?
MfG
Stromberg
-
Soweit ich weiß benutzt der Compiler da immer den normalen Konstruktor, außer auf der rechten Seite ist auch ein Objekt vom Typ A, dann natürlich den Copy-Konstruktor
-
Initialisierung mit "A a = 12;" ist copy initialization, wobei aber der copy-ctor "elided" (weggelassen) werden darf.
Ist also AFAIK äquivalent zu "A a = A(12);" bzw. "A a(A(12));".
-
Wie man sich täuschen kann
