這裡文章的題目是自擬的,只因為自己發現虛函數的訪問控制,與自己之前的理解有出入,於是備忘之。
首先,虛函數是實現多態的機制,也就是說在利用基類的指針或者引用調用虛函數時,調用的是該指針或者引用的動態類型的相應的函數,這裡有幾點需要備忘的。
1 編譯器在決定調用函數時,如果該函數是虛函數才會在運行時確定調用什麼函數,如果不是虛函數,那麼在編譯階段就已經確定了調用的函數類型,如下面的代碼;
基類與派生類都聲明了函數f。但是在main函數的調用中編譯器調用的是靜態類型對應的函數,因為f函數並不是虛函數,雖然在基類與派生類中都聲明了該函數。
這是顯然的,沒有虛函數,就沒有多態了,也就無所謂動態類型了。函數的所有調用都是靜態綁定。
2 基類定義虛函數為public,派生類覆蓋了該虛函數,但是將其聲明為private,這樣當基類的指針綁定到派生類的對象時,使用該基類指針調用該虛函數時,調用是否成功。如果二者的訪問權限反過來呢。
class Base { public: virtual void f(int i=0) {cout << "f() in Base..." << i << endl;} }; class Derived:public Base { private: void f(int i=1){cout << "f() in derived..." << i << endl;} }; int main(void) { Base *b = new Derived(); b->f(); return 0; }
首先分析,為什麼輸出結果是f() in derived. 編譯器在看到b對f進行調用時,此時編譯器根據b的靜態類型(也就是Base)來決定f函數是否可訪問,由於f函數式public的,OK, "訪問控制為public"並沒有影響調用,並且進行形參的默認參數的賦值。
由於f是虛函數,那麼具體調用哪個函數是在運行時確定的,於是,在運行時查找Derived的虛函數表,得到虛函數f(此時的f已經被Derived類覆蓋,於是調用的就是派生類的版本。)
至於,為什麼i的值為0,上述分析也已經說明了,也可以參見文章 點擊打開鏈接
如果將兩者的訪問權限交換,那麼訪問控制這一關都過不了,其實很簡單,既然你需要派生類繼承f函數,將其在Base類中聲明為private本身就是不對的。