La llista d'inicialitzadors s'utilitza per inicialitzar els membres de dades d'una classe. La llista de membres que cal inicialitzar s'indica amb el constructor com una llista separada per comes seguida de dos punts. A continuació es mostra un exemple que utilitza la llista d'inicialitzadors per inicialitzar x i y de la classe Point.
Exemple
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;> }> |
>
>Sortida
x = 10, y = 15>
El codi anterior és només un exemple de sintaxi de la llista d'inicialitzadors. En el codi anterior, x i y també es poden rubricar fàcilment dins del constructor. Però hi ha situacions en què la inicialització dels membres de dades dins del constructor no funciona i s'ha d'utilitzar la llista d'inicialitzadors. Aquests són aquests casos:
1. Per a la inicialització de membres de dades constants no estàtiques
Els membres de dades const s'han d'inicialitzar mitjançant la llista d'inicialitzadors. A l'exemple següent, t és un membre de dades const de la classe Test i s'inicializa mitjançant la llista d'inicialitzadors. La raó per inicialitzar el membre de dades const a la llista d'inicialitzadors és perquè no s'assigna memòria per separat per al membre de dades const, es plega a la taula de símbols per la qual cosa l'hem d'inicialitzar a la llista d'inicialitzadors.
A més, és un constructor parametritzat i no necessitem trucar a l'operador d'assignació, la qual cosa significa que estem evitant una operació addicional.
Exemple
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; }> |
>
>Sortida
10>
2. Per a la inicialització de membres de referència
Els membres de referència s'han d'inicialitzar mitjançant la llista d'inicialitzadors. A l'exemple següent, t és un membre de referència de la classe Test i s'inicializa mitjançant la llista d'inicialitzadors.
Exemple
C++
quan acaba q1
// 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; }> |
>
>Sortida
20 30>
3. Per a la inicialització d'objectes membres que no tenen un constructor predeterminat
A l'exemple següent, un objecte a de la classe A és un membre de dades de la classe B i A no té un constructor per defecte. La llista d'inicialitzadors s'ha d'utilitzar per inicialitzar a.
Exemple
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;> }> |
>
>Sortida
A's Constructor called: Value of i: 10 B's Constructor called>
Si la classe A tenia constructors per defecte i parametritzats, aleshores la llista d'iniciadors no és imprescindible si volem inicialitzar un amb el constructor per defecte, però sí que cal inicialitzar un mitjançant el constructor parametritzat.
4. Per a la inicialització dels membres de la classe base
Com el punt 3, el constructor parametritzat de la classe base només es pot cridar mitjançant la llista d'inicialitzadors.
Exemple
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;> }> |
>
>Sortida
A's Constructor called: Value of i: 10 B's Constructor called>
5. Quan el nom del paràmetre del constructor és el mateix que el membre de dades
Si el nom del paràmetre del constructor és el mateix que el nom del membre de dades, llavors el membre de dades s'ha d'inicialitzar mitjançant aquest punter o Llista d'inicialitzadors. A l'exemple següent, tant el nom del membre com el nom del paràmetre per a A() és i.
Exemple
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->i = i;> }> */> int> main()> {> >A a(10);> >cout << a.getI();> >return> 0;> }> |
>
>Sortida
10>
6. Per raons de rendiment
És millor inicialitzar totes les variables de classe a la llista d'inicialitzadors en lloc d'assignar valors dins del cos. Considereu l'exemple següent:
Exemple
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;> >}> };> |
>
>
Aquí el compilador segueix els passos següents per crear un objecte del tipus MyClass
1. El constructor del tipus s'anomena primer per a.
bucle while i do while a java
2. Variable de construcció per defecte
3. L'operador d'assignació de Type s'anomena dins del cos del constructor MyClass() per assignar-lo
variable = a;>
4. I finalment, el destructor de Type es demana a perquè surt de l'abast.
Ara considereu el mateix codi amb el constructor MyClass() amb la llista d'inicialitzadors
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> >}> };> |
>
>
Amb la llista d'inicialitzadors, el compilador segueix els passos següents:
1. El constructor del tipus es crida primer per a.
2. Es crida al constructor parametritzat de la classe Type per inicialitzar: variable(a). Els arguments de la llista d'inicialitzadors s'utilitzen per copiar la variable de construcció directament.
3. El destructor de Type és cridat per a ja que surt fora de l'abast.
Com podem veure en aquest exemple, si fem servir l'assignació dins del cos del constructor, hi ha tres trucades de funció: constructor + destructor + una crida d'operador d'assignació addicional. I si fem servir la llista d'inicialitzadors només hi ha dues trucades de funció: crida al constructor de còpia + crida al destructor. Vegeu aquesta publicació per obtenir un exemple corrent sobre aquest punt.
Aquesta penalització d'assignació serà molt més en aplicacions reals on hi haurà moltes variables d'aquest tipus. Gràcies a ptr per afegir aquest punt.
Paràmetre vs inicialització uniforme en C++
És millor utilitzar una llista d'inicialització amb inicialització uniforme {} en lloc d'inicialització de paràmetres () per evitar el problema de reduir les conversions i el comportament inesperat. Proporciona una comprovació de tipus més estricta durant la inicialització i evita possibles conversions de reducció
Codi mitjançant la inicialització de paràmetres ()
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;> }> |
>
>Sortida
44>
Al codi anterior, el valor 300 està fora de l'interval vàlid per a char, cosa que pot provocar un comportament no definit i resultats potencialment incorrectes. El compilador pot generar un avís o un error per a aquesta situació, depenent de la configuració de la compilació.
Codi amb inicialització uniforme {}
Mitjançant l'ús d'una inicialització uniforme amb {} i la inicialització de x amb el valor proporcionat a, el compilador realitzarà una comprovació de tipus més estricta i emetrà un avís o un error durant la compilació, indicant la conversió reduïda de int a char.
Aquí teniu el codi amb inicialització uniforme {} , que resulta en un avís i, per tant, millor utilitzar-lo
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 {} | ^>