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

Lesezeit: 7 Minuten

Kann ich in C einen Konstruktor von einem anderen Konstruktor
Stormenet

Als ein C# Entwickler Ich bin 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.

  • Verwenden this ODER auto im angesprochenen Kontext wären interessante Schlüsselwörter für zukünftige Refactoring-Zwecke.

    – sergiol

    29. Dezember 2015 um 16:13 Uhr


Kann ich in C einen Konstruktor von einem anderen Konstruktor
JohnIdol

C++11: Ja!

C++11 und höher hat dieselbe Funktion (genannt Konstruktoren delegieren).

Die Syntax unterscheidet sich geringfügig von C#:

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

C++03: Nein

Leider gibt es in C++03 keine Möglichkeit, dies zu tun, aber es gibt zwei Möglichkeiten, dies zu simulieren:

  1. Sie können zwei (oder mehr) Konstruktoren über Standardparameter kombinieren:

    class Foo {
    public:
      Foo(char x, int y=0);  // combines two constructors (char) and (char, int)
      // ...
    };
    
  2. Verwenden Sie eine Init-Methode, um gemeinsamen Code zu teilen:

    class Foo {
    public:
      Foo(char x);
      Foo(char x, int y);
      // ...
    private:
      void init(char x, int y);
    };
    
    Foo::Foo(char x)
    {
      init(x, int(x) + 7);
      // ...
    }
    
    Foo::Foo(char x, int y)
    {
      init(x, y);
      // ...
    }
    
    void Foo::init(char x, int y)
    {
      // ...
    }
    

Sehen den C++FAQ-Eintrag als Referenz.

  • Eigentlich bemerkenswert Standardparameter sorgen für einen sehr sauber Möglichkeit, das zu tun, was wir normalerweise erreichen würden, indem wir this() in C# aufrufen

    – bobobobo

    18. Februar 2010 um 22:53 Uhr


  • Beachten Sie, dass die vorgeschlagene Lösung, die C++11 nicht verwendet, nur funktioniert, wenn die zu erstellende Klasse weder Vererbung noch konstante Felder hat. Ich habe keine Möglichkeit gefunden, übergeordnete Klassen- und Konstantenfelder außerhalb der Initialisierungsliste zu initialisieren.

    – ausgegraut

    24. Juli 2013 um 15:09 Uhr

  • @bobobobo Die Verwendung von Standardparametern kompiliert sie in den Aufrufer, das ist also nicht der Fall sehr reinigen. Überladen ist mehr Code, richtig, aber die Implementierung kapselt die Standardwerte.

    – Eugen Rjabtsew

    8. April 2014 um 10:31 Uhr

  • Der einzige Nachteil bei der Verwendung von init() ist, dass Sie keinen Zeiger oder Verweis deklarieren können, der konstant ist (wie in ref/pointer const, eher das, worauf er zeigt), wenn Sie ihn nicht in constructor() initialisieren.

    – locka

    12. September 2014 um 10:45 Uhr

  • @gen (abgesehen vom fehlenden zweiten Doppelpunkt) Es wird ein temporäres Foo erstellt und dann sofort verworfen.

    – Jim Balter

    13. September 2017 um 18:59 Uhr

1647180612 763 Kann ich in C einen Konstruktor von einem anderen Konstruktor
Kyrill Ka

Ja und Nein, je nachdem, welche Version von C++.

In C++03 können Sie einen Konstruktor nicht von einem anderen aufrufen (sogenannter delegierender Konstruktor).

Dies hat sich in C++11 (alias C++0x) geändert, wodurch die Unterstützung für die folgende Syntax hinzugefügt wurde:
(Beispiel entnommen aus Wikipedia)

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

  • Aber wie unterscheidet sich das von der standardmäßigen Standardparametersyntax?

    – Tomáš Zato – Wiedereinsetzung von Monica

    14. September 2015 um 13:52 Uhr

  • @TomášZato Eine Sache, die Sie mit Standardparametern nicht tun können, ist die Verwendung Ihres Parameters zum Aufrufen des anderen Konstruktors: SomeType(string const &s) { /*...*/ } SomeType(char const *pc) : SomeType(string(pc)) { /*...*/ }

    – Kyrill Ka

    14. September 2015 um 18:14 Uhr


  • @TomášZato Ein weiterer Unterschied besteht darin, dass Sie mit Standardparametern nur einen Konstruktor haben, den Sie entweder öffentlich, geschützt oder privat machen müssen, während Sie mit 2 Konstruktoren, von denen einer den anderen aufruft, den Zugriff auf einen von ihnen einschränken können, ohne auch den Zugriff einschränken zu müssen zum anderen.

    – Kaiserludi

    22. Januar 2016 um 17:00 Uhr

  • PS: Natürlich könnte man das auch mit einer privaten Init-Funktion machen, die von mehreren Konstruktoren aufgerufen wird, aber das würde nicht für Initialisierungslisten funktionieren.

    – Kaiserludi

    22. Januar 2016 um 17:22 Uhr

  • Er unterscheidet sich auch von Standardwerten, da Sie ihn ändern können, ohne den Code, der die Bibliothek verwendet, neu zu kompilieren. Mit Standardwerten werden diese Werte in den Anruf “gebacken”.

    – Rptx

    19. März 2016 um 22:59 Uhr

1647180614 699 Kann ich in C einen Konstruktor von einem anderen Konstruktor
quadratisch

Ich glaube, Sie können einen Konstruktor von einem Konstruktor aufrufen. Es wird kompiliert und ausgeführt. Ich habe kürzlich gesehen, wie jemand dies getan hat, und es lief sowohl unter Windows als auch unter Linux.

Es macht einfach nicht was du willst. Der innere Konstruktor erstellt ein temporäres lokales Objekt, das gelöscht wird, sobald der äußere Konstruktor zurückkehrt. Sie müssten auch unterschiedliche Konstruktoren sein oder Sie würden einen rekursiven Aufruf erstellen.

Ref: https://isocpp.org/wiki/faq/ctors#init-methods

  • Guter Punkt; Die meisten sagten nur “Nein, das kannst du nicht”. Ich kann :). Ich habe dieses Zurückschalten durchgeführt und den ursprünglichen Ctor verwendet, um zu entscheiden, welchen anderen ich anrufen soll. Beim Debuggen war das Objekt im zweiten zu sehen, alles wird initialisiert, geht aber bei der Rückgabe auf die Standardwerte zurück. Macht viel Sinn, wenn man darüber nachdenkt.

    – ChiefTwoPencils

    28. Oktober 2013 um 8:05 Uhr

  • Dies ist kein “Aufruf eines Konstruktors”. Die nur Ort, an dem Sie direkt “einen Konstruktor aufrufen” können, befindet sich in der ctor-Initialisierer in C++11. In diesem Beispiel konstruieren Sie ein Objekt, bei dem es sich um einen anderen Fischkessel handelt. Lassen Sie sich nicht davon täuschen, dass es sieht aus wie ein Funktionsaufruf an den Konstruktor, denn es ist nicht ein! Es gibt tatsächlich keine Möglichkeit, einen Funktionsaufruf an den Konstruktor zu senden, weshalb es unmöglich ist, eine Instanz einer Klasse zu konstruieren, deren einzige(r) Konstruktor(en) Instanziierungen einer Funktionsvorlage sind, deren Vorlagenargumente nicht abgeleitet werden können.

    – Leichtigkeitsrennen im Orbit

    26. November 2014 um 23:38 Uhr


  • (Das heißt, es ist syntaktisch unmöglich, explizit Vorlagenargumente für einen Konstruktor bereitzustellen.)

    – Leichtigkeitsrennen im Orbit

    26. November 2014 um 23:40 Uhr

  • Es gibt tatsächlich eine Möglichkeit, einen Funktionsaufruf an einen Konstruktor zu senden – die Verwendung von Platzierung new Syntax. Dies ist jedoch normalerweise nicht das, was Sie wollen. (Und es erlaubt Ihnen nicht, explizit Vorlagenargumente bereitzustellen.)

    – keltischer Minnesänger

    23. Juni 2015 um 2:23 Uhr

  • Platzierung verwenden new würde noch eine erstellen Neu Objekt, allerdings am selben Speicherplatz. Aber trotzdem ein anderes Objekt, und es ist möglich, den Code zusammenzustellen, der dies beweist.

    – Leon

    23. September 2015 um 15:17 Uhr

1647180615 234 Kann ich in C einen Konstruktor von einem anderen Konstruktor
kchoose2

C++11: Jawohl!

C++11 und höher hat dieselbe Funktion (genannt Konstruktoren delegieren).

Die Syntax unterscheidet sich geringfügig von C#:

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

C++03: Nein

Es ist erwähnenswert, dass Sie kann Rufen Sie den Konstruktor einer übergeordneten Klasse in Ihrem Konstruktor auf, z.

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

Aber nein, Sie können keinen anderen Konstruktor derselben Klasse bis C++03 aufrufen.

Kann ich in C einen Konstruktor von einem anderen Konstruktor
Ben L

Im C++11ein Konstruktor kann eine andere Konstruktorüberladung aufrufen:

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) {}
};

Dies sollte die Erstellung der Hilfsmethode für die Initialisierung überflüssig machen. Und es wird dennoch empfohlen, keine virtuellen Funktionen in den Konstruktoren oder Destruktoren aufzurufen, um die Verwendung von Membern zu vermeiden, die möglicherweise nicht initialisiert sind.

Wenn Sie böse sein wollen, können Sie den In-Place-Operator “new” 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 betont, wird dieses Objekt möglicherweise nicht freigegeben, wenn Foo ein Objekt enthält, das Speicher zugewiesen hat. Das verkompliziert die Sache 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 auf jeden Fall etwas weniger elegant aus. Die Lösung von @JohnIdol ist viel besser.

1647180617 991 Kann ich in C einen Konstruktor von einem anderen Konstruktor
Scott Smith

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

C++11 führt ein Konstruktoren delegieren:

Konstrukteur delegieren

Wenn der Name der Klasse selbst als Klassen-oder-Bezeichner in der Member-Initialisierer-Liste erscheint, dann darf die Liste nur aus diesem einen Member-Initialisierer bestehen; ein solcher Konstruktor wird als delegierender Konstruktor bezeichnet, und der Konstruktor, der vom einzigen Mitglied der Initialisiererliste 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 Member in seiner Initialisierungsliste haben. Dies ist sinnvoll, wenn Sie daran denken, const/reference-Elemente einmal und nur einmal zu initialisieren.

998000cookie-checkKann ich in C++ einen Konstruktor von einem anderen Konstruktor aufrufen (Konstruktorverkettung durchführen)?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy