logo

Wanneer gebruiken we Initializer List in C++?

Initializer List wordt gebruikt bij het initialiseren van de gegevensleden van een klasse. De lijst met leden die moeten worden geïnitialiseerd, wordt met de constructor aangegeven als een door komma's gescheiden lijst, gevolgd door een dubbele punt. Hieronder volgt een voorbeeld waarin de initialisatielijst wordt gebruikt om x en y van de klasse Point te initialiseren.

Voorbeeld



C++






#include> using> namespace> std;> class> Point {> private>:> >int> x;> >int> y;> public>:> >Point(>int> i = 0,>int> j = 0): x(i), y(j) {}> >/* The above use of Initializer list is optional as the> >constructor can also be written as:> >Point(int i = 0, int j = 0) {> >x = i;> >y = j;> >}> >*/> >int> getX()>const> {>return> x; }> >int> getY()>const> {>return> y; }> };> int> main()> {> >Point t1(10, 15);> >cout <<>'x = '> << t1.getX() <<>', '>;> >cout <<>'y = '> << t1.getY();> >return> 0;> }>



>

>

Uitvoer

x = 10, y = 15>

De bovenstaande code is slechts een voorbeeld van de syntaxis van de Initializer-lijst. In de bovenstaande code kunnen x en y ook eenvoudig binnen de constructor worden geparafeerd. Maar er zijn situaties waarin initialisatie van gegevensleden binnen de constructor niet werkt en Initializer List moet worden gebruikt. De volgende zijn dergelijke gevallen:

1. Voor initialisatie van niet-statische const-gegevensleden

const-gegevensleden moeten worden geïnitialiseerd met behulp van Initializer List. In het volgende voorbeeld is t een const-gegevenslid van de klasse Test en wordt geïnitialiseerd met behulp van Initializer List. De reden voor het initialiseren van het const-datalid in de initialisatielijst is omdat er geen geheugen afzonderlijk wordt toegewezen voor het const-datalid. Het wordt opgevouwen in de symbooltabel, waardoor we het in de initialisatielijst moeten initialiseren.

Het is bovendien een geparametriseerde constructor en we hoeven de toewijzingsoperator niet aan te roepen, wat betekent dat we één extra bewerking vermijden.

Voorbeeld

C++




// C++ progmram to demonstrate the use of> // initializer list to initialize the const> // data member> #include> using> namespace> std;> class> Test {> >const> int> t;> public>:> >//Initializer list must be used> >Test(>int> t):t(t) {}> >int> getT() {>return> t; }> };> int> main() {> >Test t1(10);> >cout< return 0; }>

>

>

Uitvoer

10>

2. Voor initialisatie van referentieleden

Referentieleden moeten worden geïnitialiseerd met behulp van de Initializer List. In het volgende voorbeeld is t een referentielid van de klasse Test en wordt geïnitialiseerd met behulp van de Initializer List.

Voorbeeld

C++


str.replace in Java



// Initialization of reference data members> #include> using> namespace> std;> class> Test {> >int> &t;> public>:> >Test(>int> &t):t(t) {}>//Initializer list must be used> >int> getT() {>return> t; }> };> int> main() {> >int> x = 20;> >Test t1(x);> >cout< x = 30; cout< return 0; }>

>

>

Uitvoer

20 30>

3. Voor initialisatie van lidobjecten die geen standaardconstructor hebben

In het volgende voorbeeld is een object a van klasse A een gegevenslid van klasse B, en heeft A geen standaardconstructor. Initialisatielijst moet worden gebruikt om een ​​bestand te initialiseren.

Voorbeeld

C++




// C++ progmam to initialize a member object without default> // constructor> #include> using> namespace> std;> class> A {> >int> i;> public>:> >A(>int>);> };> A::A(>int> arg)> {> >i = arg;> >cout <<>'A's Constructor called: Value of i: '> << i> ><< endl;> }> // Class B contains object of A> class> B {> >A a;> public>:> >B(>int>);> };> B::B(>int> x) : a(x)> {>// Initializer list must be used> >cout <<>'B's Constructor called'>;> }> int> main()> {> >B obj(10);> >return> 0;> }>

>

>

Uitvoer

A's Constructor called: Value of i: 10 B's Constructor called>

Als klasse A zowel standaard- als geparametriseerde constructors had, dan is Initializer List geen must als we a willen initialiseren met behulp van de standaardconstructor, maar het is wel een must om a te initialiseren met behulp van de geparametriseerde constructor.

4. Voor initialisatie van basisklasseleden

Net als punt 3 kan de geparametriseerde constructor van de basisklasse alleen worden aangeroepen met behulp van de Initializer List.

Voorbeeld

C++




#include> using> namespace> std;> class> A {> >int> i;> public>:> >A(>int> );> };> A::A(>int> arg) {> >i = arg;> >cout <<>'A's Constructor called: Value of i: '> << i << endl;> }> // Class B is derived from A> class> B: A {> public>:> >B(>int> );> };> B::B(>int> x):A(x) {>//Initializer list must be used> >cout <<>'B's Constructor called'>;> }> int> main() {> >B obj(10);> >return> 0;> }>

>

>

Uitvoer

A's Constructor called: Value of i: 10 B's Constructor called>

5. Wanneer de parameternaam van de constructor hetzelfde is als het gegevenslid

Als de parameternaam van de constructor hetzelfde is als de naam van het gegevenslid, moet het gegevenslid worden geïnitialiseerd met behulp van deze wijzer of Initialisatielijst. In het volgende voorbeeld zijn zowel de lidnaam als de parameternaam voor A() i.

Voorbeeld

C++




#include> using> namespace> std;> class> A {> >int> i;> public>:> >A(>int>);> >int> getI()>const> {>return> i; }> };> A::A(>int> i) : i(i)> {> }>// Either Initializer list or this pointer must be used> /* The above constructor can also be written as> A::A(int i) {> >this->ik = ik;> }> */> int> main()> {> >A a(10);> >cout << a.getI();> >return> 0;> }>

>

>

Uitvoer

10>

6. Om prestatieredenen

Het is beter om alle klassevariabelen in de Initializer List te initialiseren in plaats van waarden in de body toe te wijzen. Beschouw het volgende voorbeeld:

Voorbeeld

C++




// 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 volgt de compiler de volgende stappen om een ​​object van het type MyClass te maken

1. De constructor van Type wordt eerst aangeroepen voor a.

2. Standaardconstructievariabele

3. De toewijzingsoperator van Type wordt binnen de hoofdtekst van de MyClass()-constructor aangeroepen om toe te wijzen

variable = a;>

4. En dan is er ten slotte een destructor van Type nodig, omdat deze buiten bereik valt.

Beschouw nu dezelfde code met de MyClass()-constructor met Initializer List

C++




// 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> >}> };>

>

>

Met de Initializer List worden de volgende stappen gevolgd door de compiler:

1. De constructor van Type wordt eerst aangeroepen voor a.
2. De geparametriseerde constructor van de klasse Type wordt aangeroepen om te initialiseren: variabele(a). De argumenten in de initialisatielijst worden gebruikt om de constructvariabele rechtstreeks te kopiëren.
3. De destructor van Type is nodig omdat deze buiten bereik valt.

Zoals we in dit voorbeeld kunnen zien, zijn er drie functieaanroepen: constructor + destructor + één optelling van de opdrachtoperator. En als we Initializer List gebruiken, zijn er slechts twee functieaanroepen: copy constructor + destructor call. Zie dit bericht voor een lopend voorbeeld op dit punt.

Deze toewijzingsstraf zal veel groter zijn in echte toepassingen waar er veel van dergelijke variabelen zullen zijn. Dankzij ptr voor het toevoegen van dit punt.

Parameter versus uniforme initialisatie in C++

Het is beter om een ​​initialisatielijst met uniforme initialisatie {} te gebruiken in plaats van parameterinitialisatie () om het probleem van beperkende conversies en onverwacht gedrag te voorkomen. Het biedt strengere typecontroles tijdens de initialisatie en voorkomt potentiële beperkende conversies

Code met behulp van parameterinitialisatie ()

C++


java case-verklaring



#include> class> Base {> >char> x;> public>:> >Base(>char> a)> >: x{ a }> >{> >}> >void> print() { std::cout <<>static_cast><>int>>(X); }> };> int> main()> {> >Base b{ 300 };>// Using uniform initialization with {}> >b.print();> >return> 0;> }>

>

>

Uitvoer

44>

In de bovenstaande code valt de waarde 300 buiten het geldige bereik voor char, wat kan leiden tot ongedefinieerd gedrag en mogelijk onjuiste resultaten. De compiler kan voor deze situatie een waarschuwing of fout genereren, afhankelijk van de compilatie-instellingen.

Code met uniforme initialisatie {}

Door uniforme initialisatie te gebruiken met {} en x te initialiseren met de opgegeven waarde a, zal de compiler strengere typecontroles uitvoeren en een waarschuwing of fout geven tijdens het compileren, wat de beperkte conversie van int naar char aangeeft.
Hier is code met uniforme initialisatie {} , wat resulteert in een waarschuwing en dus beter te gebruiken is

C++




#include> class> Base {> >char> x;> public>:> >Base(>char> a)> >: x{ a }> >{> >}> >void> print() { std::cout <<>static_cast><>int>>(X); }> };> int> main()> {> >Base b{ 300 };>// Using uniform initialization with {}> >b.print();> >return> 0;> }>

>

>

main.cpp: In function ‘int main()’: main.cpp:17:17: error: narrowing conversion of ‘300’ from ‘int’ to ‘char’ [-Wnarrowing] 17 | Base b{ 300 }; // Using uniform initialization with {} | ^>