Lista de inițializare este utilizată la inițializarea membrilor de date ai unei clase. Lista de membri care urmează să fie inițializați este indicată cu constructor ca o listă separată prin virgulă urmată de două puncte. Următorul este un exemplu care utilizează lista de inițializare pentru a inițializa x și y din clasa Point.
Exemplu
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;> }> |
>
>Ieșire
x = 10, y = 15>
Codul de mai sus este doar un exemplu pentru sintaxa listei de inițializare. În codul de mai sus, x și y pot fi, de asemenea, parafate cu ușurință în interiorul constructorului. Dar există situații în care inițializarea membrilor de date din interiorul constructorului nu funcționează și trebuie utilizată Lista de inițializare. Următoarele sunt astfel de cazuri:
1. Pentru inițializarea membrilor de date const non-static
membrii de date const trebuie inițializați utilizând Lista de inițializare. În exemplul următor, t este un membru de date const al clasei Test și este inițializat utilizând Lista de inițializare. Motivul inițializării membrului de date const în lista de inițializare este că nu este alocată separat nicio memorie pentru membrul de date const, acesta este pliat în tabelul de simboluri, datorită căruia trebuie să-l inițializam în lista de inițializare.
De asemenea, este un constructor parametrizat și nu trebuie să apelăm operatorul de atribuire, ceea ce înseamnă că evităm o operație suplimentară.
Exemplu
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; }> |
>
>Ieșire
10>
2. Pentru inițializarea membrilor de referință
Membrii de referință trebuie inițializați utilizând Lista de inițializare. În exemplul următor, t este un membru de referință al clasei Test și este inițializat folosind Lista de inițializare.
Exemplu
C++
împachetare cuvinte css
// 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; }> |
>
>Ieșire
20 30>
3. Pentru inițializarea obiectelor membre care nu au un constructor implicit
În exemplul următor, un obiect a din clasa A este un membru de date al clasei B, iar A nu are un constructor implicit. Lista de inițializare trebuie utilizată pentru a inițializa a.
Exemplu
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;> }> |
>
>Ieșire
A's Constructor called: Value of i: 10 B's Constructor called>
Dacă clasa A a avut atât constructori impliciti, cât și parametrizați, atunci Lista de inițializare nu este obligatorie dacă vrem să inițializam un folosind constructorul implicit, dar este obligatoriu să inițializam un folosind constructorul parametrizat.
4. Pentru inițializarea membrilor clasei de bază
La fel ca și punctul 3, constructorul parametrizat al clasei de bază poate fi apelat doar folosind Lista de inițializare.
Exemplu
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;> }> |
>
>Ieșire
A's Constructor called: Value of i: 10 B's Constructor called>
5. Când numele parametrului constructorului este identic cu membrul de date
Dacă numele parametrului constructorului este același cu numele membrului de date, atunci membrul de date trebuie inițializat fie folosind acest indicator sau Lista de inițializare. În exemplul următor, atât numele membrului, cât și numele parametrului pentru A() este i.
Exemplu
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;> }> |
>
expresie de regresie în java
>Ieșire
10>
6. Din motive de performanță
Este mai bine să inițializați toate variabilele de clasă din Lista de inițializare în loc să atribuiți valori în interiorul corpului. Luați în considerare următorul exemplu:
Exemplu
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;> >}> };> |
>
>
Aici compilatorul urmează următorii pași pentru a crea un obiect de tip MyClass
1. Constructorul tipului este apelat mai întâi pentru a.
2. Variabila de construcție implicită
3. Operatorul de atribuire al Type este numit în corpul constructorului MyClass() pentru a fi atribuit
variable = a;>
4. Și apoi, în cele din urmă, destructorul de tip este chemat pentru a, deoarece iese din domeniul de aplicare.
Acum luați în considerare același cod cu constructorul MyClass() cu 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> >}> };> |
>
>
Cu Lista de inițializare, compilatorul urmează următorii pași:
1. Constructorul tipului este apelat mai întâi pentru a.
2. Constructorul parametrizat al clasei Type este apelat pentru a inițializa: variabila(a). Argumentele din lista de inițializare sunt folosite pentru a copia direct variabila de construcție.
3. Destructorul de tip este chemat pentru a deoarece iese din domeniul de aplicare.
După cum putem vedea din acest exemplu, dacă folosim alocarea în corpul constructorului, există trei apeluri de funcție: constructor + destructor + un apel de operator de atribuire adițională. Și dacă folosim Initializer List există doar două apeluri de funcție: copy constructor + call destructor. Vedeți această postare pentru un exemplu de rulare în acest punct.
Această penalizare de atribuire va fi mult mai mare în aplicațiile reale unde vor exista multe astfel de variabile. Mulțumită ptr pentru adăugarea acestui punct.
Parametru vs Inițializare uniformă în C++
Este mai bine să folosiți o listă de inițializare cu inițializare uniformă {} decât inițializarea parametrilor () pentru a evita problema restrângerii conversiilor și a comportamentului neașteptat. Oferă o verificare mai strictă a tipului în timpul inițializării și previne potențialele conversii de restrângere
Cod folosind inițializarea parametrilor ()
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;> }> |
>
>Ieșire
44>
În codul de mai sus, valoarea 300 este în afara intervalului valid pentru char, ceea ce poate duce la un comportament nedefinit și la rezultate potențial incorecte. Compilatorul poate genera o avertizare sau o eroare pentru această situație, în funcție de setările de compilare.
Cod folosind inițializarea uniformă {}
Folosind inițializarea uniformă cu {} și inițializarea x cu valoarea furnizată a, compilatorul va efectua o verificare mai strictă de tip și va emite un avertisment sau o eroare în timpul compilării, indicând conversia restrânsă de la int la char.
Aici este codul cu inițializare uniformă {} , care are ca rezultat un avertisment și, prin urmare, mai bine de utilizat
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 {} | ^>