初級C++3繼承、多態、異常、命名空間


面向對象特色:抽象 封裝 繼承 多態數組

可重用型 software reusability函數

繼承 inheritancespa

做用:在一個已存在的類的基礎上創建一個新的類設計

已存在的類:父類 father class  基類 base class指針

           新類:子類 son class    派生類 derived class對象


 單繼承 single inheritance:一個派生類只從一個基類派生  樹結構繼承

多重繼承 multiple inheritance:一個派生類有兩個或以上基類  圖結構接口


派生類是基類的具體化ip

基類是派生類的抽象內存


派生類的聲明方式:

class 派生類名:[繼承方式] 基類名

{派生類新增長的成員};


繼承方式:

    |--public  公用的

    |--private    私有的(默認)

    |--protected  受保護的


派生類的構成:

    |--從基類繼承過來的成員  共性

    |--本身增長的成員     個性


構造派生類的3個步驟:

一、從基類接受成員(不包括構造函數和析構函數) 謹慎定義基類,由於會形成冗餘

二、調整從基類接受的成員(公用變私有,重載)

三、增長派生類的個性成員,定義構造函數和析構函數


——————————————————————————————————


基類中的成員  公用派生類  私有派生類  保護派生類

    私有成員     不可訪問      不可訪問      不可訪問

    公用成員     公用              私有             保護

    保護成員     保護              私有            保護



派生類中的成員有4種訪問屬性

派生類的成員   派生類中  派生類外部  下層派生類

    公用成員        1                 1                1

  受保護成員       1                0                1

    私有成員        1                 0                0

不可訪問成員     0                 0                0


私有繼承和保護繼承不經常使用

實際中經常使用的是公用繼承


———————————————————————————————————


派生類的構造函數

派生類不能繼承基類的構造函數和析構函數

在執行派生類的構造函數時,調用基類的構造函數



簡單派生類的構造函數

派生類構造函數名(總參數列表):基類構造函數名(參數列表)  //相似於函數初始化列表

{ 派生類中新增數據成員初始化語句 }

先調用基類構造函數,再執行派生類構造函數

先執行派生類析構函數,再執行基類析構函數


有子對象 subobject 的派生類的構造函數

派生類構造函數名(總參數列表):基類構造函數名(參數列表),子對象名(參數列表)

{ 派生類中新增數據成員初始化語句 }

順序:

調用基類構造函數

調用子對象構造函數

執行派生類自己構造函數


對於多層派生的構造函數,只需寫出其上一層派生類/直接基類的構造函數便可


析構函數

先執行派生類本身的析構函數

再執行子對象的析構函數

最後執行基類的析構函數


———————————————————————————————————


多重繼承 multiple inheritance

容許一個派生類同時繼承多個基類


多重繼承派生類的構造函數

派生類構造函數名(總參數列表):基類1構造函數(參數列表),基類2構造函數(參數列表),基類3構造函數(參數列表)

{ 派生類中新增數據成員初始化語句 }


調用基類構造函數的順序與聲明順序相同


多重繼承引發的二義性 ambiguous

解決方法 在訪問時加 基類名::變量/函數


———————————————————————————————————


虛基類 virtual base class

A派生B C

D多繼承B C

虛基類讓D只保存一份A的數據

在繼承間接共同基類時,只保留一份成員


class A

{};

class B:virtual public A

{};

class C:virtual public A

{};

class D:public B, public A

{};


虛基類不是在聲明基類時聲明的,而是在聲明派生類時,指定繼承方式時聲明的

    class 派生類名:virtual 繼承方式 基類名


爲保證虛基類在派生類中只繼承一次,應當在該基類的全部直接派生類中聲明爲虛基類。不然仍然會出現對基類的屢次繼承。


D的構造函數:D():A(),B(),C()

在最後的派生類中,負責對虛基類 直接基類的初始化

編譯系統只執行最後的派生類對虛基類的構造函數的調用,保證了虛基類的數據成員不會被屢次初始化


使用多重繼承要十分當心二義性問題。

不提倡在程序中使用多重啓程,能用單繼承就不用多重繼承。


———————————————————————————————————


基類與派生類的轉換


只有公用派生類纔是基類真正的子類型,它完整地繼承了基類的功能。

不一樣類型數據之間的自動轉換和賦值,稱爲賦值兼容

基類與派生類對象之間有賦值兼容關係

一、派生類對象能夠向基類對象賦值;

二、派生類對象能夠向基類對象的引用進行賦值或初始化;//此引用對應派生類中基類的部分

三、若是函數的參數是基類對象或基類對象的引用,相應的實參能夠用子類對象;

四、指向基類對象的指針能夠指向派生類對象。


——————————————————————————————————


組合 composition

在一個類中以另外一個類的對象做爲數據成員 has a   繼承 is a


———————————————————————————————————


繼承在軟件開發中的重要意義

縮短軟件開發過程的關鍵是  軟件重用

典型例子:類庫

對類庫中類的聲明通常放在頭文件中

類的實現(函數的定義部分)單獨編譯,以代碼形式存放在系統某一目錄下


——————————————————————————————————


多態性與虛函數


多態性 polymorphism

一個事物有多種形態

向不一樣的對象發送同一個消息,不一樣的對象在接受時會產生不一樣的行爲


從系統實現角度分類:

    |--靜態多態性 編譯時多態 函數重載

    |--動態多態性 運行時多態 虛函數 virtual function


虛函數的做用是容許在派生類中從新定義與基類同名的函數,

而且能夠經過基類指針或引用來訪問基類和派生類中的同名函數。


經過指向基類的指針,指向基類或不一樣的派生類對象,能夠調用各自的虛函數


virtual關鍵字

一、在基類中用virtual聲明成員函數爲虛函數,在類外定義虛函數時,沒必要再加virtual;

二、當一個成員函數被聲明爲虛函數後,其派生類中的同名函數都自動稱爲虛函數

   建議在派生類的虛函數前加virtual

三、虛函數與指向基類對象的指針變量配合使用


函數重載:橫向  首部不一樣(參數不一樣)

    虛函數:縱向  首部相同


編譯系統要根據已有的信息,對同名函數的調用作出判斷。

肯定調用的具體對象的過程稱爲關聯(binding)

把一個函數名與一個類對象捆綁在一塊兒,創建關聯

把一個標識符和一個存儲地址聯繫起來


靜態關聯 static binding  

在編譯時便可肯定其調用的虛函數屬於哪一類

函數重載屬於靜態關聯  studl.diaplay() gradl.display()均屬於靜態關聯

運行前關聯 早期關聯 early binding


動態關聯 dynamic binding

在運行階段把虛函數和類對象binding在一塊兒

這種多態性是動態的多態性,運行階段的多態性

運行階段關聯 滯後關聯 late binding


說明:

使用虛函數,系統要有必定的空間開銷

當一個類帶有虛函數時,編譯系統會爲該類構造一個虛函數表(virtual function table)

它是一個指針數組,存放每一個虛函數的入口地址

系統在進行動態關聯時的時間開銷是不多的,所以多態是高效的。


———————————————————————————————————


若是析構函數未聲明爲虛函數

在撤銷動態存儲空間時,僅能調用基類的析構函數。


建議將基類的析構函數聲明爲虛函數

保證在撤銷動態存儲空間時能獲得正確處理。


———————————————————————————————————


純虛函數與抽象類


純虛函數 pure virtual function  

在聲明虛函數時被「初始化」爲0的函數


通常形式:

virtual 函數類型 函數名(參數列表)=0;


注意:

一、純虛函數沒有函數體

二、最後面的「=0」僅起形式上的做用,告訴編譯系統「這是純虛函數」

三、聲明語句加分號



抽象類 abstract class

不用來定義對象而只做爲一種基本類型用做繼承的類  

因爲它用做基類,一般稱爲抽象基類 abstract base class


凡是包含純虛函數的類都是抽象類

由於虛函數不能被調用,因此沒法創建對象


抽象類的做用是做爲一個類族的共同基類,爲一個類族提供一個公共接口。


能夠創建對象的類稱爲具體類 concrete class


———————————————————————————————————


異常處理

程序中兩大類錯誤:

    |--編譯錯誤/語法錯誤

    |--運行錯誤

        |--除0

        |--內存不足

        |--沒法打開文件

        |--數據類型出錯


在設計程序時,應當事先分析程序運行時可能出現的各類意外狀況,並分別制定相應的處理方法,這就是程序的異常處理的任務


若是在執行一個函數過程當中出現異常,能夠不在本函數中當即處理,而是發出一個信息傳給它的上一級(調用它的函數)

它的上級捕捉到這個信息後進行處理,若是處理不了,繼續向上級拋,、

若是最高一級也沒法處理,終止程序。


異常處理機制的3個部分:

try 檢查

catch 捕捉

throw 拋出 


throw拋出什麼樣的數據由程序設計者自定,能夠是任何類型的數據(包括自定義類型的數據,如類對象,結構體)


說明:

一、被檢測的語句必須放在try塊中,不然不起做用

二、try塊和catch塊做爲一個總體出現,能夠有try無catch

三、try catch 後必須跟{}

四、只能有一個try,能夠有多個catch

五、catch後面的圓括號中,通常只寫異常信息的類型名

        catch(double)

        catch(double d) //能夠利用throw傳遞過來的具體值

六、catch(...) 捕捉任何類型的異常信息

七、throw;此語句表明:我不處理這個異常,請上級處理

九、若是throw拋出的異常信息找不到與之匹配的catch塊,那麼系統就會調用一個系統函數terminate,使程序終止運行


在函數聲明中進行異常狀況的指定

double triangle(double, double, doubl); //可拋任何類型的異常

double triangle(double, double, double) throw(double); //可拋double型異常

double triangle(double, double, double) throw(double, int, char, float); //可拋double int char float類型的異常

double triangle(double, double, double) throw(); //不能拋出異常


在異常處理中處理析構函數

C++的異常處理機制會在throw拋出異常信息被catch捕獲時,對有關的局部對象進行析構

析構對象的順序與構造的順序相反

而後執行與異常信息匹配的catch塊中的語句


——————————————————————————————————


命名空間

命名空間是能夠由用戶命名的做用域,用來處理程序中常見的同名衝突


所謂命名空間,實際上就是一個由程序設計者命名的內存區域。

程序設計者能夠根據須要指定一些有名字的空間域,把一些全局實體分別放在各個命名空間中,從而與其餘全局實體分隔開來。

namespace ns    //namespace 關鍵字

{

    int a;

    double b; //a b 稱爲命名空間成員 namespace member

}


ns::a

ns::b  //命名空間限定 qualified  被限定名 qualified name


命名空間的做用相似於目錄與文件的關係


命名空間的做用是創建一些相互分隔的做用域,把一些全局實體分割開來,以避免產生名字衝突。


全局變量在全局命名空間,獨立於全部有名的命名空間以外,它不須要用namespace聲明,由系統隱式聲明,存在於每一個程序之中。


命名空間能夠包括:

    變量(能夠帶有初始化)

    常量

    函數(定義或者聲明)

    結構體

    類

    模板

    命名空間(嵌套命名空間)


使用命名空間成員的方法

一、命名空間名::命名空間成員名

二、使用命名空間別名

    namespace 別名 = 命名空間名;

三、using 命名空間成員名

   using std::cout;

四、using namespace 命名空間名

   using namespace std;


無名的命名空間

file

namespace

{

    void fun()

    {...}

}


fun();

在無名的命名空間中的東西只在本文件的做用域中有效。C++

對全局變量用static聲明使其只在本文件有效。C



標準命名空間 std

存放標準庫的有關內容的命名空間

C++庫的全部標識符都是在一個名爲std的命名空間中定義的

或者說

標準頭文件中函數、類、對象、類模板是在命名空間std中定義的


C傳統方法                C++新方法

#include<stdio.h>        #include<cstdio>

#include<math.h>         #include<cmath>

#include<string.h>       #include<cstring>

                                         using namespace std;

無需命名空間             須要命名空間 

相關文章
相關標籤/搜索