Ich verwende gerne Member-Initialisierungslisten mit meinen Konstruktoren … aber ich habe die Gründe dafür schon lange vergessen …
Verwenden Sie Member-Initialisierungslisten in Ihren Konstruktoren? Wenn ja warum? Wenn nein, warum nicht?
paxos1977
Ich verwende gerne Member-Initialisierungslisten mit meinen Konstruktoren … aber ich habe die Gründe dafür schon lange vergessen …
Verwenden Sie Member-Initialisierungslisten in Ihren Konstruktoren? Wenn ja warum? Wenn nein, warum nicht?
Adam Rosenfeld
Für die Mitglieder der POD-Klasse macht es keinen Unterschied, es ist nur eine Frage des Stils. Für Klassenmember, die Klassen sind, wird dann ein unnötiger Aufruf eines Standardkonstruktors vermieden. Erwägen:
class A
{
public:
A() { x = 0; }
A(int x_) { x = x_; }
int x;
};
class B
{
public:
B()
{
a.x = 3;
}
private:
A a;
};
In diesem Fall ist der Konstruktor für B
ruft den Standardkonstruktor für auf A
und dann initialisieren a.x
zu 3. Ein besserer Weg wäre z B
‘s-Konstruktor, der direkt aufgerufen werden soll A
‘s Konstruktor in der Initialisierungsliste:
B()
: a(3)
{
}
Dies würde nur anrufen A
‘S A(int)
Konstruktor und nicht sein Standardkonstruktor. In diesem Beispiel ist der Unterschied vernachlässigbar, aber stellen Sie sich das vor A
Der Standardkonstruktor von hat mehr getan, wie z. B. das Zuweisen von Speicher oder das Öffnen von Dateien. Sie würden das nicht unnötig tun wollen.
Wenn eine Klasse keinen Standardkonstruktor hat oder Sie einen haben const
Mitgliedsvariable, du Muss Verwenden Sie eine Initialisierungsliste:
class A
{
public:
A(int x_) { x = x_; }
int x;
};
class B
{
public:
B() : a(3), y(2) // 'a' and 'y' MUST be initialized in an initializer list;
{ // it is an error not to do so
}
private:
A a;
const int y;
};
Ein Muss ist auch bei wichtigen Hinweisen
– 4pie0
6. Mai 2014 um 12:38 Uhr
Warum nicht “a(3);” verwenden? oder “a = A(3);” im Körper des Standardkonstruktors von B?
– Sergej
6. März 2015 um 10:07 Uhr
Können Sie erklären, was Sie mit POD meinen?
– Jonas Stein
19. November 2015 um 11:12 Uhr
@JonasStein POD ist ein klar definierter Satz von Regeln, die sich auf einfache Datenstrukturen (und nicht auf vollständige Klassen) beziehen. Weitere Informationen finden Sie in den häufig gestellten Fragen: stackoverflow.com/questions/146452/what-are-pod-types-in-c
– Affe0506
28. März 2016 um 4:02 Uhr
@Sergey, der Standardkonstruktor von A würde immer noch aufgerufen werden.
– Wassilis
2. Mai 2017 um 18:24 Uhr
Naveen
Abgesehen von den oben erwähnten Leistungsgründen haben Sie keine andere Wahl, als Initialisierungslisten zu verwenden, wenn Ihre Klasse Verweise auf Objekte speichert, die als Konstruktorparameter übergeben werden, oder Ihre Klasse über konstante Variablen verfügt.
Dasselbe gilt für const-Mitglieder, glaube ich.
– Richard Corden
29. Mai 2009 um 16:44 Uhr
ja, Zuweisung kann nicht verwendet werden, um die konstanten Variablen zu ändern, daher muss sie initialisiert werden.
– Hareen Laks
14. April 2018 um 13:53 Uhr
Yuvi
Ein wichtiger Grund für die Verwendung der Konstruktor-Initialisierungsliste, der hier nicht in den Antworten erwähnt wird, ist die Initialisierung der Basisklasse.
Gemäß der Konstruktionsreihenfolge sollte die Basisklasse vor der untergeordneten Klasse erstellt werden. Ohne Konstruktor-Initialisierungsliste ist dies möglich, wenn Ihre Basisklasse über einen Standardkonstruktor verfügt, der aufgerufen wird, bevor der Konstruktor der untergeordneten Klasse eingegeben wird.
Wenn Ihre Basisklasse jedoch nur über einen parametrisierten Konstruktor verfügt, müssen Sie die Konstruktor-Initialisierungsliste verwenden, um sicherzustellen, dass Ihre Basisklasse vor der untergeordneten Klasse initialisiert wird.
Initialisierung von Unterobjekten, die nur parametrisierte Konstruktoren haben
Effizienz
Mit der Konstruktor-Initialisierungsliste initialisieren Sie Ihre Datenelemente auf den genauen Zustand, den Sie in Ihrem Code benötigen, anstatt sie zuerst auf ihren Standardzustand zu initialisieren und dann ihren Zustand auf den zu ändern, den Sie in Ihrem Code benötigen.
Wenn nicht statische konstante Datenmember in Ihrer Klasse Standardkonstruktoren haben und Sie keine Konstruktor-Initialisierungsliste verwenden, können Sie sie nicht in den beabsichtigten Zustand initialisieren, da sie in ihren Standardzustand initialisiert werden.
Referenzdatenmember müssen initialisiert werden, wenn der Compiler in den Konstruktor eintritt, da Referenzen nicht einfach deklariert und später initialisiert werden können. Dies ist nur mit Konstruktorinitialisiererliste möglich.
mloskot
Neben den Leistungsproblemen gibt es noch ein weiteres sehr wichtiges, das ich Code-Wartbarkeit und -Erweiterbarkeit nennen würde.
Wenn ein T
ist POD und Sie starten lieber die Initialisierungsliste, dann wenn einmal T
in einen Nicht-POD-Typ ändern, müssen Sie nichts um die Initialisierung herum ändern, um unnötige Konstruktoraufrufe zu vermeiden, da sie bereits optimiert ist.
Wenn Typ T
hat einen Standardkonstruktor und einen oder mehrere benutzerdefinierte Konstruktoren und wenn Sie sich einmal entscheiden, den Standardkonstruktor zu entfernen oder auszublenden, müssen Sie den Code Ihrer benutzerdefinierten Konstruktoren nicht aktualisieren, wenn die Initialisierungsliste verwendet wurde, da dies bereits der Fall ist richtig umgesetzt.
Das gleiche mit const
Mitglieder oder Referenzmitglieder, sagen wir zunächst T
ist wie folgt definiert:
struct T
{
T() { a = 5; }
private:
int a;
};
Als nächstes entscheidest du dich, dich zu qualifizieren a
als const
wenn Sie die Initialisierungsliste von Anfang an verwenden würden, dann wäre dies eine einzelne Zeilenänderung, aber mit der T
wie oben definiert, muss auch die Konstruktordefinition ausgegraben werden, um die Zuweisung zu entfernen:
struct T
{
T() : a(5) {} // 2. that requires changes here too
private:
const int a; // 1. one line change
};
Es ist kein Geheimnis, dass die Wartung viel einfacher und weniger fehleranfällig ist, wenn der Code nicht von einem „Code-Affen“ geschrieben wurde, sondern von einem Ingenieur, der Entscheidungen auf der Grundlage gründlicher Überlegungen darüber trifft, was er tut.
Bevor der Hauptteil des Konstruktors ausgeführt wird, werden alle Konstruktoren für seine übergeordnete Klasse und dann für seine Felder aufgerufen. Standardmäßig werden die Konstruktoren ohne Argumente aufgerufen. Mit Initialisierungslisten können Sie auswählen, welcher Konstruktor aufgerufen wird und welche Argumente dieser Konstruktor erhält.
Wenn Sie eine Referenz oder ein konstantes Feld haben oder wenn eine der verwendeten Klassen keinen Standardkonstruktor hat, müssen Sie eine Initialisierungsliste verwenden.
Amal K
// Without Initializer List
class MyClass {
Type variable;
public:
MyClass(Type a) { // Assume that Type is an already
// declared class and it has appropriate
// constructors and operators
variable = a;
}
};
Hier führt der Compiler die folgenden Schritte aus, um ein Objekt des Typs zu erstellen MyClass
:
Type
Der Konstruktor von wird zuerst aufgerufen für „a
“.Type
“ wird im Körper von aufgerufen MyClass()
Konstruktor zuzuweisen.variable = a;
Type
” wird gerufen für “a
“, da es außerhalb des Geltungsbereichs liegt.Betrachten Sie nun den gleichen Code mit MyClass()
Konstruktor mit einer Initialisierungsliste:
// With Initializer List
class MyClass {
Type variable;
public:
MyClass(Type a):variable(a) { // Assume that Type is an already
// declared class and it has appropriate
// constructors and operators
}
};
Bei der Initializer List folgt der Compiler folgenden Schritten:
Kopierkonstruktor von „Type
” Klasse wird aufgerufen, um zu initialisieren: variable(a)
. Die Argumente in der Initialisierungsliste werden verwendet, um das Konstrukt „variable
” direkt.
Destruktor von „Type
” wird gerufen für “a
“, da es außerhalb des Geltungsbereichs liegt.
Eswaran Pandi
Syntax:
class Sample
{
public:
int Sam_x;
int Sam_y;
Sample(): Sam_x(1), Sam_y(2) /* Classname: Initialization List */
{
// Constructor body
}
};
Notwendigkeit der Initialisierungsliste:
class Sample
{
public:
int Sam_x;
int Sam_y;
Sample() */* Object and variables are created - i.e.:declaration of variables */*
{ // Constructor body starts
Sam_x = 1; */* Defining a value to the variable */*
Sam_y = 2;
} // Constructor body ends
};
im obigen Programm, wenn der Konstruktor der Klasse ausgeführt wird, Sam_x und Sam_y werden erstellt. Dann werden im Konstruktorkörper diese Mitgliedsdatenvariablen definiert.
Anwendungsfälle:
In C Variablen Muss während der Erstellung definiert werden. Auf die gleiche Weise müssen wir in C++ die Variablen Const und Reference während der Objekterstellung initialisieren, indem wir die Initialisierungsliste verwenden. Wenn wir nach der Objekterstellung initialisieren (innerhalb des Konstruktorkörpers), erhalten wir einen Kompilierzeitfehler.
Mitgliedsobjekte der Klasse Sample1 (Basis) ohne Standardkonstruktor
class Sample1
{
int i;
public:
Sample1 (int temp)
{
i = temp;
}
};
// Class Sample2 contains object of Sample1
class Sample2
{
Sample1 a;
public:
Sample2 (int x): a(x) /* Initializer list must be used */
{
}
};
Beim Erstellen eines Objekts für die abgeleitete Klasse, das den abgeleiteten Klassenkonstruktor intern aufruft und den Basisklassenkonstruktor aufruft (Standard). Wenn die Basisklasse keinen Standardkonstruktor hat, erhält der Benutzer einen Kompilierzeitfehler. Um dies zu vermeiden, müssen wir beides haben
1. Default constructor of Sample1 class
2. Initialization list in Sample2 class which will call the parametric constructor of Sample1 class (as per above program)
Der Parametername des Klassenkonstruktors und das Datenelement einer Klasse sind gleich:
class Sample3 {
int i; /* Member variable name : i */
public:
Sample3 (int i) /* Local variable name : i */
{
i = i;
print(i); /* Local variable: Prints the correct value which we passed in constructor */
}
int getI() const
{
print(i); /*global variable: Garbage value is assigned to i. the expected value should be which we passed in constructor*/
return i;
}
};
Wie wir alle wissen, hat die lokale Variable die höchste Priorität und dann die globale Variable, wenn beide Variablen den gleichen Namen haben. In diesem Fall berücksichtigt das Programm den “i”-Wert {sowohl linke als auch rechte Seitenvariable. dh: i = i} als lokale Variable im Sample3()-Konstruktor und Klassenmitgliedsvariable (i) wurde überschrieben. Um dies zu vermeiden, müssen wir beides verwenden
1. Initialization list
2. this operator.
Hier aufgeführte Gründe… https://www.geeksforgeeks.org/when-do-we-use-initializer-list-in-c/
– u8it
11. Juni 2018 um 22:17 Uhr