(十五)面向?qū)ο蟪绦蛟O(shè)計(Part3)

copy from(https://blog.csdn.net/billcyj/article/details/78888074)

15.7 構(gòu)造函數(shù)和拷貝控制

創(chuàng)建具篇、拷貝度迂、移動击狮、賦值和銷毀

15.7.1 虛析構(gòu)函數(shù)

繼承體系中的析構(gòu)函數(shù)應(yīng)該定義為虛函數(shù)。
以前說過今穿,定義了析構(gòu)函數(shù)就要定義拷貝和賦值沪袭,但這里基類的析構(gòu)函數(shù)是例外。

為什么?

保證可以動態(tài)分配繼承體系中的對象布疙。且delete時能執(zhí)行對應(yīng)的析構(gòu)函數(shù)。
若指針指向繼承體系中的某個類型愿卸,則可能出現(xiàn)指針的靜態(tài)類型和被刪除對象的動態(tài)類型不符合:
如:delete一個Quote*類型指針灵临,該指針指向Bulk_quote類型對象。那應(yīng)該執(zhí)行Bulk_quote的析構(gòu)函數(shù)趴荸。

virtual ~Quote()=default;

15.7.2 合成拷貝控制與繼承

  • 派生類中定義為刪除的拷貝控制與基類的關(guān)系
class B
{
public:
    B(); //默認(rèn)構(gòu)造函數(shù)聲明
    B(const B&) = delete; //定義為刪除的拷貝構(gòu)造函數(shù)
    //既然定義了拷貝構(gòu)造函數(shù)儒溉,就不會合成移動操作了
};
class D : public B
{
    //沒有聲明任何東西,只是單純繼承了B
};
D d; //正確:D的合成默認(rèn)構(gòu)造函數(shù)調(diào)用B的默認(rèn)構(gòu)造函數(shù)发钝,自己反正也沒成員
D d2(d); //錯誤:因為B的拷貝構(gòu)造函數(shù)是delete的顿涣,所以D的也是delete,無法被調(diào)用
 
  • 移動操作與繼承

移動操作:基類多有虛析構(gòu)函數(shù)酝豪,所以不會合成移動操作涛碑,如果確實需要,應(yīng)首先在基類中顯式定義孵淘,此時要同時顯式定義拷貝操作:

class Quote
{
public:
    Quote() = default; //強行合成默認(rèn)構(gòu)造函數(shù)

    Quote(const Quote&) = default; //拷貝構(gòu)造函數(shù)
    Quote(Quote&&) = default; //移動構(gòu)造函數(shù)
    Quote& operator=(const Quote&) = default; //拷貝賦值
    Quote& operator=(Quote&&) = default; //移動賦值

    virtual ~Quote() = default; //虛析構(gòu)函數(shù)
};

如此锌唾,Quote的派生類也會自動獲得合成的移動操作。

15.7.3 派生類的拷貝控制成員

派生類的拷貝和移動構(gòu)造函數(shù)在拷貝和移動自有成員的同時夺英,也要拷貝和移動基類部分晌涕,賦值運算符也類似。
而析構(gòu)函數(shù)只負(fù)責(zé)銷毀派生類自己分配的資源 基類部分自動銷毀

  • 定義派生類的拷貝或移動構(gòu)造函數(shù)
class Base
{

};
class D : public Base
{
//我們要拷貝或移動基類部分痛悯,就必須在派生類的構(gòu)造函數(shù)初始值列表中顯式調(diào)用
public:
    D(const D& d) : Base(d) {} //調(diào)用基類的拷貝構(gòu)造函數(shù)來拷貝基類部分
    //這兒比較特殊的是Base(d)會去匹配Base的拷貝構(gòu)造函數(shù)余黎,雖然人家其實接受B類型

    D(D&& d) : Base(std::move(d)){}
};
  • 派生類賦值運算符

也就是拷貝賦值和移動賦值。

D &D::operator=(const D &rhs)
{
    Base::operator=(rhs); //顯式地為基類部分賦值:(合成的或自定義的)基類的拷貝賦值運算符將釋
    //放掉左側(cè)對象的基類部分的舊值载萌,然后利用rhs為其賦一個新值
    //接下來為派生類自己的部分賦值(省略)
    return *this;
}

  • 派生類析構(gòu)函數(shù)

對象銷毀的順序與創(chuàng)建順序相反:派生類析構(gòu)函數(shù)先執(zhí)行惧财,然后執(zhí)行基類的析構(gòu)函數(shù)巡扇。
也就是,對直接基類部分拷貝后垮衷,再拷貝類本身的成員厅翔;銷毀本身后再銷毀基類,基類部分會自動銷毀搀突。

禁止在構(gòu)造或析構(gòu)函數(shù)中調(diào)用虛函數(shù)
假設(shè)我們在基類的構(gòu)造函數(shù)中調(diào)用派生類的某個函數(shù)去訪問其成員刀闷,這會派生類對象還沒構(gòu)建完成,怎么能訪問呢仰迁?于是甸昏,C++禁止了這種行為。

15.7.4 繼承的構(gòu)造函數(shù)

1.派生類類不能繼承基類的默認(rèn)構(gòu)造函數(shù)徐许、拷貝構(gòu)造函數(shù)施蜜、移動構(gòu)造函數(shù);
2.但派生類能夠重用其基類自定義的構(gòu)造函數(shù)雌隅;
3.派生類中的基類成員調(diào)用基類的構(gòu)造函數(shù)初始化翻默,派生類中的其他成員將被默認(rèn)初始化

class Bulk_quote : public Disc_quote
{
public:
    using Disc_quote::Disc_quote; //使用using繼承Disc_quote的構(gòu)造函數(shù)
};

把using放到構(gòu)造函數(shù)上時,using聲明語句將令編譯器產(chǎn)生代碼恰起,而且修械,編譯器會生成一個與基類對應(yīng)的派生類構(gòu)造函數(shù),針對上面的例子生成的派生類構(gòu)造函數(shù)如下

Bulk_quote(const string& book, double price, size_t qty, double disc) : Disc_quote(book, price, qty, disc) {}

  • 繼承的構(gòu)造函數(shù)的特點

1.構(gòu)造函數(shù)的using聲明不會改變該構(gòu)造函數(shù)的訪問級別
2.如果基類的構(gòu)造函數(shù)是explicit或constexpr的村缸,則繼承的構(gòu)造函數(shù)也是
3.當(dāng)一個基類構(gòu)造函數(shù)含有默認(rèn)實參,派生類將獲得多個繼承的構(gòu)造函數(shù)武氓,其中每個構(gòu)造函數(shù)分別忽略掉一個含有默認(rèn)實參的形參
另外梯皿,如果派生類自己又定義了一個和基類構(gòu)造函數(shù)具有相同參數(shù)列表的構(gòu)造函數(shù),那么基類的這個構(gòu)造函數(shù)不會被繼承县恕,就用派生類自己定義的就好了东羹,覆蓋了

15.8 容器與繼承

我們不能把具有繼承關(guān)系的多種類型的對象直接存放在容器中:

vector<Quote> basket;
basket.push_back(Bulk_quote("a", 50, 10, 0.25));

basket的元素是Quote對象,因此當(dāng)我們向其中添加Bulk_quote對象時忠烛,屬于派生類的部分會被忽略

容器中應(yīng)放置指針(最好是智能指針)而非對象

vector<shared_ptr<Quote>> basket;
basket.push_back(make_shared<Quote>("a", 50));
basket.push_back(make_shared<Quote>("b", 50, 10, 0.25));
cout << basket.back()->net_price(15) << endl; //打印折扣后的價格属提,這回派生類對象是完整的

基類的指針 則指向?qū)ο蟮膭討B(tài)類型可能是基類也可能是派生類

派生類應(yīng)反映與基類的Is A關(guān)系,公有派生類的對象應(yīng)該可以用在任何需要基類對象的地方美尸;類之間Has A則是包含成員的意思冤议。
對于C++面向?qū)ο蟮木幊虂碚f,并不是直接用對象师坎,用的是指針和引用恕酸。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市胯陋,隨后出現(xiàn)的幾起案子蕊温,更是在濱河造成了極大的恐慌袱箱,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,490評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件义矛,死亡現(xiàn)場離奇詭異发笔,居然都是意外死亡,警方通過查閱死者的電腦和手機凉翻,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,581評論 3 395
  • 文/潘曉璐 我一進店門了讨,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人噪矛,你說我怎么就攤上這事量蕊。” “怎么了艇挨?”我有些...
    開封第一講書人閱讀 165,830評論 0 356
  • 文/不壞的土叔 我叫張陵残炮,是天一觀的道長。 經(jīng)常有香客問我缩滨,道長势就,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,957評論 1 295
  • 正文 為了忘掉前任脉漏,我火速辦了婚禮苞冯,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘侧巨。我一直安慰自己舅锄,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,974評論 6 393
  • 文/花漫 我一把揭開白布司忱。 她就那樣靜靜地躺著皇忿,像睡著了一般。 火紅的嫁衣襯著肌膚如雪坦仍。 梳的紋絲不亂的頭發(fā)上鳍烁,一...
    開封第一講書人閱讀 51,754評論 1 307
  • 那天,我揣著相機與錄音繁扎,去河邊找鬼幔荒。 笑死,一個胖子當(dāng)著我的面吹牛梳玫,可吹牛的內(nèi)容都是我干的爹梁。 我是一名探鬼主播,決...
    沈念sama閱讀 40,464評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼提澎,長吁一口氣:“原來是場噩夢啊……” “哼卫键!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起虱朵,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤莉炉,失蹤者是張志新(化名)和其女友劉穎钓账,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體絮宁,經(jīng)...
    沈念sama閱讀 45,847評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡梆暮,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,995評論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了绍昂。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片啦粹。...
    茶點故事閱讀 40,137評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖窘游,靈堂內(nèi)的尸體忽然破棺而出唠椭,到底是詐尸還是另有隱情,我是刑警寧澤忍饰,帶...
    沈念sama閱讀 35,819評論 5 346
  • 正文 年R本政府宣布贪嫂,位于F島的核電站,受9級特大地震影響艾蓝,放射性物質(zhì)發(fā)生泄漏力崇。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,482評論 3 331
  • 文/蒙蒙 一赢织、第九天 我趴在偏房一處隱蔽的房頂上張望亮靴。 院中可真熱鬧,春花似錦于置、人聲如沸茧吊。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,023評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽搓侄。三九已至,卻和暖如春宪彩,著一層夾襖步出監(jiān)牢的瞬間休讳,已是汗流浹背讲婚。 一陣腳步聲響...
    開封第一講書人閱讀 33,149評論 1 272
  • 我被黑心中介騙來泰國打工尿孔, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人筹麸。 一個月前我還...
    沈念sama閱讀 48,409評論 3 373
  • 正文 我出身青樓活合,卻偏偏與公主長得像,于是被迫代替她去往敵國和親物赶。 傳聞我的和親對象是個殘疾皇子白指,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,086評論 2 355

推薦閱讀更多精彩內(nèi)容