c++中拷貝構(gòu)造函數(shù)的參數(shù)類型必須是引用
在C++中, 構(gòu)造函數(shù),拷貝構(gòu)造函數(shù),析構(gòu)函數(shù)和賦值函數(shù)(賦值運(yùn)算符重載)是最基本不過(guò)的需要掌握的知識(shí)。 但是如果我問(wèn)你“拷貝構(gòu)造函數(shù)的參數(shù)為什么必須使用引用類型?”這個(gè)問(wèn)題, 你會(huì)怎么回答? 或許你會(huì)回答為了減少一次內(nèi)存拷貝? 很慚愧的是,我的第一感覺(jué)也是這么回答。不過(guò)還好,我思索一下以后,發(fā)現(xiàn)這個(gè)答案是不對(duì)的。
原因:
如果拷貝構(gòu)造函數(shù)中的參數(shù)不是一個(gè)引用,即形如CClass(const CClass c_class),那么就相當(dāng)于采用了傳值的方式(pass-by-value),而傳值的方式會(huì)調(diào)用該類的拷貝構(gòu)造函數(shù),從而造成無(wú)窮遞歸地調(diào)用拷貝構(gòu)造函數(shù)。因此拷貝構(gòu)造函數(shù)的參數(shù)必須是一個(gè)引用。
需要澄清的是,傳指針其實(shí)也是傳值,如果上面的拷貝構(gòu)造函數(shù)寫成CClass(const CClass* c_class),也是不行的。事實(shí)上,只有傳引用不是傳值外,其他所有的傳遞方式都是傳值。
先從一個(gè)小例子開始:(自己測(cè)試一下自己看看這個(gè)程序的輸出是什么?)
#include<iostream>
using namespace std;
class CExample
{
private:
int m_nTest;
public:
CExample(int x) : m_nTest(x) //帶參數(shù)構(gòu)造函數(shù)
{
cout << "constructor with argument"<<endl;
}
// 拷貝構(gòu)造函數(shù),參數(shù)中的const不是嚴(yán)格必須的,但引用符號(hào)是必須的
CExample(const CExample & ex) //拷貝構(gòu)造函數(shù)
{
m_nTest = ex.m_nTest;
cout << "copy constructor"<<endl;
}
CExample& operator = (const CExample &ex) //賦值函數(shù)(賦值運(yùn)算符重載)
{
cout << "assignment operator"<<endl;
m_nTest = ex.m_nTest;
return *this;
}
void myTestFunc(CExample ex)
{
}
};
int main(void)
{
CExample aaa(2);
CExample bbb(3);
bbb = aaa;
CExample ccc = aaa;
bbb.myTestFunc(aaa);
return 0;
}
果你能一眼看出就是這個(gè)結(jié)果的話, 恭喜你,可以站起來(lái)扭扭屁股,不用再往下看了。
如果你的結(jié)果和輸出結(jié)果有誤差, 那拜托你謙虛的看完。
第一個(gè)輸出: constructor with argument // CExample aaa(2);
如果你不理解的話, 找個(gè)人把你拖出去痛打一頓,然后嘴里還喊著“我是二師兄,我是二師兄.......”
第二個(gè)輸出:constructor with argument // CExample bbb(3);
分析同第一個(gè)
第三個(gè)輸出: assignment operator // bbb = aaa;
第四個(gè)輸出: copy constructor // CExample ccc = aaa;
這兩個(gè)得放到一塊說(shuō)。 肯定會(huì)有人問(wèn)為什么兩個(gè)不一致。原因是, bbb對(duì)象已經(jīng)實(shí)例化了,不需要構(gòu)造,此時(shí)只是將aaa賦值給bbb,只會(huì)調(diào)用賦值函數(shù),就這么簡(jiǎn)單,還不懂的話,撞墻去! 但是ccc還沒(méi)有實(shí)例化,因此調(diào)用的是拷貝構(gòu)造函數(shù),構(gòu)造出ccc,而不是賦值函數(shù),還不懂的話,我撞墻去!!
第五個(gè)輸出: copy constructor // bbb.myTestFunc(aaa);
實(shí)際上是aaa作為參數(shù)傳遞給bbb.myTestFunc(CExample ex), 即CExample ex = aaa;和第四個(gè)一致的, 所以還是拷貝構(gòu)造函數(shù),而不是賦值函數(shù), 如果仍然不懂, 我的頭剛才已經(jīng)流血了,不要再讓我撞了,你就自己使勁的再裝一次吧。
通過(guò)這個(gè)例子, 我們來(lái)分析一下為什么拷貝構(gòu)造函數(shù)的參數(shù)只能使用引用類型。
看第四個(gè)輸出: copy constructor // CExample ccc = aaa;
構(gòu)造ccc,實(shí)質(zhì)上是ccc.CExample(aaa); 我們假如拷貝構(gòu)造函數(shù)參數(shù)不是引用類型的話, 那么將使得 ccc.CExample(aaa)變成aaa傳值給ccc.CExample(CExample ex),即CExample ex = aaa,因?yàn)?ex 沒(méi)有被初始化, 所以 CExample ex = aaa 繼續(xù)調(diào)用拷貝構(gòu)造函數(shù),接下來(lái)的是構(gòu)造ex,也就是 ex.CExample(aaa),必然又會(huì)有aaa傳給CExample(CExample ex), 即 CExample ex = aaa;那么又會(huì)觸發(fā)拷貝構(gòu)造函數(shù),就這下永遠(yuǎn)的遞歸下去。
所以繞了那么大的彎子,就是想說(shuō)明拷貝構(gòu)造函數(shù)的參數(shù)使用引用類型不是為了減少一次內(nèi)存拷貝, 而是避免拷貝構(gòu)造函數(shù)無(wú)限制的遞歸下去。
附帶說(shuō)明,在下面幾種情況下會(huì)調(diào)用拷貝構(gòu)造函數(shù):
a、顯式或隱式地用同類型的一個(gè)對(duì)象來(lái)初始化另外一個(gè)對(duì)象。如上例中,用對(duì)象c初始化d;
b、作為實(shí)參(argument)傳遞給一個(gè)函數(shù)。如CClass(const CClass c_class)中,就會(huì)調(diào)用CClass的拷貝構(gòu)造函數(shù);
c、在函數(shù)體內(nèi)返回一個(gè)對(duì)象時(shí),也會(huì)調(diào)用返回值類型的拷貝構(gòu)造函數(shù);
d、初始化序列容器中的元素時(shí)。比如 vector<string> svec(5),string的缺省構(gòu)造函數(shù)和拷貝構(gòu)造函數(shù)都會(huì)被調(diào)用;
e、用列表的方式初始化數(shù)組元素時(shí)。string a[] = {string(“hello”), string(“world”)}; 會(huì)調(diào)用string的拷貝構(gòu)造函數(shù)。
如果在沒(méi)有顯式聲明構(gòu)造函數(shù)的情況下,編譯器都會(huì)為一個(gè)類合成一個(gè)缺省的構(gòu)造函數(shù)。如果在一個(gè)類中聲明了一個(gè)構(gòu)造函數(shù),那么就會(huì)阻止編譯器為該類合成缺省的構(gòu)造函數(shù)。和構(gòu)造函數(shù)不同的是,即便定義了其他構(gòu)造函數(shù)(但沒(méi)有定義拷貝構(gòu)造函數(shù)),編譯器總是會(huì)為我們合成一個(gè)拷貝構(gòu)造函數(shù)。
另外函數(shù)的返回值是不是引用也有很大的區(qū)別,返回的不是引用的時(shí)候,只是一個(gè)簡(jiǎn)單的對(duì)象,此時(shí)需要調(diào)用拷貝構(gòu)造函數(shù),否則,如果是引用的話就不需要調(diào)用拷貝構(gòu)造函數(shù)。
#include<iostream>
using namespace std;
class A
{
private:
int m_nTest;
public:
A()
{
}
A(const A& other) //構(gòu)造函數(shù)重載
{
m_nTest = other.m_nTest;
cout << "copy constructor"<<endl;
}
A & operator =(const A& other)
{
if(this != &other)
{
m_nTest = other.m_nTest;
cout<<"Copy Assign"<<endl;
}
return *this;
}
};
A fun(A &x)
{
return x; //返回的不是引用的時(shí)候,需要調(diào)用拷貝構(gòu)造函數(shù)
}
int main(void)
{
A test;
fun(test);
system("pause");
return 0;
}
分享一道筆試題目,編譯運(yùn)行下圖中的C++代碼,結(jié)果是什么?(A)編譯錯(cuò)誤;(B)編譯成功,運(yùn)行時(shí)程序崩潰;(C)編譯運(yùn)行正常,輸出10。請(qǐng)選擇正確答案并分析原因。
class A
{
private:
int value;
public:
A(int n)
{
value = n;
}
A(A other)
{
value = other.value;
}
void Print()
{
cout<<value<<endl;
}
};
int main(void)
{
A a = 10;
A b = a;
b.Print();
return 0;
}
答案:編譯錯(cuò)誤。在復(fù)制構(gòu)造函數(shù)中傳入的參數(shù)是A的一個(gè)實(shí)例。由于是傳值,把形參拷貝到實(shí)參會(huì)調(diào)用復(fù)制構(gòu)造函數(shù)。因此如果允許復(fù)制構(gòu)造函數(shù)傳值,那么會(huì)形成永無(wú)休止的遞歸并造成棧溢出。因此C++的標(biāo)準(zhǔn)不允許復(fù)制構(gòu)造函數(shù)傳值參數(shù),而必須是傳引用或者常量引用。在Visual Studio和GCC中,都將編譯出錯(cuò)。
上一篇:深入C語(yǔ)言內(nèi)存區(qū)域分配(進(jìn)程的各個(gè)段)詳解
欄 目:C語(yǔ)言
本文標(biāo)題:c++中拷貝構(gòu)造函數(shù)的參數(shù)類型必須是引用
本文地址:http://mengdiqiu.com.cn/a1/Cyuyan/4308.html
您可能感興趣的文章
- 04-02func函數(shù)+在C語(yǔ)言 func函數(shù)在c語(yǔ)言中
- 04-02c語(yǔ)言中對(duì)數(shù)函數(shù)的表達(dá)式 c語(yǔ)言中對(duì)數(shù)怎么表達(dá)
- 04-02c語(yǔ)言沒(méi)有round函數(shù) round c語(yǔ)言
- 04-02C語(yǔ)言中怎么打出三角函數(shù) c語(yǔ)言中怎么打出三角函數(shù)的值
- 01-10深入理解C++中常見(jiàn)的關(guān)鍵字含義
- 01-10使用C++實(shí)現(xiàn)全排列算法的方法詳解
- 01-10深入Main函數(shù)中的參數(shù)argc,argv的使用詳解
- 01-10APUE筆記之:進(jìn)程環(huán)境詳解
- 01-10c++中inline的用法分析
- 01-10如何尋找數(shù)組中的第二大數(shù)


閱讀排行
- 1C語(yǔ)言 while語(yǔ)句的用法詳解
- 2java 實(shí)現(xiàn)簡(jiǎn)單圣誕樹的示例代碼(圣誕
- 3利用C語(yǔ)言實(shí)現(xiàn)“百馬百擔(dān)”問(wèn)題方法
- 4C語(yǔ)言中計(jì)算正弦的相關(guān)函數(shù)總結(jié)
- 5c語(yǔ)言計(jì)算三角形面積代碼
- 6什么是 WSH(腳本宿主)的詳細(xì)解釋
- 7C++ 中隨機(jī)函數(shù)random函數(shù)的使用方法
- 8正則表達(dá)式匹配各種特殊字符
- 9C語(yǔ)言十進(jìn)制轉(zhuǎn)二進(jìn)制代碼實(shí)例
- 10C語(yǔ)言查找數(shù)組里數(shù)字重復(fù)次數(shù)的方法
本欄相關(guān)
- 04-02c語(yǔ)言函數(shù)調(diào)用后清空內(nèi)存 c語(yǔ)言調(diào)用
- 04-02func函數(shù)+在C語(yǔ)言 func函數(shù)在c語(yǔ)言中
- 04-02c語(yǔ)言的正則匹配函數(shù) c語(yǔ)言正則表達(dá)
- 04-02c語(yǔ)言用函數(shù)寫分段 用c語(yǔ)言表示分段
- 04-02c語(yǔ)言中對(duì)數(shù)函數(shù)的表達(dá)式 c語(yǔ)言中對(duì)
- 04-02c語(yǔ)言編寫函數(shù)冒泡排序 c語(yǔ)言冒泡排
- 04-02c語(yǔ)言沒(méi)有round函數(shù) round c語(yǔ)言
- 04-02c語(yǔ)言分段函數(shù)怎么求 用c語(yǔ)言求分段
- 04-02C語(yǔ)言中怎么打出三角函數(shù) c語(yǔ)言中怎
- 04-02c語(yǔ)言調(diào)用函數(shù)求fibo C語(yǔ)言調(diào)用函數(shù)求
隨機(jī)閱讀
- 04-02jquery與jsp,用jquery
- 08-05dedecms(織夢(mèng))副欄目數(shù)量限制代碼修改
- 01-11ajax實(shí)現(xiàn)頁(yè)面的局部加載
- 01-10SublimeText編譯C開發(fā)環(huán)境設(shè)置
- 01-10使用C語(yǔ)言求解撲克牌的順子及n個(gè)骰子
- 01-10C#中split用法實(shí)例總結(jié)
- 01-10delphi制作wav文件的方法
- 08-05DEDE織夢(mèng)data目錄下的sessions文件夾有什
- 01-11Mac OSX 打開原生自帶讀寫NTFS功能(圖文
- 08-05織夢(mèng)dedecms什么時(shí)候用欄目交叉功能?