Wenn Sie einen C ++ - Programmierer nach der Bedeutung des expliziten Schlüsselworts fragen, antworten die meisten, dass dieses Schlüsselwort vor der Konstruktordeklaration mit einem Parameter (oder mit einer großen Anzahl von Parametern, aber wenn alle Parameter ab dem zweiten Parameter Standardwerte haben) steht und eine implizite Konvertierung verhindert Typen bei der Initialisierung.
class Simple { public: Simple(int a) : a_(a) {} private: int a_; }; class SimpleExplicit { public: explicit SimpleExplicit(int a) : a_(a) {} private: int a_; }; template <typename S> void someFunc(const S& s) { } int main(int, char**) { Simple s3 = 11; // SimpleExplicit se3 = 11; - COMPILE ERROR SimpleExplicit se3 = SimpleExplicit(11); someFunc<Simple>(11); // someFunc<SimpleExplicit>(11); - COMPILE ERROR someFunc<SimpleExplicit>(SimpleExplicit(11)); return 0; }
Im guten alten C ++ 03 endeten die Keyword-Anwendungsszenarien dort, beginnend mit C ++ 11 wurde der Umfang der expliziten Erweiterung jedoch erweitert: Jetzt ist dies nicht nur in Konstruktoren mit einem Parameter sinnvoll, sondern auch nicht nur in Konstruktoren.
Im Jahr 2011 fügte der Standard eine einheitliche Initialisierung hinzu, die die Methoden des Zoos zur Initialisierung von Objekten, die von C ++ geerbt wurden, bereinigen sollte. Ich werde hier nicht im Detail auf die universelle Initialisierung eingehen, es gibt viele detaillierte Artikel zu diesem Thema leicht zu finden durch Stichwörter. Kurz gesagt: Es wird vorgeschlagen, Objekte mit geschweiften Klammern zu initialisieren. Tatsächlich handelt es sich bei dieser Erweiterung um die sogenannte Erweiterung Aggregatinitialisierung von C. geerbt.
Mit dem Aufkommen der universellen Initialisierung machte dies für Designer mit 0.2.3 oder mehr Parametern explizit Sinn:
class Simple { public: Simple() : a_(0), b_(0) {} Simple(int a) : a_(a), b_(0) {} Simple(int a, int b) : a_(a), b_(b) {} private: int a_, b_; }; class SimpleExplicit { public: explicit SimpleExplicit() : a_(0), b_(0) {} explicit SimpleExplicit(int a) : a_(a), b_(0) {} explicit SimpleExplicit(int a, int b) : a_(a), b_(b) {} private: int a_, b_; }; template <typename S> void someFunc(const S& s) { } int main(int, char**) { Simple s4 = {}; someFunc<Simple>({}); // SimpleExplicit se4 = {}; - COMPILE ERROR SimpleExplicit se4 = SimpleExplicit{}; // someFunc<SimpleExplicit>({}); - COMPILE ERROR someFunc<SimpleExplicit>(SimpleExplicit{}); Simple s5 = {11}; someFunc<Simple>({11}); // SimpleExplicit se5 = {11}; - COMPILE ERROR SimpleExplicit se5 = SimpleExplicit{11}; // someFunc<SimpleExplicit>({11}); - COMPILE ERROR someFunc<SimpleExplicit>(SimpleExplicit{11}); Simple s6 = {11, 22}; someFunc<Simple>({11, 22}); // SimpleExplicit se6 = {11, 22}; - COMPILE ERROR SimpleExplicit se6 = SimpleExplicit{11, 22}; // someFunc<SimpleExplicit>({11, 22}); - COMPILE ERROR someFunc<SimpleExplicit>(SimpleExplicit{11, 22}); return 0; }
Ab C ++ 11 kann das explizite Schlüsselwort außerdem auf Typkonvertierungsoperatoren angewendet werden, wodurch auch deren impliziter Aufruf verhindert wird:
class Simple { public: Simple() {} operator bool() const { return true; } }; class SimpleExplicit { public: explicit SimpleExplicit() {} explicit operator bool() const { return true; } }; int main(int, char**) { Simple s7{}; bool b7 = s7; SimpleExplicit se7{}; // bool be7 = se7; - COMPILE ERROR bool be7 = static_cast<bool>(se7); return 0; }
Abschließend möchte ich empfehlen, die universelle Initialisierung in jedem neuen C ++ - Code zu verwenden und explizite Konstruktoren immer explizit zu deklarieren, es sei denn, die implizite Konvertierung ist semantisch gerechtfertigt.