日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > c/c++ >内容正文

c/c++

C++学习笔记系列之继承多态

發(fā)布時(shí)間:2025/3/15 c/c++ 17 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C++学习笔记系列之继承多态 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

一、移動(dòng)語(yǔ)義

?


1、右值引用

?

? ? ?有一種機(jī)制,可以在語(yǔ)法層面識(shí)別出臨時(shí)對(duì)象,在使用臨時(shí)對(duì)象構(gòu)造新對(duì)象(拷貝構(gòu)造)的時(shí)候,將臨時(shí)對(duì)象所持有的資源『轉(zhuǎn)移』到新的對(duì)象中,就能消除這種不必要的拷貝。

?

2、左值和右值

? ? ?左值和右值都是針對(duì)表達(dá)式而言的, 左值是指表達(dá)式結(jié)束后依然存在的持久對(duì)象

????? 右值是指表達(dá)式結(jié)束時(shí)就不再存在的臨時(shí)對(duì)象

?????區(qū)分: 能對(duì)表達(dá)式進(jìn)行取地址,則為左值 否則為右值

?

  • 非const左值引用不能綁定到右值上
  • const左值引用能綁定到右值上
  • const左值引用同時(shí)可以綁定到左值上
  • 因此,const左值引用作為函數(shù)的形參時(shí),無(wú)法判斷傳過(guò)來(lái)的實(shí)參是左值還是右值

?

3、右值引用

?

  • 右值引用只能綁定到右值上,不能綁定到左值上。
  • 移動(dòng)構(gòu)造函數(shù),string( string ?&& rhs) ? ?右值引用。
  • 常量右值引用沒(méi)有現(xiàn)實(shí)意義(畢竟右值引用的初衷在于移動(dòng)語(yǔ)義,而移動(dòng)就意味著『修改』)。

?

4、移動(dòng)語(yǔ)義

?

  • 問(wèn)題:臨時(shí)對(duì)象,帶來(lái)的不必要的資源浪費(fèi)。
  • 需求:為了提高程序的執(zhí)行效率,需要直接將臨時(shí)對(duì)象的內(nèi)容直接轉(zhuǎn)移到新對(duì)象之中。
  • 問(wèn)題準(zhǔn)換: 需要在語(yǔ)法層面識(shí)別出一個(gè)臨時(shí)對(duì)象(右值)?

?

在C++11之前,只有const左值引用能夠綁定到右值,const int & ref = 10 ; 但是它也能綁定到左值,故當(dāng)const作為函數(shù)形參時(shí),實(shí)參不能區(qū)分是左值還是右值,故提出了----右值引用-->只能綁定到右值,

int && ref = 10 ;

?

String(String && rhs); ? ? //移動(dòng)構(gòu)造函數(shù)

String & operator=(String && rhs);//移動(dòng)賦值運(yùn)算符函數(shù)

?

  • std : : move函數(shù)的作用就是強(qiáng)制將一個(gè)左值轉(zhuǎn)換成右值引用。并且,具有移動(dòng)語(yǔ)義的函數(shù)會(huì)優(yōu)先執(zhí)行。
  • 使用移動(dòng)語(yǔ)義的特點(diǎn),該語(yǔ)句之后該對(duì)象不會(huì)再使用了。
  • 編譯器只對(duì)右值引用才能調(diào)用轉(zhuǎn)移構(gòu)造函數(shù)和轉(zhuǎn)移賦值函數(shù),而所有命名對(duì)象都只能是左值引用,如果已知一個(gè)命名對(duì)象不再被使用而想對(duì)它調(diào)用轉(zhuǎn)移構(gòu)造函數(shù)和轉(zhuǎn)移賦值函數(shù)。
  • 傳遞進(jìn)來(lái)的實(shí)參是右值,在函數(shù)體內(nèi)有了名字,就變成了左值。

?

5、資源管理 ---RAII

?

  • 利用對(duì)象生命周期管理程序資源(包括內(nèi)存、文件句柄、鎖等)的技術(shù)。
  • 關(guān)鍵:要保證資源的釋放順序與獲取順序嚴(yán)格相反
  • 在構(gòu)造時(shí)初始化資源, 或托管已構(gòu)造的資源
  • 析構(gòu)時(shí)釋放資源
  • 一般不允許復(fù)制或賦值(對(duì)象語(yǔ)義) - 值語(yǔ)義
  • 提供若干訪問(wèn)資源的方法

?

  • RAII的本質(zhì)是用?棧對(duì)象?來(lái)管理資源,因?yàn)闂?duì)象在離開作用域時(shí),會(huì)自動(dòng)調(diào)用析構(gòu)函數(shù)

?

6、資源管理---智能指針 ?RAII(Resource Acquisition Is Initialization) ??資源獲取即初始化時(shí)機(jī)

?

智能指針(Smart Pointer) ? ?--->利用棧對(duì)象來(lái)管理資源。

? ? ? ? ? 1、 是存儲(chǔ)指向動(dòng)態(tài)分配(堆)對(duì)象指針的類

? ? ? ? ? 2、在面對(duì)異常的時(shí)候格外有用,因?yàn)樗麄兡軌虼_保正確的銷毀動(dòng)態(tài)分配的對(duì)象

?

C++11提供了以下幾種智能指針,位于頭文件<memory>,它們都是類模板

?

  • auto_ptr ?被棄用的原因 --> 在語(yǔ)法上來(lái)說(shuō)是可以表達(dá)復(fù)制語(yǔ)義的,但實(shí)現(xiàn)上發(fā)生了所有權(quán)的轉(zhuǎn)移,該智能指針存在缺陷。
  • std::unique_pt
    • (獨(dú)享型--不能進(jìn)行復(fù)制或賦值 --> 即在它的內(nèi)里面沒(méi)有提供復(fù)制構(gòu)造函數(shù)和賦值運(yùn)算符函數(shù)),可以有移動(dòng)語(yǔ)義。具有移動(dòng)(std::move)語(yǔ)義(即提供了移動(dòng)構(gòu)造函數(shù)和移動(dòng)賦值運(yùn)算符函數(shù)),可做為容器元素 時(shí)(需要用移動(dòng)語(yǔ)義方式添加元素,添加完后,原對(duì)象不再被使用),可以指定自定義的刪除器。
  • std::shared_ptr? c++11
    • 共享型,能復(fù)制和賦值
    • 從語(yǔ)義上來(lái)講,可以將對(duì)象語(yǔ)義(不能被復(fù)制或賦值)準(zhǔn)換成值語(yǔ)義(就是能夠被復(fù)制和賦值)。
      • ifstream ifs; ?本身不能復(fù)制
      • shared_ptr<ifstream> sp(&ifs);
      • shared_ptr<ifstream> sp2(sp); //可以復(fù)制了。
    • shared_ptr是一個(gè)引用計(jì)數(shù)智能指針,用于共享對(duì)象的所有權(quán)
    • 1.引進(jìn)了一個(gè)計(jì)數(shù)器shared_count,用來(lái)表示當(dāng)前有多少個(gè)智能指針對(duì)象共享指針指向的內(nèi)存塊
    • 2.析構(gòu)函數(shù)中不是直接釋放指針對(duì)應(yīng)的內(nèi)存塊,如果shared_count大于0則不釋放內(nèi)存只是將引用計(jì)數(shù)減1,只有計(jì)數(shù)等于0時(shí)釋放內(nèi)存
    • 3.復(fù)制構(gòu)造與賦值操作符只是提供一般意義上的復(fù)制功能,并且將引用計(jì)數(shù)加1.
    • 問(wèn)題:循環(huán)引用(可能發(fā)生內(nèi)存泄漏? --->通過(guò)weak_ptr 解決

?

? ? ? ? ? ? ??

?

?

  • std::weak_ptr? ? c++11
    • 為了解決循環(huán)引用問(wèn)題而誕生
    • std::shared_ptr是強(qiáng)引用智能指針
    • std::weak_ptr 是弱引用智能指針
    • 強(qiáng)引用,只要有一個(gè)引用存在,對(duì)象就不能被釋放
    • 弱引用,并不增加對(duì)象的引用計(jì)數(shù),但它只知道對(duì)象是否存在。
    • 如果存在,提升為shared_ptr成功,提升操作由lock方法完成;否則,提升失敗
    • 通過(guò)weak_ptr訪問(wèn)對(duì)象的成員的時(shí)候,要提升為shared_ptr
  • shared_ptr的誤用

?

  • 1、同時(shí)將一個(gè)原生的裸指針交給不同的智能指針進(jìn)行托管。
    • Point *pt = new Point(1,2); ? ? std::shared_ptr<Point> p1(pt);//在類之外對(duì)對(duì)象進(jìn)行托管 ??

? ? ? ?? std::shared_ptr<Point> p2(pt);

  • 2、
    • shared_ptr<Point> p1(new Point(1, 2)); ??

? ? ?? shared_ptr<Point> p2(new Point(3, 4)); ??

? ? ? ? p2.reset(p1.get());

?

class std::enable_shared_from_this 方法shared_from_this()

?

  • g++ -std=c++11 xx.cc


二 、繼承與派生

?


?

1、繼承的概念:

?

? ? ? 在既有類的基礎(chǔ)上定義新的類,而不用將既有類的內(nèi)容重新書寫一遍,這稱為“繼承”(inheritance),既有類稱為“基類”或“父類”,在它的基礎(chǔ)上建立的類稱為“派生類”或“子類 。

? ? ?

?????MFC已經(jīng)被微軟棄用。

?????ABC的時(shí)代 ? ? ? ? ?A ? ----> ? 人工智能AI

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? B ? ----> ? ?Big ?Data

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? C ? ----> ? ?云的時(shí)代

盡量向這些內(nèi)容上靠。

?

2、繼承的定義形式

? ? ?

? ? ?class 派生類 : 派生方式 基類 {…};? ? //public, protected, private

?????派生類生成過(guò)程包含3個(gè)步驟:

    • 吸收基類的成員
    • 改造基類的成員
    • 添加自己新的成員

?????

3、不能被繼承(繼承的局限性)

? ? ?

    • 構(gòu)造函數(shù)
    • 析構(gòu)函數(shù)
    • 用戶重載的new 、delete運(yùn)算符 ? ? ? ? ? ? ?
      • operator new /operator delete
    • 用戶重載的=運(yùn)算符 ? ? (對(duì)象的復(fù)制)
    • 友元關(guān)系(單向性,不具備傳遞性) ? ?

?

  • 繼承時(shí),若不寫關(guān)鍵字,默認(rèn)私有繼承。
  • 保護(hù)成員不能直接通過(guò)對(duì)象進(jìn)行訪問(wèn),但是它對(duì)其子類、派生類進(jìn)行開放
  • 無(wú)論何種繼承,基類的私有成員都不能在派生類內(nèi)部直接訪問(wèn)。
  • 采用public的繼承方式稱為接口繼承。privated的繼承方式叫實(shí)現(xiàn)繼承。protected的繼承稱保護(hù)繼承。
  • 采用的protected進(jìn)行繼承時(shí),除了基類的private成員不能在派生類直接訪問(wèn)外,其他成員都可以在類內(nèi)部直接訪問(wèn)?;恜ublic成員在派生類內(nèi)部變成了protected了
  • protected繼承時(shí),除了基類的私有成員在整個(gè)繼承體系中不能直接訪問(wèn)外,其他的非私有成員都可以在派生類內(nèi)部進(jìn)行訪問(wèn)。
  • 派生類只有一個(gè)基類時(shí),稱為單基派生,在實(shí)際運(yùn)用中,C++同時(shí)支持多個(gè)基類,這種方法稱為多基派生或多重繼承。
    • class 派生類名:繼承方式1 基類名1,繼承方式2 基類名2,…,繼承方式n 基類名n { private: ??
      • 新增私有成員列表;
      • public: ??
      • 新增公開成員列表;
      • };
  • 成員名的二義性 ? ----> 作用域限定符 ?::
  • 對(duì)于存儲(chǔ)二義性,采用虛擬繼承解決, ? ? ? ? ? ? ? ? class C: virtual public A

?

?

? ? ? ? ? ? ? ? ? ?

?

重要基礎(chǔ): ?---> ?三種繼承方式的訪問(wèn)權(quán)限

?

  • 對(duì)于派生類創(chuàng)建的對(duì)象,只有調(diào)用通過(guò)pubic繼承的基類的public的成員,其他情況都不能訪問(wèn)
  • 對(duì)于基類的私有成員,無(wú)論以何種方式進(jìn)行繼承,在派生類內(nèi)都不能訪問(wèn)。
  • 對(duì)于基類的非私有成員,不論以何種方式繼承,在派生類內(nèi)部都能直接訪問(wèn)。
  • 如果派生類采用了私有繼承,其基類的非私有成員在這一層級(jí)的訪問(wèn)權(quán)限就變成private,之后的派生類均不能再雷內(nèi)部直接訪問(wèn)頂層內(nèi)部的非私有成員,如果才用的protected繼承,在繼承體系之中一直都可以訪問(wèn)基類的非私有成員。

?

?

4、派生類的構(gòu)造和銷毀

?

派生類對(duì)象的創(chuàng)建總原則: 先完成基類部分的初始化,在完成派生類的初始化。

?

  • 派生時(shí),構(gòu)造函數(shù)和析構(gòu)函數(shù)是不能繼承的,構(gòu)造時(shí),先基類在派生類。
  • 系統(tǒng)首先通過(guò)派生類的構(gòu)造函數(shù)來(lái)調(diào)用基類的構(gòu)造函數(shù),完成基類成員的初始化,而后對(duì)派生類中新增的成員進(jìn)行初始化。
  • 如果派生類沒(méi)有顯式定義構(gòu)造函數(shù)而基類有,則基類必須擁有默認(rèn)構(gòu)造函數(shù)。
  • 當(dāng)派生類有顯示定義構(gòu)造函數(shù)時(shí),基類部分的初始化,如果你想調(diào)用基類的有參構(gòu)造函數(shù),必須要在派生類構(gòu)造函數(shù)的初始化列表中顯式調(diào)用基類的有參構(gòu)造函數(shù)。
  • 調(diào)用順序?yàn)?#xff1a;
    • 完成對(duì)象所占整塊內(nèi)存的開辟,由系統(tǒng)在調(diào)用構(gòu)造函數(shù)時(shí)自動(dòng)完成。
    • 調(diào)用基類的構(gòu)造函數(shù)完成基類成員的初始化。
    • 若派生類中含對(duì)象成員、const成員或引用成員,則必須在初始化表中完成其初始化。
    • 派生類構(gòu)造函數(shù)體執(zhí)行。
  • 隱藏機(jī)制,當(dāng)派生類與基類有同名函數(shù)時(shí),基類的同名函數(shù)會(huì)被隱藏,只會(huì)執(zhí)行派生類的同名函數(shù),即使,基類的參數(shù)有變化,也會(huì)被隱藏。可以通過(guò)加上域名限定符,來(lái)調(diào)用被隱藏的基類成員函數(shù)。

?

5、派生類的析構(gòu)

?

  • 當(dāng)對(duì)象被刪除時(shí),派生類的析構(gòu)函數(shù)被執(zhí)行。析構(gòu)函數(shù)同樣不能繼承。
  • 在執(zhí)行派生類析構(gòu)函數(shù)時(shí),基類析構(gòu)函數(shù)會(huì)被自動(dòng)調(diào)用(與虛函數(shù))。
  • 執(zhí)行順序是先執(zhí)行派生類的析構(gòu)函數(shù),再執(zhí)行基類的析構(gòu)函數(shù),這和執(zhí)行構(gòu)造函數(shù)時(shí)的順序正好相反。

?

6、多基派生類

?

  • 各基類構(gòu)造函數(shù)的執(zhí)行順序與其在初始化表中的順序無(wú)關(guān),而是由定義派生類時(shí)繼承指定的基類順序決定的。
  • 析構(gòu)函數(shù)的執(zhí)行順序同樣是與構(gòu)造函數(shù)的執(zhí)行順序相反。
  • 覆蓋:
    • oversee? 隱藏:父子類,函數(shù)名稱相同,不帶 ? ? ? ? ? ? ? ? ? virtual關(guān)鍵字的函數(shù)
      • 2個(gè)函數(shù)參數(shù)相同,但基類函數(shù)不是虛函數(shù)。若是虛函數(shù),并且通過(guò)對(duì)象名去調(diào)用的時(shí)候,也可以認(rèn)為是隱藏,通過(guò)指針或引用去調(diào)用,叫覆蓋。
      • 2個(gè)函數(shù)參數(shù)不同,無(wú)論基類函數(shù)是否是虛函數(shù),基類函數(shù)都會(huì)被屏蔽。
    • override ?覆蓋:父子類,函數(shù)的名稱、返回值 ? ? ? ? ? ? ? ? ?類型、參數(shù)的類型個(gè)數(shù)都相同有virtual關(guān)鍵字
    • overload ?重載:同一個(gè)類,函數(shù)名稱相同,參 ? ? ? ? ? ? ? ? ? 數(shù)不同(類型,順序,個(gè)數(shù))

?

7、基類與派生類對(duì)象間的相互轉(zhuǎn)換

?

  • 可以把派生類的對(duì)象賦值給基類的對(duì)象
  • 可以把派生類的對(duì)象賦值給基類的引用
  • 可以聲明基類的指針指向派生類的對(duì)象 (向上轉(zhuǎn)型)
    • 向下轉(zhuǎn)型:一般不能進(jìn)行,只有當(dāng)sizeof(基類) == sizeof (派生類)

? ??

?????也就是說(shuō)如果函數(shù)的形參是基類對(duì)象或者基類對(duì)象的引用或者基類對(duì)象的指針類型,在進(jìn)行函數(shù)調(diào)用時(shí),相應(yīng)的實(shí)參可以是派生類對(duì)象 。

?

  • 如果用戶定義了基類的拷貝構(gòu)造函數(shù)或者賦值運(yùn)算符=,而沒(méi)有顯式定義派生類的拷貝構(gòu)造函數(shù),那么在用一個(gè)派生類對(duì)象初始化新的派生類對(duì)象時(shí),兩對(duì)象間的派生類部分執(zhí)行缺省的行為,而兩對(duì)象間的基類部分執(zhí)行用戶定義的基類拷貝構(gòu)造函數(shù)。
  • 定義了派生類有顯式定義拷貝構(gòu)造函數(shù)或者重載了派生類的對(duì)象賦值運(yùn)算符=,而基類也有顯式定義,派生類對(duì)象初始化新的派生類,或者在派生類對(duì)象間賦值時(shí),只會(huì)調(diào)用派生類的拷貝構(gòu)造函數(shù)或者重載賦值函數(shù),而不會(huì)再自動(dòng)調(diào)用基類的拷貝構(gòu)造函數(shù)和基類的重載對(duì)象賦值運(yùn)算符,只有顯式調(diào)用基類的拷貝構(gòu)造或賦值運(yùn)算符函數(shù)。

?

二 、多態(tài)

?


?

1、概述

?

? ? ?通常是指對(duì)于同一個(gè)消息、同一種調(diào)用,在不同的場(chǎng)合,不同的情況下,執(zhí)行不同的行為 。

?

2、分類

?

? ? ?靜態(tài)多態(tài)性, 和動(dòng)態(tài)多態(tài)性。

? ?? 靜態(tài)多態(tài)性?:函數(shù)重載和運(yùn)算符重載。編譯器可以在編譯過(guò)程中完成這種聯(lián)編。

? ?? 動(dòng)態(tài)多態(tài)性:在程序運(yùn)行時(shí)完成選擇,通過(guò)虛函數(shù)來(lái)實(shí)現(xiàn)動(dòng)態(tài)聯(lián)編。 ? 繼承 + 虛函數(shù) ?--->實(shí)現(xiàn)

?

3、虛函數(shù) ? ---> 通過(guò)虛(函數(shù))表 實(shí)現(xiàn)

?

  • 函數(shù)原型前加一個(gè)關(guān)鍵字virtual即可。當(dāng)成員函數(shù)成為虛函數(shù)后,則該對(duì)象的存數(shù)布局就會(huì)多一個(gè)虛函數(shù)指針,它指向一個(gè)虛函數(shù)表,表中存放虛函數(shù)入口地址。
  • 如果一個(gè)基類的成員函數(shù)定義為虛函數(shù),那么,它在所有派生類中也保持為虛函數(shù);即使在派生類中省略了virtual關(guān)鍵字,也仍然是虛函數(shù)。
  • 虛函數(shù)的作用:
    • 不加virtual時(shí),具體調(diào)用哪個(gè)版本的disp()只取決于指針本身的類型,和指針?biāo)笇?duì)象的類型無(wú)關(guān)。
    • 而加virtual時(shí),具體調(diào)用哪個(gè)版本的disp()不再取決于指針本身的類型,而是取決于指針?biāo)笇?duì)象的類型。
  • 派生類重定義虛函數(shù)格式
    • 與基類的虛函數(shù)有相同的參數(shù)個(gè)數(shù);
    • 與基類的虛函數(shù)有相同的參數(shù)類型;
    • 與基類的虛函數(shù)有相同的返回類型。
  • 虛函數(shù)的訪問(wèn)
    • 通過(guò)對(duì)象名調(diào)用虛函數(shù),不會(huì)展現(xiàn)虛函數(shù)的性質(zhì),此時(shí)虛函數(shù)退化成一個(gè)普通函數(shù),直接通過(guò)函數(shù)名去訪問(wèn)。靜態(tài)聯(lián)編。
    • 使用指針訪問(wèn)非虛函數(shù)時(shí),編譯器根據(jù)指針本身的類型決定要調(diào)用哪個(gè)函數(shù),而不是根據(jù)指針指向的對(duì)象類型;
    • 使用指針訪問(wèn)? 虛函數(shù)時(shí),編譯器根據(jù)指針?biāo)笇?duì)象的類型決定要調(diào)用哪個(gè)函數(shù)(動(dòng)態(tài)聯(lián)編),而與指針本身的類型無(wú)關(guān)。
    • 引用訪問(wèn)類似。
    • 在類內(nèi)的非虛函數(shù)成員函數(shù)中訪問(wèn)該類層次中的虛函數(shù),采用動(dòng)態(tài)聯(lián)編,要使用this指針。
    • 構(gòu)造函數(shù)和析構(gòu)函數(shù)是特殊的成員函數(shù),在其中訪問(wèn)虛函數(shù)時(shí),C++采用靜態(tài)聯(lián)編。即它們所調(diào)用的虛函數(shù)是自己類中定義的函數(shù),如果在自己的類中沒(méi)有實(shí)現(xiàn)該函數(shù),則調(diào)用的是基類中的虛函數(shù)。但絕不會(huì)調(diào)用任何在派生類中重定義的虛函數(shù)。

?

4、虛函數(shù)指針

? ? ? ? ??

  • 如果類中包含有虛成員函數(shù),在用該類實(shí)例化對(duì)象時(shí),對(duì)象的第一個(gè)成員將是一個(gè)指向虛函數(shù)表(vftable)的指針(vfptr)。虛函數(shù)表記錄運(yùn)行過(guò)程中實(shí)際應(yīng)該調(diào)用的虛函數(shù)的入口地址。

?

?

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

?

  • 動(dòng)態(tài)多態(tài)性(虛函數(shù)機(jī)制)被激活的條件
    • 基類要定義一個(gè)虛函數(shù)
    • 派生類要覆蓋該虛函數(shù)
    • 通過(guò)基類的指針或者引用指向派生類對(duì)象
    • 該指針或引用調(diào)用虛函數(shù)。

?

  • 在構(gòu)造函數(shù)或析構(gòu)函數(shù)之中調(diào)用虛函數(shù)才用的是靜態(tài)聯(lián)編。
  • 構(gòu)造函數(shù)為什么不能是虛函數(shù)?
    • 答:根據(jù)虛函數(shù)的使用條件來(lái)說(shuō),只有先創(chuàng)建對(duì)象,在對(duì)象創(chuàng)建的過(guò)程之中才有了虛函數(shù)指針(vfptr),然后才能通過(guò)它去調(diào)用虛函數(shù)。故虛函數(shù)的使用時(shí)建立在對(duì)象的創(chuàng)建,及構(gòu)造函數(shù)之后的。

?

?

5、純虛函數(shù)與抽象類

?

  • 首先必須是成員函數(shù), 沒(méi)有給出實(shí)現(xiàn)的函數(shù),用作借口。定義了純虛函數(shù)的類成為抽象類,不能實(shí)例化。其實(shí)現(xiàn)交給派生類實(shí)現(xiàn),若有多個(gè)純虛函數(shù),須全部實(shí)現(xiàn),否則,該派生類也是抽象類。 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 形式:? ??返回值類型 ?函數(shù)名(函數(shù)參數(shù)) = 0
  • 當(dāng)在基類中無(wú)法為虛函數(shù)提供任何有實(shí)際意義的定義時(shí),可以將該虛函數(shù)聲明為純虛函數(shù),它的實(shí)現(xiàn)留給該基類的派生類去做。

?

class 類名

{

?????virtual 類型 函數(shù)名 (參數(shù)表)=0;

????? …

};

?

    • 純虛函數(shù)不能被直接調(diào)用創(chuàng)建對(duì)象,僅提供一個(gè)與派生類一致的接口。
    • 一個(gè)類可以包含多個(gè)純虛函數(shù)。只要類中含有一個(gè)純虛函數(shù),該類便為抽象類。一個(gè)抽象類只能作為基類來(lái)派生新類,不能創(chuàng)建抽象類的對(duì)象,但可聲明一個(gè)指向抽象類的指針。
    • 擁有純虛函數(shù)的累稱為抽象類
    • 使用多態(tài)
      • 繼承 + ?虛函數(shù) ? 實(shí)現(xiàn)多態(tài)(面向?qū)ο蟮木幊?#xff09;
      • bind + function ? 實(shí)現(xiàn)多態(tài)(基于對(duì)象的編程方式) ? --> function/bind 的救贖
  • 只定義了protected型構(gòu)造函數(shù)的類也是抽象類,不能直接實(shí)例化的類。
  • 構(gòu)造函數(shù)不能被定義成虛函數(shù),但析構(gòu)函數(shù)可以定義為虛函數(shù),一般來(lái)說(shuō),如果類中定義了虛函數(shù),析構(gòu)函數(shù)也應(yīng)被定義為虛析構(gòu)函數(shù),尤其是類內(nèi)有申請(qǐng)的動(dòng)態(tài)內(nèi)存,需要清理和釋放的時(shí)候。
  • 一旦基類的虛構(gòu)函數(shù)稱為虛函數(shù)之后,派生類的析構(gòu)函數(shù)會(huì)自動(dòng)稱為虛函數(shù)。即使沒(méi)有給出virtual關(guān)鍵字。

?

?

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

?

6、virtual ?繼承 ?(虛擬繼承-虛函數(shù))

?

  • 同樣使用 virtual ?關(guān)鍵字?---> ?存在、間接和共享 ?這三種特征
  • 虛擬繼承如何表現(xiàn):
    • 存在即表示虛繼承體系和虛基類確實(shí)存在
    • 間接性表現(xiàn)在當(dāng)訪問(wèn)虛基類的成員時(shí)同樣也必須通過(guò)某種間接機(jī)制來(lái)完成(通過(guò)虛基表來(lái)完成)
    • 共享性表現(xiàn)在虛基類會(huì)在虛繼承體系中被共享,而不會(huì)出現(xiàn)多份拷貝
  • 虛繼承:在繼承定義中包含了virtual關(guān)鍵字的繼承關(guān)系 虛基類:在虛繼承體系中的通過(guò)virtual繼承而來(lái)的基類

?

語(yǔ)法:

class Subclass : public virtual Baseclass

{

????? public:? ? //...

?????private:? ?//...

????? protected: //...

};

????? 其中Baseclass稱之為Subclass的虛基類; 而不是說(shuō)Baseclass就是虛基類

?

7、虛擬繼承的一些特性

?

注:以下結(jié)論均可通過(guò)vs的圖形化調(diào)試驗(yàn)證。

?

  • 一:單個(gè)虛擬繼承,不帶虛函數(shù)? ?
    • 虛擬繼承與繼承的區(qū)別: ? ? ?
      • 1、虛基類處于對(duì)象內(nèi)存的末尾 ? ? ?
      • 2、多了一個(gè)虛基指針 (vbptr)
  • 二:單個(gè)虛擬繼承,帶虛函數(shù) ? ? ?
    • 如果派生類擁有自己的虛函數(shù)(并不是覆蓋),它產(chǎn)生的虛函數(shù)指針是位于虛基指針的前面的 。
    • 或者說(shuō),一個(gè)類如果有自己的虛函數(shù),它在內(nèi)存中的布局一定是位于最開始的位置,原因是為了提高(或者說(shuō)是派生類的)訪問(wèn)虛函數(shù)的速度 。
  • 三:多重繼承(帶虛函數(shù)) ??
    • 1. 每個(gè)基類都有自己的虛表 ??
    • 2. 派生類的虛成員函數(shù)被加入到第一個(gè)基類的虛函數(shù)表中 ??
    • 3. 內(nèi)存布局中,其基類布局依次按其聲明時(shí)的順序進(jìn)行排列 ??
    • 4. 派生類會(huì)覆蓋掉基類的對(duì)應(yīng)的虛函數(shù),第一個(gè)虛函數(shù)表中的被覆蓋的虛函數(shù)地址是真實(shí)的;之后的虛函數(shù)表中的對(duì)應(yīng)的 被覆蓋的虛函數(shù)所存放的并不是虛函數(shù)的地址,而是一條跳轉(zhuǎn)指令
  • 四:多重繼承具有共同的基類 ?vs? 虛擬繼承 /* 虛基指針?biāo)赶虻奶摶淼膬?nèi)容: ??
    • 1. 虛基指針的第一條內(nèi)容表示的是該虛基指針距離所在的子對(duì)象的首地址的偏移 ??
    • 2. 虛基指針的第二條內(nèi)容表示的是該虛基指針距離虛基類子對(duì)象的首地址的偏移

?

8、虛基派生的構(gòu)造函數(shù)和析構(gòu)函數(shù)

?

  • 從虛基類直接或間接派生出來(lái)的子類的構(gòu)造函數(shù)初始化列表均有對(duì)該虛基類構(gòu)造函數(shù)的調(diào)用,這樣就保證虛基類的唯一副本只被初始化一次。即虛基類的構(gòu)造函數(shù)只被執(zhí)行一次。
  • 繼承機(jī)制下析構(gòu)函數(shù)的調(diào)用順序: 先調(diào)用派生類的析構(gòu)函數(shù),然后調(diào)用派生類中成員對(duì)象的析構(gòu)函數(shù) ,再調(diào)用普通基類的析構(gòu)函數(shù) 最后調(diào)用虛基類的析構(gòu)函數(shù) 。

9、效率

?

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

?

10、擴(kuò)展閱讀

?

0. 擴(kuò)展閱讀

http://blog.csdn.net/myan/article/details/5928531

? http://www.cnblogs.com/leoo2sk/archive/2009/04/09/1432103.html

?

1、參考閱讀 ? ? http://blog.csdn.net/haoel/article/details/3081328

?

?http://blog.csdn.net/haoel/article/details/3081385

?

?

三、總結(jié)

?


?

1、概述

?

  • 客觀世界 ? ? ? ? ? ? ? ? 程序世界

? ? ? ? ? ? ? ? 類到對(duì)象? ? ? ? ? ? ? ??實(shí)例化

? ? ? ? ? ? ? ? 對(duì)象到類 ? ? ? ? ? ? ? ? ?? 抽 ?象

  • 對(duì)象的管理方式:
    • 單個(gè)對(duì)象 ---> 智能指針
    • 多個(gè)對(duì)象 ----> 數(shù)據(jù)結(jié)構(gòu) + 算法 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?實(shí)現(xiàn) (STL -->模板)
  • OOP (面向?qū)ο蟮木幊?#xff09;


四、面向?qū)ο蟮脑O(shè)計(jì)

?


?

1、概述

?

  • 面向?qū)ο蠓治?OOA)
  • 面向?qū)ο缶幊?OOP)
  • 面向?qū)ο笤O(shè)計(jì)(OOD)

?

經(jīng)驗(yàn):在平常的時(shí)候,沒(méi)有必要提前告訴他(不然預(yù)期太高),可以學(xué)其他的東西。在緊急的時(shí)候,可以適當(dāng)表現(xiàn)一下。 ? ? ?--- > ? 以后需要學(xué)習(xí)的事情。

?

  • Unifed Modeling Language(UML), 又稱統(tǒng)一建模語(yǔ)言或標(biāo)準(zhǔn)建模語(yǔ)言,UML為軟件開發(fā)提供了一些標(biāo)準(zhǔn)的圖例(10),統(tǒng)一開發(fā)思想,從而促進(jìn)團(tuán)隊(duì)協(xié)作 。

?

  • 類與類之間的關(guān)系
  • 繼承(泛化) ?? 垂直的 (A ?is ?B)空心的三角箭頭
  • 依賴 ? ?---> 虛線箭頭? 下面四種都是橫向的(水平的) ?A ?use ?B ? ?例子:master 和 pat
    • 1. 從語(yǔ)義上來(lái)說(shuō)是 A ? use B,是偶然的,臨時(shí)的,并非固定的, 發(fā)生在函數(shù)調(diào)用時(shí)。
    • 2. B作為A的成員函數(shù)參數(shù)
    • 3. B作為A的成員函數(shù)的局部變量
    • 4. A的成員函數(shù)調(diào)用B的靜態(tài)方法

?

  • 關(guān)聯(lián) ? ? ? ? ? 下面三種都是 A ?has ? B ??
    • 1.更強(qiáng)的一種關(guān)聯(lián)關(guān)系
    • 2. 對(duì)象之間的關(guān)系表現(xiàn)為分為整體和局部
    • 3. 整體部分負(fù)責(zé)局部對(duì)象的銷毀

?

  • 組合 ? ?--->實(shí)心菱形箭頭
    • 1、比較強(qiáng)的一種關(guān)聯(lián)關(guān)系
    • 2. 對(duì)象之間的關(guān)系表現(xiàn)為分為整體和局部
    • 3. 整體部分并不負(fù)責(zé)局部對(duì)象的銷毀

?

  • 聚合 ? --->空心的菱形箭頭
    • 雙向的關(guān)聯(lián)關(guān)系 ? ? 一條直線
    • 單向的關(guān)聯(lián)關(guān)系 ? 一方只知道一方存在 ?->
    • 關(guān)系是固定的? ?A has B
    • 彼此并不負(fù)責(zé)對(duì)方的生命周期
    • 一般使用指針或者引用

?

  • 總結(jié): ? ----> 很重要的
      • 繼承 ? ? ? ?---> ?繼承關(guān)系
      • 傳參數(shù) ? ? ---> ?依賴關(guān)系
      • 指針或引用使用另一個(gè)類 ?--> ?關(guān)聯(lián)關(guān)系? (同一層次)
      • 整體和局部(指針或引用)? ?---> 聚合關(guān)系? ?(不平等的層次上,一個(gè)代表整體,一個(gè)代表部分)
      • 對(duì)象成員(強(qiáng)相關(guān)) ?---> 組合關(guān)系

?

  • 關(guān)系之間的比較
    • 繼承體現(xiàn)的是類與類之間的縱向關(guān)系
    • 其他四種體現(xiàn)的是類與類之間的橫向關(guān)系
    • 耦合強(qiáng)弱: 依賴 < 關(guān)聯(lián) < 聚合 < 組合
    • 從語(yǔ)義上來(lái)看
      • 繼承(A is B)
      • 關(guān)聯(lián)、聚合、組合(A has B)
      • 依賴(A use B)
    • 當(dāng)組合與依賴結(jié)合時(shí),可以替代繼承 ? ? ? ??
    • 組合+依賴(基于對(duì)象) vs? 繼承(面向?qū)ο?#xff09;

?

  • 設(shè)計(jì)原則
    • 強(qiáng)調(diào)模塊間保持低耦合、高內(nèi)聚的關(guān)系 。
    • SOLID的5原則
    • 單一職責(zé)原則(Single Responsibility Principle)
      • 一個(gè)類,最好只做一件事,只有一個(gè)引起它變化的原因。原則的核心就是解耦和增強(qiáng)內(nèi)聚性。
    • 開閉原則(Open Closed Principle)
      • 軟件實(shí)體(類,模塊,函數(shù)等等)應(yīng)當(dāng)對(duì)擴(kuò)展開放,對(duì)修改閉合。
      • 能在不修改類的前提下擴(kuò)展一個(gè)類的行為。
      • 核心思想就是對(duì)抽象編程,而不對(duì)具體編程,因?yàn)槌橄笙鄬?duì)穩(wěn)定。
    • 里氏替換原則(Liscov Substitution Principle)
      • 子類必須能夠替換其基類。
      • 主要著眼于抽象和多態(tài)建立在繼承的基礎(chǔ)上
    • 接口分離原則(Interface Segregation Principle)
      • 接口應(yīng)該是內(nèi)聚的,應(yīng)該避免“胖”接口
    • 依賴倒置原則(Dependency Inversion Principle)
      • 面向接口編程,依賴于抽象
      • a.高層模塊不依賴于底層模塊,二者都同依賴于抽象;
      • b.抽象不依賴于具體,具體依賴于抽象。

?

  • web服務(wù)器:
    • CS : ?qq ? 360殺毒軟件
    • BS : ? WIndows: ?IIS ?asp(小型)
        • Apachae(html/php) ? Nginx(html/php) ?(中小型) ? ? ? ? ? ?
        • Tomcat/WebLogic(jsp) ?(大型)?
      • hadoop ?spark ?( 大數(shù)據(jù) )
      • Linux內(nèi)核

總結(jié)

以上是生活随笔為你收集整理的C++学习笔记系列之继承多态的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。