日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

构造函数,拷贝构造函数,赋值函数

發(fā)布時(shí)間:2023/12/2 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 构造函数,拷贝构造函数,赋值函数 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

? ? C++中一般創(chuàng)建對(duì)象,拷貝或賦值的方式有構(gòu)造函數(shù),拷貝構(gòu)造函數(shù),賦值函數(shù)這三種方法。下面就詳細(xì)比較下三者之間的區(qū)別以及它們的具體實(shí)現(xiàn)

1.構(gòu)造函數(shù)

構(gòu)造函數(shù)是一種特殊的類成員函數(shù),是當(dāng)創(chuàng)建一個(gè)類的對(duì)象時(shí),它被調(diào)用來對(duì)類的數(shù)據(jù)成員進(jìn)行初始化和分配內(nèi)存。(構(gòu)造函數(shù)的命名必須和類名完全相同)

首先說一下一個(gè)C++的空類,編譯器會(huì)加入哪些默認(rèn)的成員函數(shù)

·默認(rèn)構(gòu)造函數(shù)和拷貝構(gòu)造函數(shù)

·析構(gòu)函數(shù)

·賦值函數(shù)(賦值運(yùn)算符)

·取值函數(shù)

**即使程序沒定義任何成員,編譯器也會(huì)插入以上的函數(shù)!?
?

注意:構(gòu)造函數(shù)可以被重載,可以多個(gè),可以帶參數(shù);

析構(gòu)函數(shù)只有一個(gè),不能被重載,不帶參數(shù)

?

而默認(rèn)構(gòu)造函數(shù)沒有參數(shù),它什么也不做。當(dāng)沒有重載無參構(gòu)造函數(shù)時(shí),

? A a就是通過默認(rèn)構(gòu)造函數(shù)來創(chuàng)建一個(gè)對(duì)象

下面代碼為構(gòu)造函數(shù)重載的實(shí)現(xiàn)

[cpp]?view plain?copy

  • <span?style="font-size:14px;">class?A??
  • {??
  • int?m_i;??
  • Public:??
  • ??A()???
  • {??
  • ?Cout<<”無參構(gòu)造函數(shù)”<<endl;??
  • }??
  • A(int?i):m_i(i)?{}??//初始化列表??
  • }</span>??

  • ?

    2.拷貝構(gòu)造函數(shù)

    ?

    拷貝構(gòu)造函數(shù)是C++獨(dú)有的,它是一種特殊的構(gòu)造函數(shù),用基于同一類的一個(gè)對(duì)象構(gòu)造和初始化另一個(gè)對(duì)象。

    當(dāng)沒有重載拷貝構(gòu)造函數(shù)時(shí),通過默認(rèn)拷貝構(gòu)造函數(shù)來創(chuàng)建一個(gè)對(duì)象

    A a;

    A b(a);

    A b=a; ?都是拷貝構(gòu)造函數(shù)來創(chuàng)建對(duì)象b

    強(qiáng)調(diào):這里b對(duì)象是不存在的,是用a 對(duì)象來構(gòu)造和初始化b的!!


    ?

    先說下什么時(shí)候拷貝構(gòu)造函數(shù)會(huì)被調(diào)用:

    在C++中,3種對(duì)象需要復(fù)制,此時(shí)拷貝構(gòu)造函數(shù)會(huì)被調(diào)用

    1)一個(gè)對(duì)象以值傳遞的方式傳入函數(shù)體

    2)一個(gè)對(duì)象以值傳遞的方式從函數(shù)返回

    3)一個(gè)對(duì)象需要通過另一個(gè)對(duì)象進(jìn)行初始化


    ?

    什么時(shí)候編譯器會(huì)生成默認(rèn)的拷貝構(gòu)造函數(shù):

    1)如果用戶沒有自定義拷貝構(gòu)造函數(shù),并且在代碼中使用到了拷貝構(gòu)造函數(shù),編譯器就會(huì)生成默認(rèn)的拷貝構(gòu)造函數(shù)。但如果用戶定義了拷貝構(gòu)造函數(shù),編譯器就不在生成。

    2)如果用戶定義了一個(gè)構(gòu)造函數(shù),但不是拷貝構(gòu)造函數(shù),而此時(shí)代碼中又用到了拷貝構(gòu)造函數(shù),那編譯器也會(huì)生成默認(rèn)的拷貝構(gòu)造函數(shù)。

    ?

    因?yàn)橄到y(tǒng)提供的默認(rèn)拷貝構(gòu)造函數(shù)工作方式是內(nèi)存拷貝,也就是淺拷貝。如果對(duì)象中用到了需要手動(dòng)釋放的對(duì)象,則會(huì)出現(xiàn)問題,這時(shí)就要手動(dòng)重載拷貝構(gòu)造函數(shù),實(shí)現(xiàn)深拷貝。

    下面說說深拷貝與淺拷貝:

    淺拷貝:如果復(fù)制的對(duì)象中引用了一個(gè)外部?jī)?nèi)容(例如分配在堆上的數(shù)據(jù)),那么在復(fù)制這個(gè)對(duì)象的時(shí)候,讓新舊兩個(gè)對(duì)象指向同一個(gè)外部?jī)?nèi)容,就是淺拷貝。(指針雖然復(fù)制了,但所指向的空間內(nèi)容并沒有復(fù)制,而是由兩個(gè)對(duì)象共用,兩個(gè)對(duì)象不獨(dú)立,刪除空間存在)

    深拷貝:如果在復(fù)制這個(gè)對(duì)象的時(shí)候?yàn)樾聦?duì)象制作了外部對(duì)象的獨(dú)立復(fù)制,就是深拷貝。


    ?

    拷貝構(gòu)造函數(shù)重載聲明如下:?
    ?

    A (const A&other)

    下面為拷貝構(gòu)造函數(shù)的實(shí)現(xiàn):

    [cpp]?view plain?copy

  • <span?style="font-size:14px;">class?A??
  • {??
  • ??int?m_i??
  • ??A(const?A&?other):m_i(other.m_i)??
  • {??
  • ??Cout<<”拷貝構(gòu)造函數(shù)”<<endl;??
  • }??
  • }</span>??

  • ?

    3.賦值函數(shù)

    當(dāng)一個(gè)類的對(duì)象向該類的另一個(gè)對(duì)象賦值時(shí),就會(huì)用到該類的賦值函數(shù)。

    當(dāng)沒有重載賦值函數(shù)(賦值運(yùn)算符)時(shí),通過默認(rèn)賦值函數(shù)來進(jìn)行賦值操作

    A a;

    A b;

    b=a;?

    強(qiáng)調(diào):這里a,b對(duì)象是已經(jīng)存在的,是用a 對(duì)象來賦值給b的!!


    ?

    賦值運(yùn)算的重載聲明如下:

    ?A& operator = (const A& other)


    ?

    通常大家會(huì)對(duì)拷貝構(gòu)造函數(shù)和賦值函數(shù)混淆,這兒仔細(xì)比較兩者的區(qū)別:

    1拷貝構(gòu)造函數(shù)是一個(gè)對(duì)象初始化一塊內(nèi)存區(qū)域,這塊內(nèi)存就是新對(duì)象的內(nèi)存區(qū),而賦值函數(shù)是對(duì)于一個(gè)已經(jīng)被初始化的對(duì)象來進(jìn)行賦值操作。

    [cpp]?view plain?copy

  • <span?style="font-size:14px;">class??A;??
  • A?a;??
  • A?b=a;???//調(diào)用拷貝構(gòu)造函數(shù)(b不存在)??
  • A?c(a)?;???//調(diào)用拷貝構(gòu)造函數(shù)??
  • ??
  • /****/??
  • ??
  • class??A;??
  • A?a;??
  • A?b;?????
  • b?=?a?;???//調(diào)用賦值函數(shù)(b存在)</span>??

  • ?

    2)一般來說在數(shù)據(jù)成員包含指針對(duì)象的時(shí)候,需要考慮兩種不同的處理需求:一種是復(fù)制指針對(duì)象,另一種是引用指針對(duì)象。拷貝構(gòu)造函數(shù)大多數(shù)情況下是復(fù)制,而賦值函數(shù)是引用對(duì)象

    3)實(shí)現(xiàn)不一樣。拷貝構(gòu)造函數(shù)首先是一個(gè)構(gòu)造函數(shù),它調(diào)用時(shí)候是通過參數(shù)的對(duì)象初始化產(chǎn)生一個(gè)對(duì)象。賦值函數(shù)則是把一個(gè)新的對(duì)象賦值給一個(gè)原有的對(duì)象,所以如果原來的對(duì)象中有內(nèi)存分配要先把內(nèi)存釋放掉,而且還要檢察一下兩個(gè)對(duì)象是不是同一個(gè)對(duì)象,如果是,不做任何操作,直接返回。(這些要點(diǎn)會(huì)在下面的String實(shí)現(xiàn)代碼中體現(xiàn))

    ?

    !!!如果不想寫拷貝構(gòu)造函數(shù)和賦值函數(shù),又不允許別人使用編譯器生成的缺省函數(shù),最簡(jiǎn)單的辦法是將拷貝構(gòu)造函數(shù)和賦值函數(shù)聲明為私有函數(shù),不用編寫代碼。如:

    [cpp]?view plain?copy

  • <span?style="font-size:14px;">class?A??
  • {??
  • ?private:??
  • ?A(const?A&?a);?//私有拷貝構(gòu)造函數(shù)??
  • ?A&?operate=(const?A&?a);?//私有賦值函數(shù)??
  • }</span>??

  • 如果程序這樣寫就會(huì)出錯(cuò):

    [cpp]?view plain?copy

  • <span?style="font-size:14px;">A?a;??
  • A?b(a);?//調(diào)用了私有拷貝構(gòu)造函數(shù),編譯出錯(cuò)??
  • ??
  • A?b;??
  • b=a;?//調(diào)用了私有賦值函數(shù),編譯出錯(cuò)</span>??

  • ?

    所以如果類定義中有指針或引用變量或?qū)ο?#xff0c;為了避免潛在錯(cuò)誤,最好重載拷貝構(gòu)造函數(shù)和賦值函數(shù)。


    ?

    下面以string類的實(shí)現(xiàn)為例,完整的寫了普通構(gòu)造函數(shù),拷貝構(gòu)造函數(shù),賦值函數(shù)的實(shí)現(xiàn)。String類的基本實(shí)現(xiàn)見我另一篇博文。

    [cpp]?view plain?copy

  • <span?style="font-size:14px;">String::String(const?char*?str)????//普通構(gòu)造函數(shù)??
  • ??
  • {??
  • ??
  • ?cout<<construct<<endl;??
  • ??
  • ?if(str==NULL)????????//如果str?NULL,就存一個(gè)空字符串“”??
  • ??
  • {??
  • ?m_string=new?char[1];??
  • ?*m_string?='\0';??
  • }??
  • ??
  • ?else??
  • ??
  • {??
  • ??
  • ??m_string=?new?char[strlen(str)+1]?;???//分配空間??
  • ??strcpy(m_string,str);??
  • ??
  • }??
  • ??
  • }??
  • ??
  • ???
  • String::String(const?String&other)???//拷貝構(gòu)造函數(shù)??
  • ??
  • {??
  • ?cout<<"copy?construct"<<endl;??
  • ?m_string=new?char[strlen(other.m_string)+1];?//分配空間并拷貝??
  • ?strcpy(m_string,other.m_string);??
  • }??
  • ??
  • String?&?String::operator=(const?String&?other)?//賦值運(yùn)算符??
  • {??
  • ?cout<<"operator?=funtion"<<endl?;??
  • ?if(this==&other)?//如果對(duì)象和other是用一個(gè)對(duì)象,直接返回本身??
  • ?{??
  • ??return?*this;??
  • ?}??
  • ?delete?[]m_string;?//先釋放原來的內(nèi)存??
  • ?m_string=?new?char[strlen(other.m_string)+1];??
  • ?strcpy(m_string,other.m_string);??
  • ?return?*?this;??
  • }</span>??

  • ?

    ?

    一句話記住三者:對(duì)象不存在,且沒用別的對(duì)象來初始化,就是調(diào)用了構(gòu)造函數(shù);

    ??????????????? 對(duì)象不存在,且用別的對(duì)象來初始化,就是拷貝構(gòu)造函數(shù)(上面說了三種用它的情況!)

    ???????????????? 對(duì)象存在,用別的對(duì)象來給它賦值,就是賦值函數(shù)。

    ?

    總結(jié)

    以上是生活随笔為你收集整理的构造函数,拷贝构造函数,赋值函数的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。