Ich meine, es geht mehr darum, Wörter auszuwählen, als dass es einen Unterschied zwischen Funktion und Konstruktoraufruf gibt. Das Objekt mit dem Namen "Konstruktor eines Objekts" kann auch als "Funktion mit vom object
Typ zurückgegebenem Typ object
" bezeichnet werden.
Man könnte argumentieren, dass C ++ nicht zulässt, dass man dieselbe Funktion und denselben Typnamen hat; Es gibt jedoch eine Problemumgehung, um dies zu tun. C ++ verfügt über einen speziellen syntaktischen Zucker (der als Konstruktor bezeichnet wird), mit dem Sie eine Funktion mit dem Namen " object
return return type" erstellen können object
. Ich denke, ein Konstruktor kann als freistehende Funktion gesehen und verwendet werden.
Gibt es einige wichtige semantische Unterschiede, die mir hier fehlen?
quelle
Antworten:
Ein Konstruktor ist im Grunde eine Methode, ja, aber es ist eine spezielle Methode.
In C ++ ist ein Konstruktor beispielsweise nicht einfach eine Funktion, die eine neue Instanz dieses Typs zurückgibt. Wenn es so wäre, würde die Vererbung nicht funktionieren. Sie konnten die Basiskonstruktoren nicht aufrufen, da sie auch eine neue Instanz zurückgeben würden. Am Ende erhalten Sie eine neue Instanz von A, die dann an den Konstruktor von B zurückgegeben wird, wodurch eine neue Instanz von B erstellt wird, die dann an den Konstruktor von C usw. zurückgegeben wird.
Stattdessen ist ein Konstruktor eher eine Initialisierungsmethode, die vom Instanzzuweiser automatisch aufgerufen wird. Wenn Sie beispielsweise "new" aufrufen, um ein Objekt auf dem Heap zu erstellen, weist es den Speicher für den von Ihnen angeforderten Typ zu (unter Verwendung eines Speicherzuweisers wie malloc) und ruft dann die Konstruktormethode auf. Der Compiler hat spezielle Regeln dafür, wie und in welcher Reihenfolge dieser Konstruktor die anderen Konstruktoren aufrufen kann. Wenn Sie beispielsweise in C # einen Basiskonstruktor nicht explizit aufrufen, fügt der Compiler dem Standardstandardkonstruktor einen Aufruf hinzu.
Es sind diese Regeln darüber, wie der Compiler mit Konstruktoren umgeht, die ihn von "einer Funktion namens .ctor, die eine Instanz des Typs zurückgibt" unterscheiden.
quelle
new
zum Erstellen von Objekten in C ++ verwendet, da es automatische Variablen enthält.Nein, ein Konstruktor von unterscheidet
object
sich stark von einer Funktion, die aufgerufen wirdobject
und zurückkehrtobject
. Ein Konstruktor hat keinen Namen, aber das ist größtenteils eine technische Angelegenheit. Die wichtigeren Unterschiede sind, dass ein Konstruktor keinen Rückgabetyp hat und nicht direkt aufgerufen werden kann.Ein Konstruktor gibt nichts zurück, da er einen Speicherblock erhält und diesen Speicher direkt bearbeitet. Es kann hilfreich sein, wenn Sie den Namen "Konstruktor" für einen Moment vergessen und ihn stattdessen als Initialisierer betrachten . Der Zweck des Konstruktors besteht nicht darin, ein Objekt "aus der Luft" zu konstruieren. Ihr Zweck ist es, ein Objekt genau dort zu initialisieren, wo es sein muss.
Wenn ein Konstruktor ein Objekt zurückgeben würde, müsste dieses zurückgegebene Objekt (der Rückgabewert) irgendwo (wahrscheinlich auf dem Stapel) leben, und dort müsste es irgendwie initialisiert werden - wir stoßen hier auf eine Schleife.
Dies geht einher mit der Tatsache, dass ein Konstruktor niemals direkt aufgerufen werden kann. Wenn Sie eine Klasse haben
object
undobject()
irgendwo einen Ausdruck verwenden , hat dieser nicht die Semantik "Aufruf des Konstruktors vonobject
". Es hat die Semantik "ein temporäres Objekt vom Typ erstellenobject
". Der Compiler übersetzt dies in die Zuweisung eines Ortes, an dem das temporäre Objekt leben soll (wahrscheinlich / häufig auf dem Stapel), und den Aufruf des Konstruktors, ein Objekt an diesem Ort zu konstruieren (= zu initialisieren).Das gleiche Prinzip gilt bei der Verwendung
new object()
. Dies ist ein neuer Ausdruck, der zwei Dinge tut:operator new
(die a zurückgibtvoid*
) auf, um dem Objekt Rohspeicher zuzuweisen.Stellen Sie sich einen Konstruktor
object
als eine Funktion wie diese vor:ist falsch. Wenn überhaupt, ist die Arbeitsweise eines Konstruktors näher daran:
Mit der Ausnahme, dass Sie es nie direkt aufrufen können. Es wird immer nur aufgerufen, wenn es von einem anderen Sprachkonstrukt angegeben wird. Selbst eine neue Platzierung (auch als Trick "Konstruktor hier aufrufen" bezeichnet)
new (&place_for_object) object()
ruft den Konstruktor nicht direkt auf. Es wird in einen Aufruf der platzierungsneuen Form übersetztoperator new
, deren Argument zurückgegeben wird, gefolgt von einem Aufruf des Konstruktors (genau wie bei jedem anderen neuen Ausdruck).quelle
Ihr Umformulierungsversuch ist falsch.
Obwohl ein Konstruktor wie eine Mitgliedsfunktion mit einem Namen aussieht, der mit dem Namen der Klasse identisch ist, hat ein Konstruktor tatsächlich überhaupt keinen Namen. Dies wird im C ++ - Standard (Abschnitt [class.ctor] / 1) ausdrücklich angegeben:
Soweit: "Ich denke, ein Konstruktor kann als freistehende Funktion gesehen und verwendet werden" geht ... Nun, ich bin mir nicht ganz sicher, was Sie meinen. Eine freie Funktion kann sicherlich kein Konstruktor sein - ein Konstruktor muss Mitglied einer Klasse sein. Gleichzeitig können Sie sicher eine freie Funktion definieren, die ein Objekt erstellt und eine Instanz dieses Objekts zurückgibt. Diese freie Funktion kann sogar (irgendwie) den gleichen Namen haben wie der Objekttyp, den sie erstellt, wenn Sie es schlecht genug wollen. Sie können beispielsweise die Klasse innerhalb eines Namespace definieren und dann eine Funktion außerhalb des Namespace definieren:
Dies ist nicht wirklich der gleiche Name (die Funktion ist gerecht
bar
und die Klasse istfoo::bar
), aber abhängig von Ihrem Standpunkt könnten Sie sie trotzdem so betrachten.Eine solche freie Funktion hätte jedoch nicht die anderen Schlüsselmerkmale eines Konstruktors. Der Aufruf eines Konstruktors kann vollständig implizit sein. Zum Beispiel, wenn ich eine Klasse habe wie:
... dann Code wie:
... kann ein temporäres foo-Objekt aus dem erstellen,
1
damit es dieses foo-Objekt an übergeben kannfoo::operator+
. Dies ist bei einer freien Funktion einfach nicht der Fall, selbst wenn diese freie Funktion so definiert wurde, dass sie den richtigen Parametertyp verwendet und den erforderlichen Ergebnistyp zurückgibt. Für eine solche implizite Konvertierung ist ein Konstruktor erforderlich.quelle
Erstens geben Konstruktoren nichts zurück und haben folglich keine Rückgabetypen.
Zweitens unterscheiden sich Konstruktoren darin, dass Sie den Konstruktor nicht direkt so aufrufen können, wie Sie Funktionen aufrufen. Wenn Sie stattdessen eine Variable deklarieren, werden geeignete Konstruktoren von der Laufzeit aufgerufen.
Drittens überschreiben im Falle einer Vererbung reguläre Funktionen in Unterklassen Funktionen in übergeordneten Klassen. Konstruktoren hingegen werden zuerst Konstruktoren der Kaskaden-Elternklasse genannt, dann Konstruktoren der Unterklasse.
Viertens können Konstruktoren Initialisierungslisten haben, während "normale" Funktionen dies nicht können.
quelle