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