<1>注意:基類的指標不能呼叫派生類自己定義的函式,只能呼叫虛函式!因為呼叫普通函式時是繫結靜態的,呼叫虛函式時才動態繫結。
為了支援c++的多型性,才用了動態繫結和靜態繫結。理解他們的區別有助於更好的理解多型性,以及在程式設計的過程中避免犯錯誤。需要理解四個名詞:
物件的靜態型別:物件在宣告時採用的型別,是在編譯期確定的。
物件的動態型別:目前所指物件的型別,是在執行期決定的。物件的動態型別可以更改,但是靜態型別無法更改。
靜態繫結:繫結的是物件的靜態型別,某特性(比如函式)依賴於物件的靜態型別,發生在編譯期。
動態繫結:繫結的是物件的動態型別,某特性(比如函式)依賴於物件的動態型別,發生在執行期。
//基類的指標不可以呼叫派生類自身定義的函式(不是虛函式)
#include
using namespace std;
class base
};class derived:public base
}; int main(void)
<2>虛函式的訪問控制(編譯器根據物件的靜態型別來決定訪問控制許可權,並且進行形參的預設引數的賦值!)
虛函式是實現多型的機制,也就是說在利用基類的指標或者引用呼叫虛函式時,呼叫的是該指標或者引用的動態型別的相應的函式,這裡有幾點需要注意的。
(1)編譯器在決定呼叫函式時,如果該函式是虛函式才會在執行時確定呼叫什麼函式(動態繫結),如果不是虛函式,那麼在編譯階段就已經確定了呼叫的函式型別(靜態繫結)。
如下面的**,基類與派生類都宣告了函式f。但是在main函式的呼叫中編譯器呼叫的是靜態型別對應的函式,因為f函式並不是虛函式,雖然在基類與派生類中都宣告了該函式。
class base
};class derived:public base
};int main(void)
(2)如下基類定義虛函式為public,派生類覆蓋了該虛函式,但是將其宣告為private,這樣當基類的指標繫結到派生類的物件時,使用該基類指標呼叫該虛函式時,呼叫是否成功。如果二者的訪問許可權反過來呢。
class base
};class derived:public base};
int main(void)
//輸出為: f() in derived 0
【分析】首先分析為什麼輸出結果是f() in derived。 編譯器在看到b對f進行呼叫時,此時編譯器根據b的靜態型別(也就是base)來決定f函式是否可訪問
,並且進行形參的預設引數的賦值!!
由於f是虛函式,那麼具體呼叫哪個函式是在執行時確定的,於是在執行時查詢derived的虛函式表,得到虛函式f(此時的f已經被derived類覆蓋,於是呼叫的就是派生類的版本。)
至於,為什麼i的值為0,上述分析也已經說明。
如果將兩者的訪問許可權交換,那麼訪問控制這一關都過不了,其實很簡單,既然你需要派生類繼承f函式,將其在base類中宣告為private本身就是不對的。
<3>推薦閱讀
C 程式設計師應了解的那些事(98)關於C 異常
本文是作者翻譯過c 之父bjarne stroustrup的技術文章c 核心準則中有關c 中異常的文章之後的總結 異常處理機制希望解決的問題 為了使用錯誤處理系統化,健壯和不繁瑣。例如下面的 void f2 int i clumsy and error prone explicit release ...
程式設計師那些事 程式設計師的迷茫?!
程式設計師從來不迷茫,迷茫的是為啥一直是程式設計師!對於乙個工作多年的程式設計師來說,自己想的是工作這麼多年,理應手到擒來,沒想到年紀越大,要學的東西越多,新東西天天有,學的學的,自己就疲乏了。有時候想做管理,徹底告別這種勞碌,可是自己明白,管理也不是這麼好幹的,沒有幾分管理經驗,怎麼幹管理呢?面試...
關於資料庫,程式設計師應該了解的那些事
對於很多程式設計師來說,公司選擇什麼樣的資料庫,基本不需要你來決定。當你加入乙個公司的時候,公司的大部分技術選型已經確認,特別是資料庫選型,因為資料庫一旦選擇,後期遷移的代價還是很大的。隨著大資料時代的來臨,湧現出了很多新型資料庫,在公司遇到資料效能瓶頸,喊去ioe口號或者是想嘗鮮時,都會慢慢的使用...