C 程式設計師應了解的那些事(7)虛函式的訪問控制

2021-10-08 14:19:28 字數 1700 閱讀 3602

<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口號或者是想嘗鮮時,都會慢慢的使用...