繼承指的是從先輩出獲得屬性和行爲的特徵,也就是新類從已有的類那裏獲得已有的特性,反過來看,從已有類產生新類的過程就是類的派生。所以類的繼承和派生是一個成對出現的概念,原來的類稱爲基類或者父類,產生的新類稱爲派生類或者子類,派生類一樣能夠做爲基類派生新的類,這樣就能夠創建一個具備共同特性的對象家族,實現代碼的重用。派生新類的過程通常包括,吸取父類的成員,調整父類的成員,添加新的成員。c++
class 派生類名稱:繼承方式 第一個基類名,繼承方式 第二個基類名稱,...,繼承方式 第n個基類名稱程序員
{函數
派生類成員聲明;spa
};指針
例:code
class Linequ: public Matrix //公有派生類Linequ定義 { public: Linequ(int dims=2); //構造函數 ~Linequ(); //析構函數 void setLinequ(double *a,double *b);//方程賦值 void printL(); //顯示方程 int Solve(); //全選主元高斯消去法求解方程 void showX(); //顯示方程的解 private: //私有數據 double *sums; //方程右端項 double *solu; //方程的解 };
其中對象
Linequ是派生類的名稱;public是繼承方式,繼承方式主要的做用是控制從基類繼承的成員的訪問屬性(另外還有 private 和protected兩種繼承方式,此處未使用)父類是Matrix;花括號{}裏面的內容是派生類的成員聲明;blog
這裏須要注意的是一個派生類也能夠同時繼承多個基類,這叫作多繼承,像上面的代碼例子是隻繼承類一個Matrix基類,就是單繼承的。另外派生出來的新類也能夠繼續做爲基類再次派生新類。繼承
派生類主要有三個步驟,吸取父類的成員,調整父類的成員,添加新的成員。接口
就是將基類中的成員,除了構造函數和析構函數以外,全都接收到派生類中,所以構造函數和析構函數是不能被繼承的。
一個是基類成員的訪問控制問題,主要依靠派生列定義時的繼承方式來控制;第二個是對基類數據成員或函數成員的隱藏,隱藏的方式就是在新類中聲明一 個和基類中數據或者 函數同名的成員,這樣派生類中的該成員就實現了對基類數據成員或函數成員的隱藏。若是在派生類中或者經過派生類的對象,直接使用成員名就只能訪問到派 生類中聲明的同 名函數,沒法基類中的數據成員或函數成員,從而實現了對基類成員的隱藏。
由於根據實際狀況給派生類添加新的適當的數據和成員,就能夠實現新的功能,例如派生類沒有繼承基類的構造函數和析構函數,因此就要在派生 列中加入新的構造函數和析構 函數來完成初始化和掃尾工做。
派生類的訪問控制是經過類的繼承方式實現的,類的繼承方式主要有public(公有繼承),protected(保護繼承),private(私有繼承)。按照這三種繼承方式,從基類繼承的基類成員在 派生類中的訪問屬性也是不一樣的,這裏的訪問屬性不一樣主要是從兩方面來講的,首先是派生類中的新增成員對從基類繼承的成員的訪問,其次是派生類外部,即經過派生類聲明的對象訪問從 基類繼承的成員函數。
當類的繼承爲公有繼承方式時,基類的公有和保護成員的訪問成員在派生類中仍然做爲派生類的公有成員和保護成員,派生類的其餘成員能夠直接訪問。在類以外只能經過派生類的對象訪問 從基類繼承的公有成員。可是不管是派生類的成員仍是派生類的對象都沒法直接訪問基類的私有成員。
當類的繼承爲私有繼承時,基類的公有和保護成員被繼承後做爲派生類的私有成員,派生類的其餘成員能夠直接訪問。可是類外部的派生類對象沒法直接訪問它們。可是爲了在私有繼承的情 況下保證基類的一部分外部接口特徵可以在派生類中存在,能夠在派生類中聲明基類的同名函數,利用派生類對基類的訪問能力,把基類的成員函數功能搬過來,同時咱們也要知道,根據同 名隱藏原則,派生類在調用時調用的確定是派生類的同名函數。
當類的繼承爲保護繼承時,訪問控制屬性同私有繼承方式相同,可是若是派生類做爲新的基類,繼續派生時,私有繼承和保護繼承就有區別啦!例如B類以私有繼承的方式繼承了A類,B類又 派生了C類,那麼C類的成員和對象都不能訪問從A類中繼承的成員。若是B類是以保護繼承的方式繼承了A類,那麼A類中的公有和保護成員在B類中就是保護成員,如果B類再派生出C類,那 麼A類中的公有和保護成員就被C類間接繼承後,有多是保護的或者私有的(是B到C的派生方式決定),所以C類中的成員可能訪問從A中繼承的成員。好繞呀!
從繼承的訪問權限能夠看出,若是類A中含有保護成員member_of_protected,那麼對於這個類A定義的對象a來說,A類中的保護成員member_of_protected和私有成員 member_of_privated是不可訪問的。可是若是A類派生了子類AA,那麼對於子類AA來講,公有成員和保護成員具備相同的訪問權限。也就是A類中保護成員可能被它的派生類訪問,可是 必定不可能被程序中的普通函數或者與A類平行的其餘類訪問。這樣就實現了成員的隱藏和共享,實現了代碼的高效利用。
類型兼容性規則指的是在任何須要基類的對象的地方,均可以使用公有派生類的對象來替代。派生類的對象能夠賦值給基類的對象 ,能夠初始化基類的引用,派生對象的地址能夠賦值給指 向基類的指針。這個的具體應用聽說在多態特性中,等學到多態在具體描述~~~~~(偷個懶~~~~)
由於基類的構造函數和析構函數是不能被繼承的,因此在派生類中,若是要對派生類新增的成員進行初始化,就必須爲派生類添加新的構造函數和析構函數,另外須要注意的是,派生類的構 造函數只負責對派生類的新增成員函數記性初始化,對於全部從基類繼承下來的成員,其初始化工做仍是由基類的構造函數完成的。一樣對派生類對象的清理工做也須要加入新的析構函數。 由於派生類的成員有全部基類的成員和派生類的新增成員,如果派生類中還內嵌了其餘類對象,那麼派生類的成員還會間接包括這些對象的成員,歸納起來就是,構造派生類的對象時,須要 對基類的成員,新增成員和內嵌對象的成員進行初始化。
派生類的構造函數語法爲:
派生類名::派生類名(參數總表):基類名1(參數表1),...,基類名n(參數表n),內嵌對象名1(內嵌對象參數表1),...,內嵌對象名m(內嵌對象參數表m)
{
派生類新增成員的初始化語句;
}
須要注意的是,雖然參數總表要求給出基類,新增類成員,內嵌成員對象的所有參數,可是實際使用時能夠根據須要自行選擇給出,不必定都給出。當一個類同時繼承多個基類時,對於全部 須要給予參數初始化的基類,都要顯示給出基類的名稱和參數,對於使用默認構造函數的基類,能夠不給出類名。一樣對於對象成員,若是使用默認構造函數,也不須要給出對象名和參數 表。對於單繼承的,只須要給出基類名稱就能夠啦!
若是基類聲明瞭但有形參數表的構造函數,派生類就應當聲明構造函數,提供一個將參數傳遞給基類構造函數的途徑,保證基類初始化時有必要的數據。
在構造派生類構造函數的執行次序是:
(1)調用基類構造函數,調用順序按照它們被繼承時聲明的順序(從左到右);(也就是按照「基類名1(參數表1),基類名2(參數表2),...,基類名n(參數表n)」這個順序!!)
(2)調用內嵌成員對象的構造函數,調用順序按照它們在類中聲明的順序;
(3)調用派生類的構造函數中的內容
對於一個類,若是程序員沒有編寫拷貝構造函數,編譯系統就會自動生成一個默認的拷貝構造函數。若是編寫拷貝構造函數,那麼須要給基類相應的拷貝構造函數傳遞參數,例如,C類是B類的派生類,C類的拷貝構造函數形式以下:
C::C(C &c1):B(c1)
{
...
}
派生類析構函數的聲明方法與沒有繼承關係的類中析構函數的聲明方法徹底相同,可是執行次序和構造函數正好相反,首先對派生類新增普通成員清理,而後對派生類新增成員清理,最後 對全部基類繼承類的成員清理。
派生類成員分爲四種:
(1)不可訪問的成員
從基類私有成員的繼承來的成員。
(2)私有成員
從基類繼承的成員和新增的成員
(3)保護成員
新增成員或者從基類繼承來的
(4)公有成員
做用域分辨符
做用域分辨符是「::」,它的最用是限定訪問成成員所在的類的名稱,通常形式是:
基類名::成員名;//數據成員
基類名::成員名(參數名);//函數成員
做用域分辨符惟一識別成員的過程,在類的派生結構層中,基類的成員和派生類新增成員都具備類做用域,二者的最用範圍是相互包含的,派生類在內層。此時,若是派生類聲明瞭一個和 基類成員同名的新成員,派生的新成員就隱藏了外層同名成員,直接使用成員名只能訪問到派生類的成員,在沒有虛函數的狀況下,如果派生類聲明瞭與基類成員函數同名的新函數,即便 函數的參數表不一樣,從基類繼承的同名函數的全部承載形式也都會被隱藏。若是要訪問被隱藏的成員,就須要使用做用域分辨符和基類名來限定。所以,「對象名.成員名」這種方式能夠惟一 標識和訪問派生類的新增成員,基類的同名成員可使用基類名和做用域分辨符訪問。所以在派生類即創建派生類對象的模塊中,派生類新增成員若是隱藏了基類的同名成員,這是使用「對 象名.成員名」的方式,就只能訪問到派生類的新增成員函數,對基類同名成員函數的訪問只能經過基類名和做用域分辨符來實現,也就是說,必須明確告訴系統要使用哪一個基類的成員。
之前討論多繼承的都是全部基類之間沒有繼承關係,可是若是這個條件不知足呢?若是某個派生類的部分或者所有直接基類是從另外一個共同的基類派生而來,在這些直接基類中,從上一級中 繼承來的成員就擁有相同的名稱,所以派生類會產生同名現象,雖然能夠經過做用域來限定,可是這樣多份相同的成員增長了內存的開銷,如何解決呢?咱們能夠經過虛基類來解決。
虛基類就是從不一樣路徑繼承過來的額同名數據成員在內存中只有一個拷貝,同一個函數名也只用一個映射,虛基類的聲明語法:
class 派生類名: virtual 繼承方式 基類名
其中虛基類的關鍵字做用範圍只對緊跟其後的基類起做用。
可是虛基類不是這麼簡單的,用到再說吧!!