新聞中心
目錄
1.什么是初始化列表
2.什么時(shí)候需要使用初始化列表?
3.初始化列表的效率
4.初始化列表的初始化順序
1.什么是初始化列表
class A {
public:
A(int value):m_dada(value)
{
}
private:
int m_dada;
};
如上圖,紅色圈起來的部分,就是構(gòu)造函數(shù)的初始化列表,以冒號(hào)開始,冒號(hào)后面依次列出需要賦值的成員變量和值。
2.什么時(shí)候需要使用初始化列表?(1)當(dāng)有成員變量是引用類型時(shí)
(2)當(dāng)有數(shù)據(jù)成員是常量時(shí)
(3)當(dāng)父類的構(gòu)造函數(shù)有參數(shù)時(shí)
(4)當(dāng)成員變量所屬類型的構(gòu)造函數(shù)有參數(shù)時(shí)
2.1當(dāng)有成員變量是引用類型時(shí)可以看到類中有一個(gè)引用類型的變量m_data,直接編譯會(huì)報(bào)錯(cuò),提示“必須初始化引用”,即使在構(gòu)造函數(shù)里面賦值也不行,此時(shí)必須使用初始化列表,下面看看使用初始化列表后的情況。
可以看到,使用初始化列表后,編譯成功。
2.2當(dāng)有數(shù)據(jù)成員是常量時(shí)可以看到,類中有個(gè)const常量m_data,直接編譯會(huì)報(bào)錯(cuò),提示“必須初始化常量”。下面看看使用初始化列表后的情況。
可以看到,使用初始化列表后,編譯成功。
2.3當(dāng)父類的構(gòu)造函數(shù)有參數(shù)時(shí)可以看到,B類的父類是A,A的構(gòu)造函數(shù)有一個(gè)參數(shù),在實(shí)現(xiàn)B類的構(gòu)造函數(shù)時(shí),如果不處理A類的構(gòu)造函數(shù),就會(huì)編譯報(bào)錯(cuò),提示“A類沒有合適的默認(rèn)構(gòu)造函數(shù)可用”。下面看下使用了初始化列表后的情況。
可以看到,使用初始化列表后,編譯成功。
2.4當(dāng)成員變量所屬類型的構(gòu)造函數(shù)有參數(shù)時(shí)可以看到,B類有一個(gè)數(shù)據(jù)成員A m_a,在B類的構(gòu)造函數(shù)中沒有對(duì)這個(gè)m_a作處理,導(dǎo)致編譯報(bào)錯(cuò),提示“A沒有合適的默認(rèn)構(gòu)造函數(shù)可以”。下面看看使用了初始化列表后的情況。
#include "stdafx.h"
#includeusing namespace std;
class A {
public:
A()
{
cout<< "call A()"<< endl;
}
~A()
{
cout<< "call ~A()"<< endl;
}
};
class B
{
public:
B(A value) : m_a(value)
{
cout<< "call B()"<< endl;
//m_a = value;
}
~B()
{
cout<< "call ~B()"<< endl;
}
private:
A m_a;
};
int main()
{
A objA;
B objB(objA);
return 0;
}
上面這段代碼,在B類的構(gòu)造函數(shù)中,使用了初始化列表給成員變量A m_a進(jìn)行賦值,運(yùn)行結(jié)果如下:
可以看到在調(diào)用B類的構(gòu)造函數(shù)時(shí),調(diào)用了一次A類的析構(gòu)函數(shù),沒有調(diào)用A類的構(gòu)造函數(shù),我想這是VS編譯器的特殊設(shè)計(jì)造成的,換成其它編譯器可能就不是這樣了,這里我認(rèn)為使用了初始化列表之后,應(yīng)該在B類的構(gòu)造函數(shù)中不會(huì)調(diào)用A類的構(gòu)造函數(shù)和析構(gòu)函數(shù)了,這樣才符合使用初始化列表的效率更高的特點(diǎn)。
下面看一下沒有使用初始化列表,而直接在B類構(gòu)造函數(shù)中給m_a賦值的情況。
#include "stdafx.h"
#includeusing namespace std;
class A {
public:
A()
{
cout<< "call A()"<< endl;
}
~A()
{
cout<< "call ~A()"<< endl;
}
};
class B
{
public:
B(A value)
{
cout<< "call B()"<< endl;
m_a = value;
}
~B()
{
cout<< "call ~B()"<< endl;
}
private:
A m_a;
};
int main()
{
A objA;
B objB(objA);
return 0;
}
可以看到,如果直接在B類的構(gòu)造函數(shù)中賦值,將會(huì)導(dǎo)致多一次A類構(gòu)造函數(shù)的調(diào)用。
綜上所述,使用初始化列表給成員變量設(shè)定初始值效率會(huì)更高,建議優(yōu)先使用這種方法。對(duì)于基礎(chǔ)類型的變量,比如int,bool類型,則沒有必要非要采用初始化列表。
4.初始化列表的初始化順序編譯器會(huì)將初始化列表一一轉(zhuǎn)換成代碼,并且這些代碼會(huì)被放在用戶編寫的代碼之前。初始化列表的初始化順序是由數(shù)據(jù)成員的聲明次序決定的,不是由初始化列表的排列次序決定的。
“初始化次序”和“初始化列表中的排列次序”如果不一致,將可能導(dǎo)致意想不到的風(fēng)險(xiǎn)。比如:
class C
{
private:
int i;
int j;
public:
C(int value):j(value),i(j)
{
cout<< "i = "<< i<< endl;
cout<< "j = "<< j<< endl;
}
};
int main()
{
C objC(10);
return 0;
}
上述程序代碼看起來像是要把j設(shè)初值為 value,再把i設(shè)初值為 j.問題在于,由于聲明次序的緣故,初始化列表中的”i(j)”其實(shí)比”j(value)”更早執(zhí)行。但因?yàn)閖 一開始未有初值,所以i(j)的執(zhí)行結(jié)果導(dǎo)致無法預(yù)知其值。
那么如何避免上面的問題呢,建議是如果要用一個(gè)成員變量的值給另外一個(gè)成員變量賦值,則建議將賦值的代碼寫在構(gòu)造函數(shù)中,如下:
class C
{
private:
int i;
int j;
public:
C(int value):j(value)
{
i = j;
cout<< "i = "<< i<< endl;
cout<< "j = "<< j<< endl;
}
};
int main()
{
C objC(10);
return 0;
}
因?yàn)槌跏蓟斜淼膱?zhí)行是在構(gòu)造函數(shù)的用戶代碼之前,所以j會(huì)先被賦值。
接下來看看下面這段代碼有沒有什么問題。
class C
{
private:
int i;
int j;
public:
C(int value):j(value)
{
i = j;
cout<< "i = "<< i<< endl;
cout<< "j = "<< j<< endl;
}
};
class D : public C
{
private:
int data;
public:
int GetValue()
{
return data;
}
D(int value):data(value),C(GetValue())
{
cout<< "data = "<< data<< endl;
}
};
int main()
{
D objD(10);
return 0;
}
上面的代碼中,在D類的構(gòu)造函數(shù)使用了初始化列表,在初始化列表中調(diào)用了成員函數(shù)來給父類的構(gòu)造函數(shù)傳參,乍一看好像沒什么問題,但是從最后的運(yùn)行結(jié)果來看,i和j未被成功賦值,這是為什么呢?
這是因?yàn)樵诔跏蓟斜碇校割惖臉?gòu)造函數(shù)被優(yōu)先執(zhí)行,導(dǎo)致data還沒來得及賦值。所以建議將父類的構(gòu)造函數(shù)放在初始化列表的最前面,以避免上述問題。
你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機(jī)房具備T級(jí)流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級(jí)服務(wù)器適合批量采購,新人活動(dòng)首月15元起,快前往官網(wǎng)查看詳情吧
網(wǎng)頁題目:C++初始化列表詳解-創(chuàng)新互聯(lián)
網(wǎng)頁地址:http://fisionsoft.com.cn/article/iodce.html