Ist ein "Objektkonstruktor" ein kürzerer Name für eine "Funktion mit dem Namen" Objekt ", die den Typ" Objekt "zurückgibt?


9

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 objectTyp 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 " objectreturn 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?


1
Beachten Sie, dass die Tatsache, dass Konstruktoren nach ihrem Typ benannt sind, alles andere als universell ist: PHP nennt sie __construct, Object Pascal / Delphi nennt sie Create - und ich scheine mich daran zu erinnern, dass es in diesem Fall nur eine Konvention ist und der eigentliche Unterschied darin besteht, dass sie haben das Schlüsselwort "Konstruktor" vor ihrer Definition.
IMSoP

Hinweis: Konstruktoren in C ++ noch nicht alles zurückgeben (und damit haben keinen Rückgabetyp).
el.pescado

ctors sind Metamethoden, keine Methoden. Sie senden keine ctors-Nachricht an eine Instanz einer Klasse, sondern an die Klasse - tatsächlich an das Klassenobjekt, das das Metaobjekt der Klasse ist. und ctors sind definitiv keine Funktionen, da sie Nebenwirkungen haben - Sie erhalten jedes Mal ein anderes Ergebnis.

Antworten:


17

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.


3
Sie werden im Allgemeinen auch nicht newzum Erstellen von Objekten in C ++ verwendet, da es automatische Variablen enthält.
Quentin

6

Nein, ein Konstruktor von unterscheidet objectsich stark von einer Funktion, die aufgerufen wird objectund zurückkehrt object. 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 objectund object()irgendwo einen Ausdruck verwenden , hat dieser nicht die Semantik "Aufruf des Konstruktors von object". Es hat die Semantik "ein temporäres Objekt vom Typ erstellen object". 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:

  1. Rufen Sie eine Zuordnungsfunktion operator new(die a zurückgibt void*) auf, um dem Objekt Rohspeicher zuzuweisen.
  2. Setzen Sie einen Konstruktoraufruf für diesen Rohspeicher ab, um ein Objekt in diesem Rohspeicher zu erstellen (= zu initialisieren).

Stellen Sie sich einen Konstruktor objectals eine Funktion wie diese vor:

static object object();

ist falsch. Wenn überhaupt, ist die Arbeitsweise eines Konstruktors näher daran:

static void object(object &place_to_work_in);

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 übersetzt operator new, deren Argument zurückgegeben wird, gefolgt von einem Aufruf des Konstruktors (genau wie bei jedem anderen neuen Ausdruck).


Ich gebe zu, dass ich nicht viel an diesem Stapel teilnehme, daher bin ich möglicherweise nicht mit der Kultur und den erwarteten Standards hier vertraut. Wenn ich diese Antwort verbessern kann, lassen Sie es mich bitte zusätzlich zum Downvoting wissen, damit ich das Problem beheben kann.
Angew ist nicht mehr stolz auf SO

+1 Mach dir keine Sorgen um diese Ablehnung, deine Antwort ist großartig :) Aus irgendeinem Grund haben fast alle Antworten hier eine Ablehnung.
Amon

1

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:

Konstruktoren haben keine Namen.

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:

namespace foo { 
    class bar {};
}

foo::bar bar() { return foo::bar(); }

Dies ist nicht wirklich der gleiche Name (die Funktion ist gerecht barund die Klasse ist foo::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:

class foo {
public:
   foo (int) {}
   foo operator+(foo const &other) {}
};

... dann Code wie:

foo f(1);

foo h(0);
h = f + 1;

... kann ein temporäres foo-Objekt aus dem erstellen, 1damit es dieses foo-Objekt an übergeben kann foo::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.


1

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 Namensobjekt, das Typobjekt zurückgibt" bezeichnet werden.

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.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.