欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

c++中拷貝構(gòu)造函數(shù)的參數(shù)類型必須是引用

 更新時(shí)間:2013年07月16日 10:58:22   投稿:jingxian  
如果拷貝構(gòu)造函數(shù)中的參數(shù)不是一個(gè)引用,即形如CClass(const CClass c_class),那么就相當(dāng)于采用了傳值的方式(pass-by-value),而傳值的方式會(huì)調(diào)用該類的拷貝構(gòu)造函數(shù),從而造成無窮遞歸地調(diào)用拷貝構(gòu)造函數(shù)。因此拷貝構(gòu)造函數(shù)的參數(shù)必須是一個(gè)引用

在C++中, 構(gòu)造函數(shù),拷貝構(gòu)造函數(shù),析構(gòu)函數(shù)和賦值函數(shù)(賦值運(yùn)算符重載)是最基本不過的需要掌握的知識(shí)。 但是如果我問你“拷貝構(gòu)造函數(shù)的參數(shù)為什么必須使用引用類型?”這個(gè)問題, 你會(huì)怎么回答? 或許你會(huì)回答為了減少一次內(nèi)存拷貝? 很慚愧的是,我的第一感覺也是這么回答。不過還好,我思索一下以后,發(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ù),從而造成無窮遞歸地調(diào)用拷貝構(gòu)造函數(shù)。因此拷貝構(gòu)造函數(shù)的參數(shù)必須是一個(gè)引用。

需要澄清的是,傳指針其實(shí)也是傳值,如果上面的拷貝構(gòu)造函數(shù)寫成CClass(const CClass* c_class),也是不行的。事實(shí)上,只有傳引用不是傳值外,其他所有的傳遞方式都是傳值。
先從一個(gè)小例子開始:(自己測(cè)試一下自己看看這個(gè)程序的輸出是什么?)

復(fù)制代碼 代碼如下:

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

如果你的結(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è)得放到一塊說。 肯定會(huì)有人問為什么兩個(gè)不一致。原因是, bbb對(duì)象已經(jīng)實(shí)例化了,不需要構(gòu)造,此時(shí)只是將aaa賦值給bbb,只會(huì)調(diào)用賦值函數(shù),就這么簡(jiǎn)單,還不懂的話,撞墻去! 但是ccc還沒有實(shí)例化,因此調(diào)用的是拷貝構(gòu)造函數(shù),構(gòu)造出ccc,而不是賦值函數(shù),還不懂的話,我撞墻去?。?br />第五個(gè)輸出: copy constructor                      //  bbb.myTestFunc(aaa);
實(shí)際上是aaa作為參數(shù)傳遞給bbb.myTestFunc(CExample ex), 即CExample ex = aaa;和第四個(gè)一致的, 所以還是拷貝構(gòu)造函數(shù),而不是賦值函數(shù), 如果仍然不懂, 我的頭剛才已經(jīng)流血了,不要再讓我撞了,你就自己使勁的再裝一次吧。
通過這個(gè)例子, 我們來分析一下為什么拷貝構(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 沒有被初始化, 所以 CExample ex = aaa 繼續(xù)調(diào)用拷貝構(gòu)造函數(shù),接下來的是構(gòu)造ex,也就是 ex.CExample(aaa),必然又會(huì)有aaa傳給CExample(CExample ex), 即 CExample ex = aaa;那么又會(huì)觸發(fā)拷貝構(gòu)造函數(shù),就這下永遠(yuǎn)的遞歸下去。
所以繞了那么大的彎子,就是想說明拷貝構(gòu)造函數(shù)的參數(shù)使用引用類型不是為了減少一次內(nèi)存拷貝, 而是避免拷貝構(gòu)造函數(shù)無限制的遞歸下去。

附帶說明,在下面幾種情況下會(huì)調(diào)用拷貝構(gòu)造函數(shù):
a、顯式或隱式地用同類型的一個(gè)對(duì)象來初始化另外一個(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ù)。

如果在沒有顯式聲明構(gòu)造函數(shù)的情況下,編譯器都會(huì)為一個(gè)類合成一個(gè)缺省的構(gòu)造函數(shù)。如果在一個(gè)類中聲明了一個(gè)構(gòu)造函數(shù),那么就會(huì)阻止編譯器為該類合成缺省的構(gòu)造函數(shù)。和構(gòu)造函數(shù)不同的是,即便定義了其他構(gòu)造函數(shù)(但沒有定義拷貝構(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ù)。

復(fù)制代碼 代碼如下:

#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)選擇正確答案并分析原因。
復(fù)制代碼 代碼如下:

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ì)形成永無休止的遞歸并造成棧溢出。因此C++的標(biāo)準(zhǔn)不允許復(fù)制構(gòu)造函數(shù)傳值參數(shù),而必須是傳引用或者常量引用。在Visual Studio和GCC中,都將編譯出錯(cuò)。

相關(guān)文章

  • C++左值與右值,右值引用,移動(dòng)語義與完美轉(zhuǎn)發(fā)詳解

    C++左值與右值,右值引用,移動(dòng)語義與完美轉(zhuǎn)發(fā)詳解

    這篇文章主要為大家詳細(xì)介紹了Python實(shí)現(xiàn)學(xué)生成績(jī)管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-03-03
  • 基于c++計(jì)算矩形重疊面積代碼實(shí)例

    基于c++計(jì)算矩形重疊面積代碼實(shí)例

    這篇文章主要介紹了基于c++計(jì)算矩形重疊面積代碼實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-07-07
  • Qt sender()函數(shù)的具體使用

    Qt sender()函數(shù)的具體使用

    在處理信號(hào)時(shí),Qt提供了一個(gè)特殊的函數(shù)sender(),可以返回發(fā)送信號(hào)的對(duì)象指針,以實(shí)現(xiàn)更靈活的代碼邏輯,本文就來介紹一下Qt sender()函數(shù)的具體使用,感興趣的可以了解一下
    2024-01-01
  • 字符串的模式匹配詳解--BF算法與KMP算法

    字符串的模式匹配詳解--BF算法與KMP算法

    這篇文章記錄一下串里面的模式匹配,模式匹配,顧名思義就是給定一個(gè)被匹配的字符串,然后用一個(gè)字符串模式(模型)去匹配上面說的字符串,看后者是否在前者里面出現(xiàn)。常用的有2種算法可以實(shí)現(xiàn),下面我們來具體探討下
    2014-08-08
  • c++的構(gòu)造函數(shù)使用方式

    c++的構(gòu)造函數(shù)使用方式

    這篇文章主要介紹了c++的構(gòu)造函數(shù)使用方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-05-05
  • C語言數(shù)據(jù)在內(nèi)存中的存儲(chǔ)詳解

    C語言數(shù)據(jù)在內(nèi)存中的存儲(chǔ)詳解

    本篇文章是C語言編程篇,主要為大家介紹C語言編程中數(shù)據(jù)在內(nèi)存中存儲(chǔ)解析,有需要的朋友可以借鑒參考下,希望可以有所幫助
    2021-09-09
  • 十個(gè)C++惡搞朋友的代碼合集

    十個(gè)C++惡搞朋友的代碼合集

    這篇文章主要為大家整理了十個(gè)C++中可以惡搞朋友的代碼合集(注意!從第五個(gè)開始為危險(xiǎn)/永久性程序,請(qǐng)慎重使用),感興趣的小伙伴可以收藏一下
    2023-02-02
  • 總結(jié)C語言中const關(guān)鍵字的使用

    總結(jié)C語言中const關(guān)鍵字的使用

    一起雖然學(xué)過c語言,但是并沒有寫過太多的代碼,最近想要拾起c語言,就寫了一些代碼,但是對(duì)const關(guān)鍵字比較陌生,這里總結(jié)一下,方法自己和大家有需要的時(shí)候參考借鑒,下面跟著小編一起學(xué)習(xí)學(xué)習(xí)吧。
    2016-11-11
  • 詳解用C語言實(shí)現(xiàn)三子棋游戲流程

    詳解用C語言實(shí)現(xiàn)三子棋游戲流程

    三子棋是一種民間傳統(tǒng)游戲,又叫九宮棋、圈圈叉叉、一條龍、井字棋等。將正方形對(duì)角線連起來,相對(duì)兩邊依次擺上三個(gè)雙方棋子,只要將自己的三個(gè)棋子走成一條線,對(duì)方就算輸了
    2021-11-11
  • C++實(shí)現(xiàn)LeetCode(102.二叉樹層序遍歷)

    C++實(shí)現(xiàn)LeetCode(102.二叉樹層序遍歷)

    這篇文章主要介紹了C++實(shí)現(xiàn)LeetCode(102.二叉樹層序遍歷),本篇文章通過簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-07-07

最新評(píng)論