目錄樹ios
1.繼承c++
1.1 基類成員在派生類中的訪問屬性express
1.2繼承時致使的二義性安全
1.3 多基繼承函數
2.虛函數的多態spa
2.1虛函數的定義3d
2.2派生類中能夠根據須要對虛函數進行重定義指針
2.3 虛函數的訪問對象
2.4哪些函數不能定義爲虛函數blog
2.5虛函數表指針(vptr)和虛基類表指針(bptr)
2.5.1 虛函數表指針vptr
2.5.2含靜態變量、虛函數的類的空間計算
2.5.3虛基類表指針
2.5.4 虛擬繼承時構造函數的書寫
2.5.5虛函數
3.運行時類型識別與顯示轉換
3.1 typeid
3.2 顯式轉換
1.繼承
若是一個類有多個直接基類,而這些直接基類又有一個共同的基類,則在最底層的派生類中會保留這個間接的共同基類數據成員的多份同名成員。提出虛繼承,虛繼承時,公共基類在對象模型中只有一份拷貝。
1.1 基類成員在派生類中的訪問屬性
這裏必定要區分清楚派生類對象和派生類中的成員函數對基類的訪問時不一樣的。
1.2繼承時致使的二義性
1)在公有繼承下(私有,保護繼承時,不能隱式轉換)下,派生類的對象/對象指針/對象引用能夠賦值給基類的對象/對象指針/對象引用(發生隱式轉換)。但基類的對象/對象指針/對象引用不能賦值給派生類的對象/對象指針/對象引用。由於派生類包含了基類的全部信息,而基類缺少派生類中的信息。
2)c++允許把基類的對象指針/對象引用強制轉換爲(顯式)派生類的對象指針/對象引用。
3)一個指向基類的指針能夠用來指向該基類公有派生類的任何對象,這是c++實現程序運行時多態性的關鍵。
1.3 多基繼承
當繼承基類時,在派生類中就得到了基類全部數據成員的副本,該副本稱爲子對象。
類mi會包含的的d1的子對象和d2的子對象。若是多個基類中存在同名成員的狀況,形成編譯器無從判斷具體要訪問那個基類的成員,則稱對基類成員訪問的二義性問題。(解決辦法:能夠加限定符基類)
2.虛函數的多態
多態是面向對象的精髓。能夠歸納爲一個接口,多種方法。通俗來說,多態是指同一個操做做用於不一樣的對象就會產生不一樣的響應。多態性分爲靜態多態和動態多態。其中的函數重載和運算符重載屬於靜態多態。虛函數屬於動態多態性。c++是經過虛函數實現動態多態的。
2.1虛函數的定義
虛函數的定義是在函數原型前加一個關鍵字virtual便可。
若是一個基類成員定義爲虛函數,那麼,他在全部派生類中也保持爲虛函數,即便在派生類中省略了virtual關鍵字,也任然是虛函數。
2.2派生類中能夠根據須要對虛函數進行重定義,重定義的格式要求:
1)與基類的虛函數有相同的參數個數;
2)與基類的虛函數有相同的參數類型;
3)與基類的虛函數有相同的返回類型。或者與基類的虛函數相同,或者返回指針(引用),而且派生類虛函數所返回的指針(引用)類型是基類中被替換的虛函數所返回的指針(引用)類型的子類型(派生類型)。
2.3 虛函數的訪問
虛函數能夠經過對象名訪問,此時編譯器採用的是靜態編譯。
1)經過對象名訪問虛函數時,調用哪一個類的函數取決於定義對象名的類型。對象類型是基類時,就調用基類的函數。對象類型是子類時就調用子類的函數。
2)使用指針訪問非虛函數時,編譯器根據指針自己的類型決定要訪問那個函數,而不是根據指針指向的對象類型。
3)使用指針訪問虛函數時,編譯器根據指針所指對象的類型決定要訪問那個函數,而不是根據指針自己的類型。
4)使用引用訪問虛函數,與使用指針訪問虛函數類型,不一樣的是,引用一經聲明,引用變量自己不管如何改變其調用的函數都不會改變,始終指向開始定義時的函數。在必定程序上提升了代碼的安全性。(受限制的指針)
總結:
c++中函數調用默認不使用動態綁定,要觸發動態綁定需知足兩個條件:
a.只用指定爲虛函數的成員函數才能進行動態綁定,成員函數默認爲非虛函數,非虛函數不能進行動態綁定。
b.必須經過基類類型的引用或指針進行函數調用。
2.4哪些函數不能定義爲虛函數
普通函數(類的非成員函數),靜態成員函數,構造函數,友員函數。而內聯成員函數和賦值操做符重載函數即便聲明爲虛函數也毫無心義。
2.5虛函數表指針(vptr)和虛基類表指針(bptr)
2.5.1 虛函數表指針vptr
1)每一個類產生一堆指向virtual functions 的指針,放在表格中,這個表格稱爲虛函數表。
2)每一個對象被添加一個指針,指向相關的virtual table,一般這個指針被稱爲vptr(虛函數表指針)vptr的設定和重置由每個類的構造函數,析構函數和複製構造函數自動完成。每一個類所關聯的type_info信息(用以支持rtti)也由virtual table 指出。一般放在表格的第一個slot處。
2.5.2含靜態變量、虛函數的類的空間計算
sizeof應用在類和結構的處理狀況是相同的。可是在類中的靜態成員不對結構或類的大小產生影響。
2.5.3虛基類表指針
c++支持單一和多重繼承。
class iostream:public istream,public ostream{...};
繼承關係也能夠指定爲虛擬(virtual 共享的意思)
class istream :virtual public ios{...};
class ostream :virtual public ios{...}; //菱形繼承
在虛擬繼承中,基類無論在繼承串鏈中被派生多少次,永遠只會存在一個實體。
在虛擬繼承基類的之類中,子類會增長某種形式的指針,或者指向虛基類子對象,或者指向一個相關的表格,表格中存放的不是虛基類子對象的地址,就是其偏移量。此指針叫bptr.
2.5.4 虛擬繼承時構造函數的書寫
從A類直接虛擬派生(B和C)和間接派生(D)的類中,其構造函數的初始化列表中都要列出對基類A構造函數的調用。這種機制保障無論有多少層繼承,虛基類的構造函數必須且只能被調用一次。
若在初始化列表中沒有顯式調用虛基類的構造函數,則將調用虛基類的默認構造函數。若虛基類沒有定義默認構造函數,則編譯錯誤。
2.5.5虛函數
在基類中不能給出虛函數有意義的實現,而把它聲明爲純虛函數,他的實現留給基類的派生類去作。
a.兩種常見的抽象類
凡有純虛函數 的類叫抽象類(抽象接口),這種類不能聲明對象,只是做爲基類爲派生類服務。除非在派生類中徹底實現基類中的全部純虛函數,不然,派生類也是抽象類,不能實例化對象。
只定義了protected型構造函數的類也是抽象類。對於一個類,若是隻定義了protected構造函數而沒有提供public構造函數,不管是外部仍是派生類中都不能建立該類的對象,但能派生出新類,這種能派生出新類,但不能建立本身對象的類叫另一種形式的抽象類。
3.運行時類型識別與顯示轉換
3.1 typeid
c++經過下面兩種操做符提供RTTI
1)typeid 操做符,返回指針或引用所指對象的實際類型。
2)dynamic_cast操做符,將基類類型的指針或引用安全的轉換爲派生類型的指針或引用。
只有當typeid的操做數是帶虛函數的類類型的對象時,才返回動態類型信息。
3.2 顯式轉換
c++中的顯式轉換也稱強制類型轉換。包括static_cast、dynamic_cast、 const_cas、 reinterpret_cast。
在引用命名的強制類型轉換操做符以前,顯式強制類型轉換用圓括號將類型括起來實現。
1) reinterpret_cast
int *ip;
char *pc=(char*) ip;
效果與reinterpret_cast相同。
int *ip;
char *pc=reinterpret_cast<char*> ip;
2) const_cast
除了添加和刪除const特性,用const_cast符執行其餘任何類型轉換都會引發編譯錯誤。
3)static_cast
編譯器隱式執行的任何類型轉換均可以由static_cast顯式完成。
只有當類型之間可隱式轉換時(除類層次間的下行轉化除外),static_cast的轉換纔是合法的。不然出錯。類層次間的下行轉化不能經過隱式轉換完成。
使用static_cast完成下行轉換(把基類指針或引用轉換爲子類指針或引用),因爲沒有動態類型檢查,因此不安全。
c++的基本類型的指針之間不含隱式轉換(除void*)須要顯示轉換。故char* 不能隱式轉換爲int*。
4)dynamic_cast
把expression轉換爲type類型的對象,type必須是類的指針,類的引用或void*
a.tpye和expression的類型須要一致,都爲指針或引用。
與其餘轉換類型不一樣,dynamic_cast 涉及運行時類型檢查,而這個運行時類型信息存儲在類的虛函數表裏,只有定義了虛函數的類纔有虛函數表,對沒有虛函數表的類在使用時會致使dynamic_cast編譯錯誤。若是綁定到引用或指針的對象的類型不是目標類型,則dynamic_cast失敗。若是轉換到指針類型的dynamic_cast失敗,則dynamic_cast的結果爲0.若是轉換到dynamic_cast失敗,則拋出一個bad_cast類型的異常。dynamic_cast操做符執行兩個操做。首先驗證請求的轉換是否有效,操做符執行的驗證是在運行時進行的。
b.dynamic_cast主要用於類層次間的上行轉換和下行轉換
dynamic_cast運算符能夠在執行期決定真正的類型。若是下行轉換時安全的(基類的指針或引用執行一個派生類對象)這個運算符會傳回轉型過的指針。若是downcast不安全,這個運算符會傳回空指針(基類的指針或引用沒有指向一個派生類對象)
在類間進行上行轉換時,dynamic_cast和static_cast的效果同樣。
在類間進行下行轉換時,dynamic_cast具備類型檢查功能,比static_cast更加安全。
在運行dynamic_cast時必須包括多態類型。static_cast則沒有這個限制。