新聞中心

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

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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



評論


相關推薦

技術專區(qū)

關閉