c++ - konstruktor - java constructor




Kann ich einen Konstruktor von einem anderen Konstruktor(do constructor chaining) in C++ aufrufen? (10)

Als C# -Entwickler bin ich gewohnt, Konstruktoren zu durchlaufen:

class Test {
    public Test() {
        DoSomething();
    }

    public Test(int count) : this() {
        DoSomethingWithCount(count);
    }

    public Test(int count, string name) : this(count) {
        DoSomethingWithName(name);
    }
}

Gibt es eine Möglichkeit, dies in C ++ zu tun?

Ich habe versucht, den Klassennamen aufzurufen und das Schlüsselwort 'this' zu verwenden, aber beides schlägt fehl.


Beim Aufrufen eines Konstruktors weist er tatsächlich Speicher entweder vom Stapel oder vom Heap zu. Wenn Sie also einen Konstruktor in einem anderen Konstruktor aufrufen, wird eine lokale Kopie erstellt. Also modifizieren wir ein anderes Objekt, nicht das, auf das wir uns konzentrieren.


Dieser Ansatz kann für einige Arten von Klassen funktionieren (wenn sich der Zuweisungsoperator "gut" verhält):

Foo::Foo()
{
    // do what every Foo is needing
    ...
}

Foo::Foo(char x)
{
    *this = Foo();

    // do the special things for a Foo with char
    ...
}

Einfach gesagt, können Sie nicht vor C ++ 11.

C ++ 11 führt delegierende Konstruktoren ein :

Delegieren des Konstruktors

Wenn der Name der Klasse selbst als Klasse oder Kennung in der Memberinitialisierungsliste angezeigt wird, muss die Liste nur aus diesem einen Memberinitialisierer bestehen. Ein solcher Konstruktor wird als delegierender Konstruktor bezeichnet, und der Konstruktor, der vom einzigen Mitglied der Initialisierungsliste ausgewählt wird, ist der Zielkonstruktor

In diesem Fall wird der Zielkonstruktor durch Überladungsauflösung ausgewählt und zuerst ausgeführt, dann kehrt das Steuerelement zum delegierenden Konstruktor zurück und sein Rumpf wird ausgeführt.

Delegierende Konstruktoren können nicht rekursiv sein.

class Foo {
public: 
  Foo(char x, int y) {}
  Foo(int y) : Foo('a', y) {} // Foo(int) delegates to Foo(char,int)
};

Beachten Sie, dass ein delegierender Konstruktor ein Alles-oder-Nichts-Vorschlag ist; Wenn ein Konstruktor an einen anderen Konstruktor delegiert, darf der aufrufende Konstruktor keine anderen Mitglieder in seiner Initialisierungsliste haben. Dies ist sinnvoll, wenn Sie darüber nachdenken, const / reference-Mitglieder einmal und nur einmal zu initialisieren.


Es ist erwähnenswert, dass Sie den Konstruktor einer Elternklasse in Ihrem Konstruktor aufrufen können , zB:

class A { /* ... */ };

class B : public A
{
    B() : A()
    {
        // ...
    }
};

Aber, nein, Sie können keinen anderen Konstruktor derselben Klasse aufrufen.


Ich würde vorschlagen, eine private friend Methode zu verwenden, die die Anwendungslogik des Konstruktors implementiert und von den verschiedenen Konstruktoren aufgerufen wird. Hier ist ein Beispiel:

Angenommen, wir haben eine Klasse namens StreamArrayReader mit einigen privaten Feldern:

private:
    istream * in;
      // More private fields

Und wir wollen die zwei Konstruktoren definieren:

public:
    StreamArrayReader(istream * in_stream);
    StreamArrayReader(char * filepath);
    // More constructors...

Wo der zweite einfach den ersten benutzt (und natürlich wollen wir die Umsetzung des ersteren nicht kopieren). Idealerweise würde man gerne so etwas machen wie:

StreamArrayReader::StreamArrayReader(istream * in_stream){
    // Implementation
}

StreamArrayReader::StreamArrayReader(char * filepath) {
    ifstream instream;
    instream.open(filepath);
    StreamArrayReader(&instream);
    instream.close();
}

Dies ist jedoch in C ++ nicht erlaubt. Aus diesem Grund können wir eine private Friend-Methode wie folgt definieren, die implementiert, was der erste Konstruktor tun soll:

private:
  friend void init_stream_array_reader(StreamArrayReader *o, istream * is);

Nun hat diese Methode (weil sie ein Freund ist) Zugriff auf die privaten Felder von o . Dann wird der erste Konstruktor:

StreamArrayReader::StreamArrayReader(istream * is) {
    init_stream_array_reader(this, is);
}

Beachten Sie, dass dadurch nicht mehrere Kopien für die neu erstellten Kopien erstellt werden. Der zweite wird:

StreamArrayReader::StreamArrayReader(char * filepath) {
    ifstream instream;
    instream.open(filepath);
    init_stream_array_reader(this, &instream);
    instream.close();
}

Das heißt, anstatt dass ein Konstruktor einen anderen anruft, rufen beide einen privaten Freund an!


In C++11 kann ein Wikipedia :

class Foo  {
     int d;         
public:
    Foo  (int i) : d(i) {}
    Foo  () : Foo(42) {} //New to C++11
};

Darüber hinaus können Mitglieder auch so initialisiert werden.

class Foo  {
     int d = 5;         
public:
    Foo  (int i) : d(i) {}
};

Dadurch sollte die Initialisierungs-Hilfsmethode nicht mehr erstellt werden. Es wird weiterhin empfohlen, keine virtuellen Funktionen in den Konstruktoren oder Destruktoren aufzurufen, um die Verwendung von Membern zu vermeiden, die möglicherweise nicht initialisiert werden.


Nein, Sie können keinen Konstruktor in C ++ 03 (als delegierender Konstruktor bezeichnet) von einem anderen Konstruktor aus aufrufen.

Dies änderte sich in C ++ 11 (aka C ++ 0x), die Unterstützung für die folgende Syntax hinzugefügt:
(Beispiel aus Wikipedia )

class SomeType
{
  int number;

public:
  SomeType(int newNumber) : number(newNumber) {}
  SomeType() : SomeType(42) {}
};

Nein, in C ++ kann man keinen Konstruktor von einem Konstruktor aufrufen. Was Sie tun können, wie Warren sagte, ist:

  • Überladen Sie den Konstruktor mit verschiedenen Signaturen
  • Verwenden Sie Standardwerte für Argumente, um eine "einfachere" Version verfügbar zu machen

Beachten Sie, dass Sie im ersten Fall die Code-Duplizierung nicht reduzieren können, indem Sie einen Konstruktor von einem anderen Konstruktor aufrufen. Sie können natürlich eine separate private / protected-Methode verwenden, die die gesamte Initialisierung durchführt, und den Konstruktor hauptsächlich mit der Behandlung von Argumenten behandeln lassen.


Wenn Sie Ihre Frage richtig verstehen, fragen Sie, ob Sie mehrere Konstruktoren in C ++ aufrufen können.

Wenn Sie danach suchen, dann ist das nicht möglich.

Sie können sicherlich mehrere Konstruktoren haben, jeder mit eindeutigen Argumentsignaturen, und dann den gewünschten Namen bei der Instanziierung eines neuen Objekts aufrufen.

Sie können am Ende sogar einen Konstruktor mit default-Argumenten haben.

Aber Sie haben möglicherweise nicht mehrere Konstruktoren und rufen sie dann einzeln auf.


Wenn du böse sein willst, kannst du den direkten "neuen" Operator verwenden:

class Foo() {
    Foo() { /* default constructor deliciousness */ }
    Foo(Bar myParam) {
      new (this) Foo();
      /* bar your param all night long */
    } 
};

Scheint für mich zu arbeiten.

bearbeiten

Wie @ElvedinHamzagic hervorhebt, wenn Foo ein Objekt enthält, das Speicher zugewiesen hat, wird dieses Objekt möglicherweise nicht freigegeben. Dies verkompliziert die Dinge weiter.

Ein allgemeines Beispiel:

class Foo() {
private:
  std::vector<int> Stuff;
public:
    Foo()
      : Stuff(42)
    {
      /* default constructor deliciousness */
    }

    Foo(Bar myParam)
    {
      this->~Foo();
      new (this) Foo();
      /* bar your param all night long */
    } 
};

Sieht etwas weniger elegant aus. @ John Idol's Lösung ist viel besser.





constructor