logo

Kdaj uporabljamo Initializer List v C++?

Initializer List se uporablja pri inicializaciji podatkovnih članov razreda. Seznam članov, ki jih je treba inicializirati, je označen s konstruktorjem kot seznam, ločen z vejico, ki mu sledi dvopičje. Sledi primer, ki uporablja seznam inicializatorjev za inicializacijo x in y razreda Point.

Primer



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



>

>

Izhod

x = 10, y = 15>

Zgornja koda je samo primer sintakse seznama inicializatorjev. V zgornji kodi je mogoče x in y enostavno inicializirati znotraj konstruktorja. Toda obstajajo situacije, ko inicializacija podatkovnih članov znotraj konstruktorja ne deluje in je treba uporabiti seznam inicializatorjev. Takšni primeri so naslednji:

1. Za inicializacijo nestatičnih podatkovnih članov const

const podatkovne člane je treba inicializirati s seznamom inicializatorjev. V naslednjem primeru je t stalni podatkovni član testnega razreda in je inicializiran s seznamom inicializatorjev. Razlog za inicializacijo podatkovnega člana const na seznamu inicializatorja je, ker za podatkovni član const ni ločeno dodeljen pomnilnik, ampak je zložen v tabeli simbolov, zaradi česar ga moramo inicializirati na seznamu inicializatorja.

Poleg tega je parametrizirani konstruktor in nam ni treba klicati operaterja dodelitve, kar pomeni, da se izognemo eni dodatni operaciji.

Primer

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

>

>

Izhod

10>

2. Za inicializacijo referenčnih članov

Referenčne člane je treba inicializirati s seznamom inicializatorjev. V naslednjem primeru je t referenčni član razreda Test in je inicializiran s seznamom inicializatorjev.

Primer

C++


java parseint



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

>

>

Izhod

20 30>

3. Za inicializacijo članskih objektov, ki nimajo privzetega konstruktorja

V naslednjem primeru je objekt a razreda A podatkovni član razreda B in A nima privzetega konstruktorja. Seznam inicializatorjev je treba uporabiti za inicializacijo a.

Primer

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

>

>

Izhod

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

Če bi imel razred A privzete in parametrirane konstruktorje, potem seznam inicializatorjev ni obvezen, če želimo inicializirati s pomočjo privzetega konstruktorja, je pa nujno inicializirati a z uporabo parametriziranega konstruktorja.

4. Za inicializacijo članov osnovnega razreda

Tako kot pri točki 3 lahko parametrizirani konstruktor osnovnega razreda pokličete samo s seznamom inicializatorjev.

Primer

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

>

>

Izhod

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

5. Ko je ime parametra konstruktorja enako kot podatkovni član

Če je ime parametra konstruktorja enako imenu podatkovnega člana, mora biti podatkovni član inicializiran z ta kazalec ali Initializer List. V naslednjem primeru sta ime člana in ime parametra za A() i.

Primer

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

>

>

Izhod

10>

6. Zaradi učinkovitosti

Bolje je inicializirati vse spremenljivke razreda na seznamu inicializatorjev, namesto da vrednosti dodeljujete znotraj telesa. Razmislite o naslednjem primeru:

Primer

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

>

>

Tukaj prevajalnik sledi naslednjim korakom za ustvarjanje objekta tipa MyClass

1. Konstruktor tipa se najprej pokliče za a.

2. Privzeta konstruktivna spremenljivka

3. Operator dodelitve Type je poklican znotraj telesa konstruktorja MyClass() za dodelitev

variable = a;>

4. In potem se končno kliče destruktor vrste, ker gre izven obsega.

Zdaj razmislite o isti kodi s konstruktorjem MyClass() s seznamom inicializatorjev

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

>

>

S seznamom inicializatorjev prevajalnik sledi naslednjim korakom:

1. Konstruktor tipa se najprej pokliče za a.
2. Parametrizirani konstruktor razreda Type se kliče za inicializacijo: spremenljivke(a). Argumenti na seznamu inicializatorja se uporabljajo za neposredno kopiranje konstruktivne spremenljivke.
3. Destruktor Type se kliče za a, ker gre izven obsega.

Kot lahko vidimo iz tega primera, če uporabimo dodelitev znotraj telesa konstruktorja, obstajajo trije klici funkcij: konstruktor + destruktor + en klic operaterja dodelitve dodatka. In če uporabimo Initializer List, obstajata samo dva klica funkcij: konstruktor kopiranja + klic destruktorja. Oglejte si to objavo za tekoči primer o tej točki.

Ta kazen za dodelitev bo veliko večja v resničnih aplikacijah, kjer bo veliko takih spremenljivk. Zahvale gredo ptr za dodajanje te točke.

Parameter proti enotni inicializaciji v C++

Bolje je uporabiti inicializacijski seznam z enotno inicializacijo {} namesto inicializacije parametrov (), da se izognete težavam z zoženimi konverzijami in nepričakovanim vedenjem. Zagotavlja strožje preverjanje tipa med inicializacijo in preprečuje morebitne zožene pretvorbe

Koda z uporabo inicializacije parametrov ()

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

>

>

Izhod

44>

V zgornji kodi je vrednost 300 izven veljavnega obsega za char, kar lahko povzroči nedefinirano vedenje in morebitne napačne rezultate. Prevajalnik lahko za to situacijo ustvari opozorilo ali napako, odvisno od nastavitev prevajanja.

Koda z enotno inicializacijo {}

Z uporabo enotne inicializacije z {} in inicializacijo x s podano vrednostjo a bo prevajalnik izvedel strožje preverjanje tipa in izdal opozorilo ali napako med prevajanjem, kar kaže na zožitev pretvorbe iz int v char.
Tukaj je koda z enotno inicializacijo {}, ki povzroči opozorilo in je zato boljša za uporabo

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

en milijon v številkah

>

>

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 {} | ^>