新聞中心

EEPW首頁(yè) > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > C++中復(fù)制構(gòu)造函數(shù)與重載賦值操作符的深入分析

C++中復(fù)制構(gòu)造函數(shù)與重載賦值操作符的深入分析

作者: 時(shí)間:2016-12-01 來源:網(wǎng)絡(luò) 收藏
C++++中復(fù)制控制是一個(gè)比較重要的話題,主要包括復(fù)制構(gòu)造函數(shù)重載賦值操作符、析構(gòu)函數(shù)這三部分,這三個(gè)函數(shù)是一致的,如果需要手動(dòng)定義了其中了一個(gè),那么另外的兩個(gè)也需要定義,通常在存在指針或者前期相關(guān)操作的情況下,都需要手動(dòng)的定義。復(fù)制構(gòu)造函數(shù)與重載賦值操作符實(shí)現(xiàn)的大題相同,如果沒有手動(dòng)的實(shí)現(xiàn),那么編譯器會(huì)自動(dòng)生成一個(gè),而且這兩個(gè)函數(shù)的參數(shù)也是一致的,是不能夠改變的,這是為什么呢?這是值得我們?nèi)シ治龊屯魄玫?。析?gòu)函數(shù)相比前面的兩個(gè)存在一個(gè)巨大的差別,就是無論我們是否定義這個(gè)函數(shù),編譯器都會(huì)自動(dòng)生成一個(gè)析構(gòu)函數(shù)。析構(gòu)函數(shù)我認(rèn)為主要是完成對(duì)象的釋放操作,我就不去仔細(xì)的分析啦。


我們現(xiàn)在著重來分析一下為什么復(fù)制構(gòu)造函數(shù)與重載賦值操作符在沒有定義的情況下,編譯器會(huì)為我們生成一個(gè),這說明這兩個(gè)函數(shù)是一個(gè)類必不可少的部分。由此可知如果一個(gè)類沒有定義任何的東西,編譯器也會(huì)幫助我們生成下面的4個(gè)函數(shù):1、一個(gè)構(gòu)造函數(shù),也就是所謂的類名比如classname(),這是在沒有定義構(gòu)造函數(shù)時(shí),編譯器會(huì)自動(dòng)生成的。2、析構(gòu)函數(shù),這個(gè)前面已經(jīng)提到了。3、復(fù)制構(gòu)造函數(shù)。4、重載賦值操作符。

為什么復(fù)制構(gòu)造函數(shù)和重載賦值操作符如此重要呢?

首先介紹一下復(fù)制構(gòu)造函數(shù)與重載賦值操作符的聲明形式,這兩個(gè)函數(shù)的參數(shù)是固定的,是不能改變的。假設(shè)存在一個(gè)類Base。那么它的這兩個(gè)函數(shù)聲明分別如下所示:

本文引用地址:http://m.butianyuan.cn/article/201612/324507.htm

class Base
{
public:
//構(gòu)造函數(shù)
Base();
//復(fù)制構(gòu)造函數(shù)
Base(const Base &);
//重載賦值操作符
Base &operator=(const Base &);
//析構(gòu)函數(shù)
~Base();
...
private:
...
};

面的形式可以知道,復(fù)制構(gòu)造函數(shù)與重載賦值操作符的參數(shù)是一致的,都是該類的const引用類型。為什么不能重載呢?這些都是存在的問題。我覺得要搞清楚這些問題,首先我們就不能只能片面的去理解,而是應(yīng)該對(duì)C++的面向?qū)ο缶幊逃辛艘粋€(gè)較好的理解以后再來分析這個(gè)問題。

么是引用,很多書上都會(huì)說是為了避免復(fù)制,這是其中的一個(gè)原因,如果說只是這個(gè)原因,完全可以只用指針就可以了,對(duì)于系統(tǒng)而言,不在乎多幾個(gè)指針的存儲(chǔ)空間。
首先說明一下在C++中的繼承問題,一般而言我們的繼承主要是指公共繼承,也就說如下的派生類定義所示:

class Derived : public Base
{
public:
...
private:
...
}

公共繼承而言,基類的公共部分成為了派生類的公共部分,私有部分成為了派生類的私有部分。也就是說派生類中包含基類的部分。也就是說在實(shí)現(xiàn)派生類的過程中,基類的公用接口會(huì)被派生類直接繼承。而基類的私有成員也作為派生類的私有成員。但是對(duì)于其他的繼承類型,我就不去討論啦。這時(shí)派生類的成員可以訪問到基類的私有成員。也就是說相當(dāng)于派生類是在基類的基礎(chǔ)上增加了自己的特色。

需要介紹一個(gè)問題就是采用派生類對(duì)象的引用初始化基類的引用。多態(tài)性的動(dòng)態(tài)綁定中存在兩個(gè)條件:1、必須是virtual函數(shù)(虛函數(shù)),2、必須是通過基類的引用或者基類的指針進(jìn)行成員虛函數(shù)的調(diào)用。
只有上面兩個(gè)條件滿足才能發(fā)生動(dòng)態(tài)調(diào)用問題。

由于派生類中存在基類的成員,也就相當(dāng)于一個(gè)派生類對(duì)象中包含了一個(gè)基類對(duì)象(我不知道這樣是否合理),所以可以采用一個(gè)基類引用來綁定一個(gè)派生類對(duì)象。引用實(shí)質(zhì)上是針對(duì)一塊內(nèi)存區(qū)域,引用是一個(gè)標(biāo)號(hào),是這塊內(nèi)存區(qū)域的一個(gè)名字,一個(gè)引用與一塊內(nèi)存區(qū)域綁定,因?yàn)榕缮鷮?duì)象中存在基類部分,可以認(rèn)為派生對(duì)象的區(qū)域中存在基類對(duì)象,這時(shí)可用基類的引用來表明這塊內(nèi)存區(qū)域,即采用一個(gè)基類的別名來表示(綁定)這段內(nèi)存區(qū)域,派生對(duì)象的地址(這段內(nèi)存)以及內(nèi)容都沒有發(fā)生改變,也沒有重現(xiàn)創(chuàng)造出一個(gè)新的對(duì)象,基類的引用還是指向這個(gè)派生對(duì)象。對(duì)于指針的分析方式相似。因此可以采用基類的引用綁定派生類對(duì)象。

但是如何實(shí)現(xiàn)派生類對(duì)象到基類的轉(zhuǎn)換呢?
這時(shí)候的轉(zhuǎn)換與前面的綁定存在很大的差別,因?yàn)檫@是重新分配一個(gè)基類對(duì)象,而不再是引用問題,不再是綁定問題,是依據(jù)一個(gè)派生類對(duì)象生成一個(gè)新的基類對(duì)象。因?yàn)榕缮悓?duì)象中存在一個(gè)基類對(duì)象基本的信息,完全可以生成一個(gè)基類對(duì)象,完全將此過程看作是一個(gè)初始化或者賦值的問題。也就是采用派生類創(chuàng)建一個(gè)新的對(duì)象或者賦值一個(gè)對(duì)象。
從上面的分析我們可以采用下面的形式來實(shí)現(xiàn):

Base(const Derived &);
Base &operator=(const Derived &);

是在基類函數(shù)中采用構(gòu)造函數(shù)基于派生類來重載一系列的構(gòu)造函數(shù),但是這也存在一個(gè)問題,如果存在很多派生類,這時(shí)候就要重載很多構(gòu)造函數(shù),這肯定不是我們需要的。

這時(shí)候是否發(fā)現(xiàn)與前面的問題關(guān)聯(lián)起來了?
這時(shí)候我們發(fā)現(xiàn)對(duì)于一個(gè)類而言,為什么復(fù)制構(gòu)造函數(shù)和重載賦值操作符這么重要了。因?yàn)檫@兩個(gè)函數(shù)都是接受一個(gè)基類的引用,根據(jù)前面的分析我們知道一個(gè)基類引用完全可以綁定一個(gè)派生類的對(duì)象,而派生類對(duì)象中又包含了一個(gè)基類對(duì)象的基本信息。我們能夠?qū)崿F(xiàn)一個(gè)從一個(gè)派生對(duì)象到基類的構(gòu)造過程。
我們用一個(gè)基類引用綁定一個(gè)派生對(duì)象,然后采用基類引用對(duì)基類成員進(jìn)行訪問,完成了一個(gè)基類對(duì)象基本要素的填充操作,相當(dāng)于完成了基類對(duì)象的創(chuàng)建,也就是構(gòu)造問題。這樣也就能完成由派生類對(duì)象到基類對(duì)象的構(gòu)造過程。
至于為什么是一個(gè)const的引用,我認(rèn)為主要是因?yàn)椴蝗バ薷呐缮悓?duì)象和擴(kuò)大能夠接受的參數(shù)情況,由const引用可以綁定不同類型的對(duì)象特性,說明const引用會(huì)擴(kuò)大接受實(shí)參的能力。

現(xiàn)在我可以總結(jié)起來說了,因?yàn)樵趶?fù)制構(gòu)造函數(shù)中,C++中的基類引用可以綁定一個(gè)派生類的對(duì)象,如果在允許訪問的情況下,采用基類引用可以訪問基類的成員以及派生類的其他成員,采用引用可以復(fù)制派生類對(duì)象中基類成員的值到新創(chuàng)建的基類成員中,完成一個(gè)基類成員數(shù)據(jù)的填充操作,這時(shí)候一個(gè)完整的基類對(duì)象就創(chuàng)建完成了。

重載賦值操作符則是發(fā)生在使用一個(gè)派生對(duì)象來賦值一個(gè)基類對(duì)象時(shí),這時(shí)候也是const基類引用綁定一個(gè)派生類對(duì)象,然后復(fù)制對(duì)應(yīng)的基類成員到基類對(duì)象對(duì)于的成員中,完成一個(gè)基類對(duì)象成員的更新操作。

來說,復(fù)制構(gòu)造函數(shù)不僅僅實(shí)現(xiàn)了同類型之間的初始化操作,同時(shí)也完成了采用一個(gè)派生類對(duì)象初始化一個(gè)基類對(duì)象的操作,重載賦值操作符實(shí)現(xiàn)了同類型之間的賦值操作,也完成了采用派生類對(duì)象賦值基類對(duì)象的操作。如果沒有這兩個(gè)函數(shù)的存在,也就不能完成派生類到基類的賦值和初始化操作。這也是為什么一定會(huì)存在這兩個(gè)函數(shù)的原因。



評(píng)論


相關(guān)推薦

技術(shù)專區(qū)

關(guān)閉