1162 Stimmen

Kann ich in C++ einen Konstruktor von einem anderen Konstruktor aus aufrufen (Konstruktorverkettung durchführen)?

Als C# Entwickler bin ich es 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.

17voto

lyngvi Punkte 1282

Wenn Sie böse sein wollen, können Sie den "new"-Operator an Ort und Stelle verwenden:

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

Scheint bei mir zu funktionieren.

bearbeiten

Wie @ElvedinHamzagic anmerkt, könnte Foo, wenn es ein Objekt enthält, das Speicher zugewiesen hat, nicht freigegeben werden. Dies verkompliziert die Dinge weiter.

Ein allgemeineres 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 sicher etwas weniger elegant aus. Die Lösung von @JohnIdol ist viel besser.

14voto

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

C++11 führt ein delegierende Konstrukteure :

Delegierender Konstruktor

Wenn der Name der Klasse selbst als class-or-identifier in der Liste der Mitgliedsinitialisierer auftaucht, dann darf die Liste nur aus diesem einen Mitgliedsinitialisierer bestehen. Initialisierer bestehen; ein solcher Konstruktor wird als delegierender Konstruktor, und der Konstruktor, der von dem einzigen Mitglied der Initialisierungsliste ausgewählte Konstruktor ist der Zielkonstruktor

In diesem Fall wird der Zielkonstruktor durch Überladung ausgewählt Auflösung ausgewählt und zuerst ausgeführt, dann kehrt die Kontrolle an das delegierenden Konstruktor zurück und dessen Körper 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 macht Sinn, wenn man bedenkt, dass const/reference-Mitglieder nur einmal initialisiert werden.

11voto

unwind Punkte 377331

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

  • Überladen Sie den Konstruktor, indem Sie verschiedene Signaturen verwenden
  • Standardwerte für Argumente verwenden, um eine "einfachere" Version verfügbar zu machen

Beachten Sie, dass Sie im ersten Fall die Verdoppelung des Codes nicht reduzieren können, indem Sie einen Konstruktor aus einem anderen aufrufen. Sie können natürlich eine separate, private/geschützte Methode verwenden, die die gesamte Initialisierung vornimmt, und den Konstruktor hauptsächlich mit der Argumentbehandlung befassen lassen.

7voto

e.James Punkte 112528

Eine weitere Möglichkeit, die bisher noch nicht gezeigt wurde, besteht darin, Ihre Klasse in zwei Teile aufzuspalten und eine leichtgewichtige Schnittstellenklasse um Ihre ursprüngliche Klasse zu wickeln, um den gewünschten Effekt zu erzielen:

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

class Test : public Test_Base {
    public Test() : Test_Base() {
    }

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

Dies könnte unübersichtlich werden, wenn Sie viele Konstruktoren haben, die ihr Gegenstück auf der nächsthöheren Ebene aufrufen müssen, aber für eine Handvoll Konstruktoren sollte es machbar sein.

5voto

izogfif Punkte 115

In Visual C++ können Sie diese Notation auch innerhalb eines Konstruktors verwenden: this->Classname::Classname(Parameter eines anderen Konstruktors). Siehe ein Beispiel unten:

class Vertex
{
 private:
  int x, y;
 public:
  Vertex(int xCoo, int yCoo): x(xCoo), y(yCoo) {}
  Vertex()
  {
   this->Vertex::Vertex(-1, -1);
  }
};

Ich weiß nicht, ob es auch anderswo funktioniert, ich habe es nur in Visual C++ 2003 und 2008 getestet. Sie können auch aufrufen mehrere Konstruktoren auf diese Weise, nehme ich an, genau wie in Java und C#.

P.S.: Ehrlich gesagt, war ich überrascht, dass dies nicht schon früher erwähnt wurde.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X