成員初始化列表與構(gòu)造函數(shù)體中的區(qū)別詳細解析
論壇中回答一個別人問題
C++ Primer中在講構(gòu)造函數(shù)初始化列表的時候有這么一段話:
無論是在構(gòu)造函數(shù)初始化列表中初始化成員,還是在構(gòu)造函數(shù)體中對它們賦值,最終結(jié)果是相同的。不同之處在于,使用構(gòu)造函數(shù)初始化列表的版本初始化數(shù)據(jù)成員,沒有定義初始化列表的構(gòu)造函數(shù)版本在構(gòu)造函數(shù)體中對數(shù)據(jù)成員賦值。
請問這里的初始化數(shù)據(jù)成員與對數(shù)據(jù)成員賦值的含義是什么?有什么區(qū)別?
我知道在數(shù)據(jù)成員有默認構(gòu)造函數(shù)時是有不同的,但對其他類型的成員呢?其他類型成員的初始化和賦值有區(qū)別嗎?
=========================================================================
是這個意思:
首先把數(shù)據(jù)成員按類型分類
1。內(nèi)置數(shù)據(jù)類型,復(fù)合類型(指針,引用)
2。用戶定義類型(類類型)
分情況說明:
對于類型1,在成員初始化列表和構(gòu)造函數(shù)體內(nèi)進行,在性能和結(jié)果上都是一樣的
對于類型2,結(jié)果上相同,但是性能上存在很大的差別
因為類類型的數(shù)據(jù)成員對象在進入函數(shù)體是已經(jīng)構(gòu)造完成,也就是說在成員初始化列表處進行構(gòu)造對象的工作,這是調(diào)用一個構(gòu)造函數(shù),在進入函數(shù)體之后,進行的是 對已經(jīng)構(gòu)造好的類對象的賦值,又調(diào)用個拷貝賦值操作符才能完成(如果并未提供,則使用編譯器提供的默認按成員賦值行為)
舉個例說明
class A;
class B
{public:
B(){a = 3;}
private:
A a;
}
class A
{public:
A(){}
A(int){value = 3;}
int value;
}
像上面,我們使a對象的value為3,調(diào)用一個A的構(gòu)造函數(shù)+一個默認拷貝賦值符,才達到目的
B::B():a(3){}
像這樣,只調(diào)用了一個構(gòu)造函數(shù)就達到了所需的對象啦,所以性能好的
轉(zhuǎn)載他人一篇
我的問題是關(guān)于初始化C++類成員的。我見過許多這樣的代碼(包括在你的欄目中也見到過):
CSomeClass::CSomeClass()
{
x=0;
y=1;
}
而在別的什么地方則寫成下面的樣子:
CSomeClass::CSomeClass() : x(0), y(1)
{
}
我的一些程序員朋友說第二種方法比較好,但他們都不知道為什么是這樣。你能告訴我這兩種類成員初始化方法的區(qū)別嗎?
回答
從技術(shù)上說,你的程序員朋友是對的,但是在大多數(shù)情況下,兩者實際上沒有區(qū)別。有兩個原因使得我們選擇第二種語法,它被稱為成員初始化列表:一個原因是必須的,另一個只是出于效率考慮。
讓我們先看一下第一個原因——必要性。設(shè)想你有一個類成員,它本身是一個類或者結(jié)構(gòu),而且只有一個帶一個參數(shù)的構(gòu)造函數(shù)。
class CMember {
public:
CMember(int x) { ... }
};
因為Cmember有一個顯式聲明的構(gòu)造函數(shù),編譯器不產(chǎn)生一個缺省構(gòu)造函數(shù)(不帶參數(shù)),所以沒有一個整數(shù)就無法創(chuàng)建Cmember的一個實例。
CMember* pm = new CMember; // Error!!
CMember* pm = new CMember(2); // OK
如果Cmember是另一個類的成員,你怎樣初始化它呢?你必須使用成員初始化列表。
class CMyClass {
CMember m_member;
public:
CMyClass();
};
//必須使用成員初始化列表
CMyClass::CMyClass() : m_member(2)
{
•••
}
沒有其它辦法將參數(shù)傳遞給m_member,如果成員是一個常量對象或者引用也是一樣。根據(jù)C++的規(guī)則,常量對象和引用不能被賦值,它們只能被初始化。
第二個原因是出于效率考慮,當(dāng)成員類具有一個缺省的構(gòu)造函數(shù)和一個賦值操作符時。MFC的Cstring提供了一個完美的例子。假定你有一個類CmyClass具有一個Cstring類型的成員m_str,你想把它初始化為"yada yada."。你有兩種選擇:
CMyClass::CMyClass() {
// 使用賦值操作符
// CString::operator=(LPCTSTR);
m_str = _T("yada yada");
}
//使用類成員列表
// and constructor CString::CString(LPCTSTR)
CMyClass::CMyClass() : m_str(_T("yada yada"))
{
}
在 它們之間有什么不同嗎?是的。編譯器總是確保所有成員對象在構(gòu)造函數(shù)體執(zhí)行之前初始化,因此在第一個例子中編譯的代碼將調(diào)用CString:: Cstring來初始化m_str,這在控制到達賦值語句前完成。在第二個例子中編譯器產(chǎn)生一個對CString:: CString(LPCTSTR)的調(diào)用并將"yada yada"傳遞給這個函數(shù)。結(jié)果是在第一個例子中調(diào)用了兩個Cstring函數(shù)(構(gòu)造函數(shù)和賦值操作符),而在第二個例子中只調(diào)用了一個函數(shù)。在 Cstring的例子里這是無所謂的,因為缺省構(gòu)造函數(shù)是內(nèi)聯(lián)的,Cstring只是在需要時為字符串分配內(nèi)存(即,當(dāng)你實際賦值時)。但是,一般而言, 重復(fù)的函數(shù)調(diào)用是浪費資源的,尤其是當(dāng)構(gòu)造函數(shù)和賦值操作符分配內(nèi)存的時候。在一些大的類里面,你可能擁有一個構(gòu)造函數(shù)和一個賦值操作符都要調(diào)用同一個負 責(zé)分配大量內(nèi)存空間的Init函數(shù)。在這種情況下,你必須使用初始化列表,以避免不要的分配兩次內(nèi)存。在內(nèi)部類型如ints或者longs或者其它沒有構(gòu) 造函數(shù)的類型下,在初始化列表和在構(gòu)造函數(shù)體內(nèi)賦值這兩種方法沒有性能上的差別。不管用那一種方法,都只會有一次賦值發(fā)生。有些程序員說你應(yīng)該總是用初始 化列表以保持良好習(xí)慣,但我從沒有發(fā)現(xiàn)根據(jù)需要在這兩種方法之間轉(zhuǎn)換有什么困難。在編程風(fēng)格上,我傾向于在主體中使用賦值,因為有更多的空間用來格式化和 添加注釋,你可以寫出這樣的語句:x=y=z=0;
或者memset(this,0,sizeof(this));
注意第二個片斷絕對是非面向?qū)ο蟮摹?/FONT>
當(dāng)我考慮初始化列表的問題時,有一個奇怪的特性我應(yīng)該警告你,它是關(guān)于C++初始化類成員的,它們是按照聲明的順序初始化的,而不是按照出現(xiàn)在初始化列表中的順序。
class CMyClass {
CMyClass(int x, int y);
int m_x;
int m_y;
};
CMyClass::CMyClass(int i) : m_y(i), m_x(m_y)
{
}
你可能以為上面的代碼將會首先做m_y=I,然后做m_x=m_y,最后它們有相同的值。但是編譯器先初始化m_x,然后是m_y,,因為它們是按這樣的順 序聲明的。結(jié)果是m_x將有一個不可預(yù)測的值。我的例子設(shè)計來說明這一點,然而這種bug會更加自然的出現(xiàn)。有兩種方法避免它,一個是總是按照你希望它們 被初始化的順序聲明成員,第二個是,如果你決定使用初始化列表,總是按照它們聲明的順序羅列這些成員。這將有助于消除混淆。
上一篇:關(guān)于C/C++中可變參數(shù)的詳細介紹(va_list,va_start,va_arg,va_end)
欄 目:C語言
下一篇:C/C++指針小結(jié)
本文標(biāo)題:成員初始化列表與構(gòu)造函數(shù)體中的區(qū)別詳細解析
本文地址:http://www.jygsgssxh.com/a1/Cyuyan/4033.html
您可能感興趣的文章
- 01-10c++ 構(gòu)造函數(shù)的初始化列表
- 01-10C++運算符重載 成員函數(shù)與友元函數(shù)詳解
- 01-10C++指向類成員函數(shù)的指針詳細解析
- 01-10一般函數(shù)指針和類的成員函數(shù)指針深入解析
- 01-10指向類成員函數(shù)的指針其實并非指針
- 01-10淺析C++中結(jié)構(gòu)體的定義、初始化和引用
- 01-10C++初始化列表學(xué)習(xí)
- 01-10C++中Operator類型強制轉(zhuǎn)換成員函數(shù)解析
- 01-10C++空類詳解
- 01-10大家注意vector, list, set, map成員函數(shù)erase


閱讀排行
本欄相關(guān)
- 04-02c語言函數(shù)調(diào)用后清空內(nèi)存 c語言調(diào)用
- 04-02func函數(shù)+在C語言 func函數(shù)在c語言中
- 04-02c語言的正則匹配函數(shù) c語言正則表達
- 04-02c語言用函數(shù)寫分段 用c語言表示分段
- 04-02c語言中對數(shù)函數(shù)的表達式 c語言中對
- 04-02c語言編寫函數(shù)冒泡排序 c語言冒泡排
- 04-02c語言沒有round函數(shù) round c語言
- 04-02c語言分段函數(shù)怎么求 用c語言求分段
- 04-02C語言中怎么打出三角函數(shù) c語言中怎
- 04-02c語言調(diào)用函數(shù)求fibo C語言調(diào)用函數(shù)求
隨機閱讀
- 08-05織夢dedecms什么時候用欄目交叉功能?
- 01-10delphi制作wav文件的方法
- 04-02jquery與jsp,用jquery
- 01-10C#中split用法實例總結(jié)
- 08-05DEDE織夢data目錄下的sessions文件夾有什
- 01-10SublimeText編譯C開發(fā)環(huán)境設(shè)置
- 08-05dedecms(織夢)副欄目數(shù)量限制代碼修改
- 01-10使用C語言求解撲克牌的順子及n個骰子
- 01-11ajax實現(xiàn)頁面的局部加載
- 01-11Mac OSX 打開原生自帶讀寫NTFS功能(圖文


