Wie rufen Sie einen Konstruktor für globale Objekte, für Arrays von Objekten und für Objekte in Klassen / Strukturen auf?

8

Wie würden Sie den Konstruktor der folgenden Klasse in diesen drei Situationen nennen: Globale Objekte, Arrays von Objekten und Objekte, die in einer anderen Klasse / Struktur enthalten sind?

Die Klasse mit dem Konstruktor (wird in allen drei Beispielen verwendet):

%Vor%

Und hier sind meine Versuche, diesen Konstruktor aufzurufen:

Globale Objekte

%Vor%

Arrays von Objekten

%Vor%

Dort versuche ich, den Konstruktor für alle Elemente der Arrays aufzurufen, aber ich würde auch gerne wissen, wie man es für einzelne Elemente aufruft.

Objekte in Klassen / Strukturen

%Vor%     
Jeremy Ruten 16.11.2008, 19:32
quelle

8 Antworten

9

Globale Objekte

Ihr ist der einzige Weg. Auf der anderen Seite versuchen Sie dies zu vermeiden. Es ist besser, Funktionen (oder sogar andere Objekte) als Fabriken zu verwenden. Auf diese Weise können Sie den Zeitpunkt der Erstellung steuern.

Arrays von Objekten

Es gibt keine Möglichkeit, dies direkt zu tun. Non-POD-Objekte werden immer standardmäßig erstellt. std::fill ist oft eine große Hilfe. Vielleicht möchten Sie auch nach Zuweisern und std::uninitialized_fill suchen.

Objekte in Klassen / Strukturen

Verwenden Sie Initialisierungslisten in Ihrem Konstruktor:

%Vor%

Statische Member müssen eigentlich außerhalb der Klasse definiert werden:

%Vor%     
Konrad Rudolph 16.11.2008, 19:39
quelle
4

Um einige Missverständnisse über Globals zu korrigieren:

  • Die Reihenfolge ist innerhalb einer Übersetzungseinheit gut definiert.
    • Es ist dasselbe wie die Reihenfolge der Definition
  • Die Reihenfolge der Übersetzungseinheiten ist nicht definiert.
  • Die Reihenfolge der Zerstörung ist das EXAKT Gegenteil der Schöpfung.

Nicht etwas, aber ich empfehle aber: Also eine einfache Lösung ist es, alle Globals in eine einzige Kompilierungseinheit zu setzen.

Alternativ können Sie die Verwendung statischer Variablen für Funktionen ändern.
Grundsätzlich können Sie eine Funktion haben, die einen Verweis auf das gewünschte globale Objekt zurückgibt (das globale innerhalb der Funktion definiert). Es wird bei der ersten Verwendung erstellt (und in umgekehrter Reihenfolge der Erstellung zerstört).

%Vor%     
Martin York 16.11.2008 20:04
quelle
2

Die Konrad-Antwort ist in Ordnung, nur eine Erläuterung zu den Arrays .... Es gibt eine Möglichkeit, ein Array von Elementen (keine Zeiger) zu erstellen, und hier folgt:

%Vor%

Dieser Ansatz wird hier beschrieben: Ссылка

    
andy.gurin 16.11.2008 20:10
quelle
1

Für den globalen Fall gibt es keine Möglichkeit zu steuern, wann es aufgerufen wird. Die C ++ - Spezifikation besagt im Wesentlichen, dass sie vor main () aufgerufen wird und irgendwann danach zerstört wird. Abgesehen davon kann der Compiler frei tun, was er will.

Im ersten Array-Fall erstellen Sie ein statisches Array von Foo-Objekten. Standardmäßig wird jeder Wert im Array mit dem Standardkonstruktor von Foo () initialisiert. Es gibt keine Möglichkeit mit einem Raw-C ++ - Array einen bestimmten überladenen Konstruktor zum Aufruf zu zwingen. Sie können ein bisschen Kontrolle ableiten, indem Sie zu einem Vektor anstelle eines Arrays wechseln. Der Vektorkonstruktor hat einen überladenen Konstruktorvektor (size, defaultValue), der erreichen soll, wonach Sie suchen. Aber in diesem Fall müssen Sie vorsichtig sein, denn anstatt Foo (3) aufzurufen, wird es Foo (const Foo & amp; other) nennen, wo andere Foo (3) ist.

Der zweite Array-Fall ist dem ersten Fall sehr ähnlich. Der einzige wirkliche Unterschied ist, wo der Speicher zugewiesen wird (auf dem Heap anstelle des Stapels). Es hat die gleiche Einschränkung hinsichtlich des Aufrufs des Konstruktors.

Der enthaltene Fall ist ein anderes Problem. C ++ hat eine klare Trennung zwischen der Definition eines Feldes innerhalb eines Objekts und der Initialisierung des Feldes. Um dies in C ++ zum Laufen zu bringen, müssen Sie Ihre Balken-Definition in die folgenden ändern:

%Vor%     
JaredPar 16.11.2008 19:40
quelle
1

Es scheint den allgemeinen Kern in diesem Thread zu geben, dass Sie Mitglieder eines Arrays nicht anders als den Standardkonstruktor initialisieren können. Eine Antwort erstellt sogar einen anderen Typ, nur um einen anderen Konstruktor aufzurufen. Obwohl Sie können ( wenn das Array nicht als Mitglied einer Klasse ist! ):

%Vor%

Der Typ muss jedoch kopierfähig sein: Die angegebenen Elemente werden in die Mitglieder des Arrays kopiert.

Für Arrays als Member in Klassen ist es derzeit am besten, Container zu verwenden:

%Vor%

Die von andy.gurin beschriebene placement-new -Technik ist ebenfalls eine Option. Aber beachten Sie, es wird die Dinge komplizieren. Sie müssen Destruktoren selbst aufrufen. Und wenn ein Konstruktor wirft, während Sie noch das Array aufbauen, dann müssen Sie herausfinden, wo Sie aufgehört haben ... Wenn Sie Arrays in Ihrer Klasse haben wollen und diese initialisieren wollen, verwenden Sie std::vector . ist eine einfache Wette.

    
Johannes Schaub - litb 16.11.2008 22:31
quelle
0

Konstruktion von Arrays von Objekten:

Sie können Ihr ursprüngliches Beispiel mithilfe von Standardparametern ändern.

Derzeit wird nur der Standardkonstruktor unterstützt.
Dies ist etwas, das in der nächsten Version angesprochen wird (weil jeder diese Frage stellt)

    
Martin York 16.11.2008 20:10
quelle
0

C ++ 0X Initialisierungslisten lösen dieses Problem für die Groß- und Kleinschreibung. Siehe diesen Herb Sutter Blogeintrag, wo er sie im Detail beschreibt.

In der Zwischenzeit können Sie das Problem möglicherweise so umgehen:

%Vor%

Hier ist die Klasse Foo_3 nur zum Aufruf des Konstruktors Foo mit dem korrekten Argument vorhanden. Sie könnten es sogar zu einer Vorlage machen:

%Vor%

Auch dies könnte nicht genau das tun, was Sie wollen, aber vielleicht gibt es etwas zum Nachdenken.

(Beachten Sie auch, dass Sie sich in Ihrer Klasse Foo wirklich die Angewohnheit zunutze machen sollten, Member-Initialisiererlisten anstelle von Zuweisungen im Konstruktor zu verwenden, wie in meinem obigen Beispiel)

    
Alastair 16.11.2008 20:34
quelle
0

Ich denke, es gibt zwei Möglichkeiten, um sicherzustellen, dass Konstruktoren von globalen Klassenobjekten zum Zeitpunkt ihrer "Erstellung" sicher aufgerufen werden:

  1. Deklarieren Sie sie in einem Namespace und machen Sie diesen Namespace global zugänglich.

  2. Machen Sie es zu einem globalen Zeiger auf das Klassenobjekt und weisen Sie ihm ein neues Klassenobjekt in main () zu. Erteilten Code für Konstrukteure anderer globaler Objekte, die auf das Objekt zugreifen, werden davor ausgeführt.

Nur meine zwei Cent.

    
Brandon 29.03.2011 23:43
quelle

Tags und Links