Dies sind sehr gute und wichtige Fragen.
In Bezug auf A:
Vor der Ausführung des Konstruktorkörpers erzeugt C++ Code, der automatisch die Standardkonstruktor aller aggregierten (d. h. Mitglieds-) Objekte Ihrer Klasse. Im Wesentlichen wird der folgende Code umgewandelt:
class myClass_B {
public:
myClass_B()
{
m_instance.foo();
m_pInstance->foo();
}
private:
myClass_A m_instance;
myClass_A* m_pInstance;
};
in den folgenden Code:
class myClass_B {
public:
myClass_B()
: m_instance()
, m_pInstance()
{
m_instance.foo();
m_pInstance->foo();
}
private:
myClass_A m_instance;
myClass_A* m_pInstance;
};
Die beiden Zeilen, die der Compiler automatisch eingefügt hat, heißen Initialisierungsliste ruft es den Standardkonstruktor jedes Aggregatobjekts auf vor wird der Körper Ihres Konstruktors ausgeführt. Bitte beachten Sie, dass die zweite, m_pInstance()
ruft den "Standardkonstruktor von Zeiger ", das eine nicht initialisierter Zeiger Dies ist fast immer nicht das, was Sie wollen. Siehe unten, wie man das beheben kann.
Nehmen wir nun an, dass der Konstruktor von myClass_A
hat die Signatur myClass_A(int someNumber)
d.h. es benötigt ein Argument. Dann, C++ kann nicht automatisch die Initialisierungsliste für myClass_B
da es nicht weiß, welche Nummer es übergeben soll myClass_A
Konstrukteur. Es wird einen Compilerfehler auslösen, der sich wahrscheinlich über einen fehlenden Standardkonstruktor für myClass_A
. Sie müssen zum Beispiel die Initialisierungsliste selbst schreiben:
class myClass_B {
public:
myClass_B()
: m_instance(21)
, m_pInstance(new myClass_A(21))
{
m_instance.foo();
m_pInstance->foo();
}
private:
myClass_A m_instance;
myClass_A* m_pInstance;
};
Dies ist korrekter Code, der Folgendes aufruft myClass_A
Konstruktor mit dem Wert 21 für den Parameter someNumber
. Dies zeigt auch, wie man einen Zeiger korrekt initialisiert: Er muss auf ein neu zugewiesenes Objekt zeigen.
In Bezug auf B:
Im Gegensatz zu einigen anderen, die sagen, du kannst! (Probieren Sie es aus)
Dies führt jedoch zu einem unerwarteten Verhalten, was nicht erwünscht ist. (Dazu gehört auch, dass es nur dann funktioniert, wenn die Planeten richtig ausgerichtet sind.) Es wird höchstwahrscheinlich abstürzen, aber es ist nicht garantiert, dass es abstürzt. Das kann zu langen Debugging-Nächten führen. Wenn Ihr Compiler schlau ist, könnte er dies erkennen und warnen aber es wird Ihnen keinen Fehler anzeigen.
Beachten Sie auch, dass für Nicht-Zeiger-Aggregatobjekte, die einen Standardkonstruktor haben, der Standardkonstruktor wird angerufen werden, und alles wird gut sein. Das Problem entsteht, wenn Sie eingebaute Typen oder Zeiger verwenden. Dies ist die Verwendung von nicht initialisierten Variablen und eine der häufigsten Ursachen für einen Fehler. Wenn Ihr Code etwas völlig Seltsames tut, überprüfen Sie immer, ob Sie alle Ihre Variablen initialisiert haben. Es sollte ein Reflex werden, für jede Member-Variable einen Eintrag in die Initialisierungsliste zu machen, auch wenn sie den Standardkonstruktor aufruft. Das macht die Dinge klar.
In Bezug auf C:
Ja. Siehe B für Einzelheiten. Das Interessante daran ist, dass Ihre Methode garantiert funktioniert, wenn die von Ihnen aufgerufene Methode nicht den "this"-Zeiger verwendet (d. h. keine Attributvariable verwendet und keine Methode aufruft, die eine Attributvariable verwendet). Was passiert, wenn Sie eine Methode auf einem nicht initialisierten Objekt aufrufen, ist, dass das "this"-Objekt innerhalb der Methode (d.h. auch alle Attributvariablen) zufälliger Speicher ist. Der Code der Methode wird zwar ausgeführt, verwendet aber zufälligen Speicher, und das ist es, was scheitert.
Ich hoffe, das klärt die Sache ein wenig auf.