C++11——面向?qū)ο缶幊?/h1>

虛函數(shù)的override說明符

派生類經(jīng)常(但不總是)重寫它們繼承的虛函數(shù)。如果派生類沒有重寫其基類中的虛函數(shù)鳖轰,那么與任何其他成員一樣蕴侣,派生類繼承其基類中定義的版本臭觉。
派生類可以在其重寫的函數(shù)上包含關(guān)鍵字virtual,但編譯器并沒有對(duì)此進(jìn)行強(qiáng)制要求狞膘。新標(biāo)準(zhǔn)允許派生類明確指出它希望成員函數(shù)重寫它繼承的虛函數(shù)挽封。通過在參數(shù)列表之后指定override。如果成員是const或者引用和悦,則在const或引用限定符之后指定override鸽素。

Code:
    class Bulk_quote : public Quote { // Bulk_quote inherits from Quote
        Bulk_quote() = default;
        Bulk_quote(const std::string&, double, std::size_t, double);
        // overrides the base version of function 'net_price'
        double net_price(std::size_t) const override;
    private:
        std::size_t min_qty = 0; // minimum purchase for the discount to apply
        double discount = 0.0;   // fractional discount to apply
};

通過將類定義為final來阻止繼承

有時(shí)我們定義一個(gè)我們不希望其他人繼承的類亦鳞⊙嗖睿或者我們可以定義一個(gè)我們不想考慮它是否適合作為基類的類。根據(jù)新標(biāo)準(zhǔn)瓦呼,我們可以通過在類名之后使用關(guān)鍵字final來阻止類被用作基類:

Code:
    class NoDerived final { /*  */ };   // NoDerived can't be a base class
    class Base { /*  */ };
    // Last is final; we cannot inherit from Last
    class Last final : Base { /*  */ }; // Last can't be a base class
    class Bad : NoDerived { /*  */ };   // error: NoDerived is final
    class Bad2 : Last { /*  */ };       // error: Last is final

虛函數(shù)的override和final說明符

派生類定義一個(gè)與其基類中的虛擬同名但具有不同參數(shù)列表的函數(shù)是合法的央串。編譯器認(rèn)為這樣的函數(shù)獨(dú)立于基類函數(shù)碗啄。在這種情況下稚字,派生版本不會(huì)重寫基類中的版本。在實(shí)踐中瘫想,這樣的聲明通常是一個(gè)錯(cuò)誤昌讲,因?yàn)轭愖髡叽蛩銖幕愔貙懱摵瘮?shù)但在指定參數(shù)列表時(shí)出錯(cuò)剧蚣。
在新標(biāo)準(zhǔn)下,我們可以在派生類中的虛函數(shù)上指定override礼搁。這樣做可以讓我們的意圖變得清晰目尖,并且(更重要的是)讓編譯器為我們找到這些問題瑟曲。如果標(biāo)記為override的函數(shù)沒有重寫現(xiàn)有的虛函數(shù),編譯器將拒絕該程序:

Code:
    struct B {
        virtual void f1(int) const;
        virtual void f2();
        void f3();
    };
    struct D1 : B {
        void f1(int) const override; // ok: f1 matches f1 in the base
        void f2(int) override;       // error: B has no f2(int) function
        void f3() override;          // error: f3 not virtual
        void f4() override;          // error: B doesn't have a function named f4
    };

D1中扯罐,對(duì)f1指定override說明符是合法的歹河』ㄒ鳎基類和派生類中的f1都是const型成員衅澈,同時(shí)接收一個(gè)int參數(shù),返回類型為void经备。D1中的f1正確重寫了繼承自B的虛函數(shù)弄喘。
D1中聲明的f2沒有匹配B中的f2聲明甩牺,因?yàn)?code>B中定義的版本沒有參數(shù)而D1中定義的版本接收一個(gè)int參數(shù)贬派。因?yàn)槁暶鞑黄ヅ洌?code>D1中的f2沒有重寫B中的f2波桩;它是一個(gè)新的函數(shù)请敦,這個(gè)函數(shù)剛好重名。因?yàn)槲覀兺ㄟ^關(guān)鍵字override說明這是一個(gè)重寫基類中虛函數(shù)的成員函數(shù)撒穷,但是實(shí)際上它并沒有重寫裆熙,所以編譯器會(huì)產(chǎn)生一個(gè)錯(cuò)誤入录。
因?yàn)閮H有虛函數(shù)才能被重寫,編譯器也將拒絕D1中的f3凡桥,因?yàn)樵?code>B中這個(gè)函數(shù)不是虛函數(shù)蚀同,所以不能對(duì)其進(jìn)行重寫唤崭。同樣,f4也將產(chǎn)生一個(gè)錯(cuò)誤因?yàn)?code>B中沒有名字為f4的函數(shù)腕侄。
我們也可以指定一個(gè)函數(shù)為final冕杠。任何嘗試重寫聲明為final的函數(shù)都將被標(biāo)記為一個(gè)錯(cuò)誤:

Code:
    struct D2 : B {
        // inherits f2() and f3() from B and overrides f1(int)
        void f1(int) const final; // subsequent classes can't override f1 (int)
    };
    struct D3 : D2 {
        void f2();          // ok: overrides f2 inherited from the indirect base, B
        void f1(int) const; // error: D2 declared f2 as final
    };

finaloverride說明符出現(xiàn)在參數(shù)列表(包括任何const或引用限定符)之后和尾隨返回(trailing return type)之后分预。

刪除的拷貝控制和繼承

合成的默認(rèn)構(gòu)造函數(shù)或基類或派生類的任何拷貝控制成員可以被定義為已刪除薪捍。此外,定義基類的方式可能導(dǎo)致派生類成員被定義為已刪除:

  1. 如果基類中的默認(rèn)構(gòu)造函數(shù)凳干,拷貝構(gòu)造函數(shù)救赐,拷貝賦值運(yùn)算符或析構(gòu)函數(shù)被刪除或不可訪問只磷,則派生類中的相應(yīng)成員被定義為已刪除,因?yàn)榫幾g器無法使用用于構(gòu)造阿迈,賦值或銷毀對(duì)象的基類部分的基類成員配乓。
  2. 如果基類具有不可訪問或刪除的析構(gòu)函數(shù)犹芹,則派生類中的合成默認(rèn)構(gòu)造函數(shù)和拷貝構(gòu)造函數(shù)將被定義為已刪除鞠绰,因?yàn)闊o法銷毀派生對(duì)象的基部分。
  3. 像往常一樣蜈膨,編譯器不會(huì)合成已刪除的move操作屿笼。如果我們使用= default來請(qǐng)求move操作,那么如果基類中的相應(yīng)操作被刪除或不可訪問翁巍,它將是派生類中的已刪除函數(shù)驴一,因?yàn)榛惒糠譄o法移動(dòng)。如果基類析構(gòu)函數(shù)被刪除或無法訪問灶壶,也將刪除移動(dòng)構(gòu)造函數(shù)肝断。
Code:
    class B {
    public:
        B();
        B(const B&) = delete;
        // other members, not including a move constructor
    };
    class D : public B {
        // no constructors
    };
    D d;  // ok: D's synthesized default constructor uses B's default constructor
    D d2(d); // error: D's synthesized copy constructor is deleted
    D d3(std::move(d)); // error: implicitly uses D's deleted copy constructor

例如,此基類B具有可訪問的默認(rèn)構(gòu)造函數(shù)和顯式刪除的拷貝構(gòu)造函數(shù)驰凛。因?yàn)槎x了拷貝構(gòu)造函數(shù)胸懈,所以編譯器不會(huì)為B類合成移動(dòng)構(gòu)造函數(shù)恰响。因此趣钱,我們既不能移動(dòng)也不能復(fù)制B類對(duì)象。如果從B派生的類想要允許復(fù)制或移動(dòng)其對(duì)象胚宦,那么派生類必須定義這些構(gòu)造函數(shù)的自己版本首有。當(dāng)然,該類必須決定如何復(fù)制或移動(dòng)其基類部分中的成員枢劝。實(shí)際上绞灼,如果基類沒有默認(rèn),復(fù)制或移動(dòng)構(gòu)造函數(shù)呈野,那么它的派生類通常也不會(huì)有低矮。

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

在新標(biāo)準(zhǔn)下,派生類可以重用由其直接基類定義的構(gòu)造函數(shù)被冒。類可以僅初始化其直接基類军掂, 類可以僅從其直接基類繼承構(gòu)造函數(shù)轮蜕。類不能繼承默認(rèn),拷貝和移動(dòng)構(gòu)造函數(shù)蝗锥。如果派生類沒有直接定義這些構(gòu)造函數(shù)跃洛,則編譯器會(huì)像往常一樣合成它們。
派生類通過使用using聲明來繼承其基類構(gòu)造函數(shù)终议。作為示例汇竭,我們可以定義Bulk_quote類并繼承Disc_quote類的構(gòu)造函數(shù):

Code:
    class Bulk_quote : public Disc_quote {
    public:
        using Disc_quote::Disc_quote;   // inherit Disc_quote's constructors
        double net_price(std::size_t) const;
};

通常,using聲明僅在當(dāng)前作用域中使名稱可見穴张。當(dāng)應(yīng)用于構(gòu)造函數(shù)時(shí)细燎,using聲明會(huì)導(dǎo)致編譯器生成代碼。編譯器生成與基類中的各個(gè)構(gòu)造函數(shù)對(duì)應(yīng)的派生構(gòu)造函數(shù)皂甘。也就是說玻驻,對(duì)于基類中的每個(gè)構(gòu)造函數(shù),編譯器在派生類中生成具有相同參數(shù)列表的構(gòu)造函數(shù)偿枕。
這些由編譯器產(chǎn)生的構(gòu)造函數(shù)有如下形式:

    derived(parms) : base(args) { }

其中derived是派生類的名稱璧瞬,base是基類的名稱,parms是構(gòu)造函數(shù)的參數(shù)列表渐夸,args將派生構(gòu)造函數(shù)中的參數(shù)傳遞給基礎(chǔ)構(gòu)造函數(shù)嗤锉。在我們的Bulk_quote類中,繼承的構(gòu)造函數(shù)等價(jià)于:

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

如果派生類具有自己的任何數(shù)據(jù)成員墓塌,則默認(rèn)初始化這些成員档冬。

參考文獻(xiàn)

[1] Lippman S B , Josée Lajoie, Moo B E . C++ Primer (5th Edition)[J]. 2013.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者

  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市桃纯,隨后出現(xiàn)的幾起案子酷誓,更是在濱河造成了極大的恐慌,老刑警劉巖态坦,帶你破解...
    沈念sama閱讀 217,907評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件盐数,死亡現(xiàn)場離奇詭異,居然都是意外死亡伞梯,警方通過查閱死者的電腦和手機(jī)玫氢,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,987評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來谜诫,“玉大人漾峡,你說我怎么就攤上這事∮骺酰” “怎么了生逸?”我有些...
    開封第一講書人閱讀 164,298評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我槽袄,道長烙无,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,586評(píng)論 1 293
  • 正文 為了忘掉前任遍尺,我火速辦了婚禮截酷,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘乾戏。我一直安慰自己迂苛,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,633評(píng)論 6 392
  • 文/花漫 我一把揭開白布鼓择。 她就那樣靜靜地躺著三幻,像睡著了一般。 火紅的嫁衣襯著肌膚如雪惯退。 梳的紋絲不亂的頭發(fā)上赌髓,一...
    開封第一講書人閱讀 51,488評(píng)論 1 302
  • 那天从藤,我揣著相機(jī)與錄音催跪,去河邊找鬼。 笑死夷野,一個(gè)胖子當(dāng)著我的面吹牛懊蒸,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播悯搔,決...
    沈念sama閱讀 40,275評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼骑丸,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了妒貌?” 一聲冷哼從身側(cè)響起通危,我...
    開封第一講書人閱讀 39,176評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎灌曙,沒想到半個(gè)月后菊碟,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,619評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡在刺,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,819評(píng)論 3 336
  • 正文 我和宋清朗相戀三年逆害,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蚣驼。...
    茶點(diǎn)故事閱讀 39,932評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡魄幕,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出颖杏,到底是詐尸還是另有隱情纯陨,我是刑警寧澤,帶...
    沈念sama閱讀 35,655評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站队丝,受9級(jí)特大地震影響靡馁,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜机久,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,265評(píng)論 3 329
  • 文/蒙蒙 一臭墨、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧膘盖,春花似錦胧弛、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,871評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至软棺,卻和暖如春红竭,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背喘落。 一陣腳步聲響...
    開封第一講書人閱讀 32,994評(píng)論 1 269
  • 我被黑心中介騙來泰國打工茵宪, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人瘦棋。 一個(gè)月前我還...
    沈念sama閱讀 48,095評(píng)論 3 370
  • 正文 我出身青樓稀火,卻偏偏與公主長得像,于是被迫代替她去往敵國和親赌朋。 傳聞我的和親對(duì)象是個(gè)殘疾皇子凰狞,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,884評(píng)論 2 354

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