C ++ hat eine Funktion (ich kann den richtigen Namen nicht herausfinden), die automatisch übereinstimmende Konstruktoren von Parametertypen aufruft, wenn die Argumenttypen nicht die erwarteten sind.
Ein sehr einfaches Beispiel hierfür ist das Aufrufen einer Funktion, die a std::string
mit einem const char*
Argument erwartet . Der Compiler generiert automatisch Code, um den entsprechenden std::string
Konstruktor aufzurufen .
Ich frage mich, ist es so schlecht für die Lesbarkeit, wie ich denke?
Hier ist ein Beispiel:
class Texture {
public:
Texture(const std::string& imageFile);
};
class Renderer {
public:
void Draw(const Texture& texture);
};
Renderer renderer;
std::string path = "foo.png";
renderer.Draw(path);
Ist das in Ordnung? Oder geht es zu weit? Wenn ich es nicht tun sollte, kann ich Clang oder GCC irgendwie davor warnen lassen?
Antworten:
Dies wird als konvertierender Konstruktor (oder manchmal impliziter Konstruktor oder implizite Konvertierung) bezeichnet.
Mir ist kein Wechsel zur Kompilierungszeit bekannt, der warnt, wenn dies auftritt, aber es ist sehr einfach zu verhindern. Verwenden Sie einfach das
explicit
Schlüsselwort.Ob das Konvertieren von Konstruktoren eine gute Idee ist oder nicht: Es kommt darauf an.
Umstände, unter denen implizite Konvertierung Sinn macht:
std::string
spiegeln sie dasselbe Konzeptconst char *
wider, aus dem sie implizit konvertieren können), sodass eine implizite Konvertierung sinnvoll ist.Umstände, unter denen implizite Konvertierung weniger sinnvoll ist:
AnsiString
Klasse nicht implizit aus a konstruierenUnicodeString
, da bei der Konvertierung von Unicode in ANSI möglicherweise Informationen verloren gehen.Weiterführende Literatur:
quelle
Dies ist eher ein Kommentar als eine Antwort, aber zu groß, um einen Kommentar abzugeben.
Interessanterweise
g++
lässt mich das nicht tun:Produziert folgendes:
Wenn ich jedoch die Zeile ändere in:
Diese Konvertierung wird durchgeführt.
quelle
gcc
Compileroptionen zu testen (die anscheinend nicht für diesen speziellen Fall geeignet sind). Ich habe mich nicht weiter damit befasst (ich sollte arbeiten :-), aber angesichtsgcc
der Einhaltung des Standards und der Verwendung desexplicit
Schlüsselworts wurde eine Compileroption wahrscheinlich als unnötig erachtet.Texture
sollte wahrscheinlich nicht implizit erstellt werden (gemäß den Richtlinien in anderen Antworten), sodass eine bessere Call-Site wärerenderer.Draw(Texture("foo.png"));
(vorausgesetzt, sie funktioniert wie erwartet).Es heißt implizite Typkonvertierung. Im Allgemeinen ist es eine gute Sache, da es unnötige Wiederholungen verhindert. Beispielsweise erhalten Sie automatisch eine
std::string
Version von,Draw
ohne zusätzlichen Code dafür schreiben zu müssen. Es kann auch dabei helfen, dem Open-Closed-Prinzip zu folgen, da Sie damit dieRenderer
Funktionen erweitern können, ohne sichRenderer
selbst zu ändern .Auf der anderen Seite ist es nicht ohne Nachteile. Zum einen kann es schwierig sein, herauszufinden, woher ein Argument kommt. In anderen Fällen kann es manchmal zu unerwarteten Ergebnissen kommen. Dafür steht das
explicit
Schlüsselwort. Wenn Sie es auf denTexture
Konstruktor setzen, wird die Verwendung dieses Konstruktors für die implizite Typkonvertierung deaktiviert. Mir ist keine Methode bekannt, mit der bei impliziter Typkonvertierung global gewarnt werden kann. Dies bedeutet jedoch nicht, dass keine Methode vorhanden ist, sondern nur, dass gcc über eine unverständlich große Anzahl von Optionen verfügt.quelle