Konstruktor und Initialisierung von benutzerdefinierten Klassen / Objekten

8

Ich könnte mir vorstellen, dass diese Frage bereits gestellt wurde, aber ich konnte tatsächlich keine passende Lösung finden, also bitte entschuldigen Sie, wenn das eine überflüssige Frage ist.

Ich habe eine benutzerdefinierte Klasse

%Vor%

Jetzt habe ich eine andere benutzerdefinierte Klasse, die ein Mitglied vom Typ myClass_A

hat %Vor%

Nun möchte myFunction_B() die Methode myFunction_A() von m_instance kinda wie folgt aufrufen:

%Vor%

Nun, wenn ich meinen Code kompiliere (was im Grunde wie das Beispiel ist, das ich oben gepostet habe), wird es ohne irgendwelche Warnungen oder Fehler gelingen. Also meine Fragen wären:

A. Wird der Konstruktor in diesem Beispiel aufgerufen?

B. Kann ich Methoden von einem nicht initialisierten Objekt aufrufen?

C. Angenommen, der Konstruktor wird nicht aufgerufen, aber ich kann immer noch die Methoden von diesem Objekt aufrufen - & gt; Das bedeutet noch, dass die Mitglieder meiner Klasse nicht initialisiert sind?

Tut mir leid, wenn diese Fragen irgendwie dumm sind, aber ich habe das Gefühl, dass ich gerade jetzt langsam bin.

    
Toby 21.03.2012, 10:07
quelle

5 Antworten

7

Das sind sehr gute und wichtige Fragen.

Betreffend A:

Bevor Sie den Rumpf Ihres Konstruktors ausführen, generiert C ++ Code, der automatisch den Standardkonstruktor aller aggregierten (d. h. Mitglieds-) Objekte Ihrer Klasse aufruft. Im Grunde wird der folgende Code umgewandelt:

%Vor%

in den folgenden Code:

%Vor%

Die beiden Zeilen, die der Compiler automatisch eingefügt hat, heißen Initialisierungsliste und ruft den Standardkonstruktor auf von jedem Aggregatobjekt vor wird der Rumpf Ihres Konstruktors ausgeführt. Bitte beachten Sie, dass der zweite, m_pInstance() den "Standardkonstruktor von Zeiger " aufruft, der einen nicht initialisierten Zeiger erstellt ; das ist fast immer nicht das was du willst. Siehe unten, wie Sie das beheben können.

Nehmen wir nun an, dass der Konstruktor von myClass_A die Signatur myClass_A(int someNumber) hat, d. h. er benötigt ein Argument. Dann kann C ++ nicht die Initialisierungsliste für myClass_B automatisch generieren, da es nicht weiß, welche Zahl den Konstruktor von myClass_A übergeben soll. Es wird einen Compilerfehler bei dir auslösen, der sich wahrscheinlich über einen fehlenden Standardkonstruktor für myClass_A beschweren wird. Sie müssen die Initialisiererliste selbst schreiben, zum Beispiel:

%Vor%

Dies ist der korrekte Code, der myClass_A -Konstruktor mit dem Wert 21 für den Parameter someNumber aufruft. Dies zeigt auch, wie Sie einen Zeiger korrekt initialisieren: Lassen Sie ihn auf ein neu zugewiesenes Objekt zeigen.

In Bezug auf B:

Anders als einige andere sagen, können Sie! (Probieren Sie es aus)

Aber es führt zu unerwartetem Verhalten, das nicht das ist, was Sie wollen. (Einschließlich, dass es tun könnte, was Sie nur wollen, wenn die Planeten richtig ausgerichtet sind.) Es wird höchstwahrscheinlich abstürzen, aber es ist nicht garantiert, dass es abstürzt. Dies kann zu langen Debugging-Nächten führen. Wenn Ihr Compiler intelligent ist, erkennt er dies möglicherweise und warnt Sie, aber Sie erhalten keinen Fehler.

Beachten Sie auch, dass für Non-Pointer-Aggregatobjekte, die einen Standardkonstruktor haben, der Standardkonstruktor aufgerufen wird und Sie alle gut sind. Das Problem tritt auf, wenn Sie eingebaute Typen oder Zeiger verwenden. Dies ist die Verwendung von nicht initialisierten Variablen und ist eine der häufigsten Ursachen für einen Fehler. Wenn Ihr Code etwas total Seltsames tut, überprüfen Sie immer, ob Sie alle Ihre Variablen initialisiert haben. Es sollte ein Reflex werden, einen Eintrag in die Initialisierungsliste für jede Mitgliedsvariable zu setzen, selbst wenn sie den Standardkonstruktor aufruft. Macht die Dinge klar.

In Bezug auf C:

Ja. Siehe B für Details. Das Interessante daran ist, dass Ihre Methode garantiert funktioniert, wenn die Methode, die Sie aufrufen, nicht den "This" -Zeiger verwendet (dies beinhaltet, keine Attributvariable zu verwenden und keine Methode aufzurufen, die eine Attributvariable verwendet). Was passiert, wenn Sie eine Methode für ein nicht initialisiertes Objekt aufrufen, ist, dass das "dieses" Objekt innerhalb der Methode (d. H. Alle Attributvariablen) zufälliger Speicher ist. Der Code der Methode wird ausgeführt, verwendet aber zufälligen Speicher und das ist was fehlschlägt.

Ich hoffe, das klärt die Dinge ein wenig auf.

    
LucasB 21.03.2012, 10:38
quelle
3
  

Wird der Konstruktor in diesem Beispiel aufgerufen?

Ja
Die Konstruktoren für myClass_B wurden aufgerufen, nachdem der Aufruf des Konstruktors myClass_A() abgeschlossen ist.
Normalerweise würden Sie das myClass_B -Objekt im Konstruktor von my_class_A mit einem
initialisieren. member-syntax-in-the-constructor / 8523361 # 8523361 "> Mitgliederinitialisierungsliste .

  

Kann ich tatsächlich Methoden von einem nicht initialisierten Objekt aufrufen?

Wenn ein Objekt erstellt wird, wird sein Konstruktor immer aufgerufen. Wenn Sie kein Objekt konstruieren, können Sie keine Methode dafür aufrufen. Dies ist der Zweck von Konstruktoren, ein Objekt zu erstellen und es zu initialisieren.
Wenn Sie also ein Objekt haben, ist es niemals uninitialisiert.

Wenn Sie auf Zeiger verweisen, sind Zeiger für sich keine Objekte, die auf ein gültiges oder ungültiges Objekt verweisen können. Wenn Sie einen Zeiger (zum Aufrufen einer Elementfunktion oder was auch immer) nicht auf ein gültiges Objekt zeigen, führt dies zu Undefiniertes Verhalten .

  

Angenommen, der Konstruktor wird nicht aufgerufen, aber ich kann immer noch die Methoden von diesem Objekt aufrufen - & gt; Das bedeutet noch, dass die Mitglieder meiner Klasse nicht initialisiert sind?

Antwort auf die zweite Frage beantwortet dies.

    
Alok Save 21.03.2012 10:10
quelle
2

A. yes: Konstruktoren von Mitgliedern werden vor dem Konstruktor der enthaltenden Klasse aufgerufen. B. ja, aber das Ergebnis ist undefiniertes Verhalten (= alles kann passieren; sogar scheinbar funktioniert.).

    
zvrba 21.03.2012 10:10
quelle
2

Klassenmitglieder werden automatisch vom Compiler mithilfe des Standardkonstruktors initialisiert, sofern Sie nicht anders im Konstruktor Ihrer eigenen Klasse angeben Initialisierungsliste . Also ja, der Konstruktor wird aufgerufen.

Sie können dies selbst testen, indem Sie:

  • Der Konstruktor muss eine Nachricht (die Sie sehen werden) oder
  • drucken
  • macht den Konstruktor privat oder deklariert einen Konstruktor mit Argumenten, so dass der Standardkonstruktor nicht mehr automatisch erzeugt wird (der Compiler verweigert die Kompilierung, da er das Aggregatobjekt nicht mehr standardmäßig konstruieren kann)

Wenn Sie Methoden aufrufen oder auf Member eines Objekts zugreifen, das nicht initialisiert wurde oder bereits zerstört wurde (beide Szenarien können erstellt werden), haben Sie undefiniertes Verhalten .

    
Jon 21.03.2012 10:10
quelle
0

A. Der Konstruktor für Ihre Klasse myClass_A wird aufgerufen, sobald das Objekt der Klasse myClass_B instanziiert wird.

B. Sie können z. B. keine Methoden von nicht-entialisierten Objekten aufrufen

%Vor%

wird eine Ausnahme auslösen.

C. Sie können eine Methode niemals erfolgreich aufrufen, ohne dass das Objekt vollständig aufgebaut ist.

    
Jeeva 21.03.2012 10:14
quelle

Tags und Links