C++ 復(fù)制控制之復(fù)制構(gòu)造函數(shù)的實現(xiàn)
C++類用三個特殊的成員函數(shù):復(fù)制構(gòu)造函數(shù)、賦值操作符和析構(gòu)函數(shù) 來決定類對象之間的初始化或賦值時發(fā)生什么。所謂的“復(fù)制控制”即通過這三個成員函數(shù)控制對象復(fù)制的過程
復(fù)制構(gòu)造函數(shù)首先是一個構(gòu)造函數(shù),它同所有其他的構(gòu)造函數(shù)一樣與類同名,沒有返回值。它有一個唯一的參數(shù)(錯誤),是該類類型的引用(一般將它聲明為const,源于用于賦值的對象一般不用改變它本身的值)。于是復(fù)制構(gòu)造函數(shù)的原型為:
class BOOK { public: BOOK(const BOOK& rhs); //構(gòu)造函數(shù)一 BOOK(string &name,float price = 0):_bookName(name),_price(price){}; //構(gòu)造函數(shù)二 BOOK():_price(0),_bookName(""){}; //構(gòu)造函數(shù)三 private: float _price ; string _bookName; //.... };
什么時候被調(diào)用
復(fù)制構(gòu)造函數(shù)在需要復(fù)制類對象的時候被調(diào)用,這些調(diào)用情況可以總結(jié)為:
根據(jù)一個同類型的對象顯示或隱式地初始化一個對象。
1.當(dāng)定義一個新對象并用一個同類型的對象對它進(jìn)行初始化的時候,將顯式使用復(fù)制構(gòu)造函數(shù),如:
BOOK book1; BOOK book2(book1);
當(dāng)將該類型的對象傳遞給函數(shù)或從函數(shù)返回該類型的對象時,將隱式地調(diào)用復(fù)制構(gòu)造函數(shù)。
1.作為值傳遞的實參傳遞給一個函數(shù)。
2.函數(shù)返回時復(fù)制一個對象。
3.初始化順序容器中的元素。
如:
vector<string> svec(5);
編譯器首先調(diào)用string類默認(rèn)構(gòu)造函數(shù)創(chuàng)建一個臨時值,再用復(fù)制構(gòu)造函數(shù)將臨時值復(fù)制到每一個元素。
1.根據(jù)元素初始化列表初始化數(shù)組元素。
如:
BOOK books[]={ string("book1"), string("book2"), string("book3"), BOOK() };
book數(shù)組的前三個元素將調(diào)用構(gòu)造函數(shù)二進(jìn)行隱式類型轉(zhuǎn)換(C++隱式類型轉(zhuǎn)換),然后調(diào)用復(fù)制構(gòu)造函數(shù)進(jìn)行數(shù)組元素的復(fù)制。如果類禁止隱式類型轉(zhuǎn)換(構(gòu)造函數(shù)使用了explicit聲明),或希望不指定實參或多個實參,需要使用完整的構(gòu)造函數(shù)語法,如數(shù)組最后一個元素的初始化。
如果沒有為類聲明復(fù)制構(gòu)造函數(shù)會怎樣
如果你沒有聲明一個復(fù)制構(gòu)造函數(shù),那么編譯器會給聲明一個。實際上,如果你自己沒有聲明,編譯器會為類聲明一個復(fù)制構(gòu)造函數(shù) ,一個賦值操作符以及一個析構(gòu)函數(shù),此外如果你沒有聲明任何構(gòu)造函數(shù)的話,編譯器也會為你聲明一個合成默認(rèn)構(gòu)造函數(shù)。(錯誤)所有這些編譯器自動生成的類成員函數(shù)皆為pubilc 且 inline。編譯器創(chuàng)建的復(fù)制構(gòu)造函數(shù)單純地將來源對象的每一個非static成員拷貝到目標(biāo)對象,這在很多時候是不能滿足類需求的,特別是類中含有指針時,這時候就需要我們自己來寫復(fù)制控制的三個特殊成員函數(shù)了。
編譯器合成的復(fù)制構(gòu)造函數(shù)做了什么
合成復(fù)制構(gòu)造函數(shù)的行為是:對每一個非static成員進(jìn)行逐個成員初始化。成員類型不同,初始化方式不一樣:
- 內(nèi)置類型(如int):直接復(fù)制值。
- 類類型:調(diào)用該類的復(fù)制構(gòu)造函數(shù)進(jìn)行復(fù)制。
- 數(shù)組:這個比較特殊,因為我們知道一般不能復(fù)制數(shù)組,但在類中,復(fù)制數(shù)組時合成復(fù)制構(gòu)造函數(shù)將復(fù)制數(shù)組的每一個值。
另外,合成復(fù)制構(gòu)造函數(shù)對類數(shù)據(jù)成員的初始化都是放在構(gòu)造函數(shù)初始化列表中進(jìn)行的。
禁止復(fù)制
如果我們想禁止某個類的復(fù)制行為,我們當(dāng)然不會想去定義一個復(fù)制構(gòu)造函數(shù),然而編譯器卻會自動為我們定義一個,那么到底該如何阻止一個類的復(fù)制行為呢?
我們可以將復(fù)制構(gòu)造函數(shù)定義為private,不允許用戶代碼復(fù)制該類類型的對象,若進(jìn)行復(fù)制將在編譯時發(fā)生錯誤。然而類的友元和成員仍可以進(jìn)行復(fù)制,解決辦法是我們可以聲明一個private復(fù)制構(gòu)造函數(shù)卻不進(jìn)行定義,類成員或友元進(jìn)行復(fù)制嘗試時,將在程序運(yùn)行時發(fā)生錯誤。
到此這篇關(guān)于C++ 復(fù)制控制之復(fù)制構(gòu)造函數(shù)的實現(xiàn)的文章就介紹到這了,更多相關(guān)C++ 復(fù)制構(gòu)造函數(shù)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
簡要對比C語言中的setgid()函數(shù)和setregid()函數(shù)
這篇文章主要介紹了C語言中的setgid()函數(shù)和setregid()函數(shù)的簡要對比,是C語言入門學(xué)習(xí)中的基礎(chǔ)知識,需要的朋友可以參考下2015-08-08Qt MQTT開發(fā)環(huán)境搭建的實現(xiàn)示例
本文主要介紹了Qt MQTT開發(fā)環(huán)境搭建的實現(xiàn)示例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-06-06Linux中使用C語言的fork()函數(shù)創(chuàng)建子進(jìn)程的實例教程
fork是一個在Linux系統(tǒng)環(huán)境下專有的函數(shù),現(xiàn)有的進(jìn)程調(diào)用fork后將會創(chuàng)建一個新的進(jìn)程,這里我們就來看一下Linux中使用C語言的fork()函數(shù)創(chuàng)建子進(jìn)程的實例教程2016-06-06Qt實現(xiàn)進(jìn)程界面之間的鼠標(biāo)焦點切換
這篇文章主要為大家詳細(xì)介紹了Qt實現(xiàn)進(jìn)程界面之間的鼠標(biāo)焦點切換,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2020-09-09