標籤:style blog color os 資料 io
一、C++為什麼引入虛函數,虛函數有哪些用途?
1.非虛的世界
對象的自恰性:對同樣的函數調用,每個對象都會做出恰當的響應.
b. 通過指向子類對象的基類指標調用函數:
只能調用基類的成員函數,雖然指標指向子類對象.
一旦調用子類所特有的成員函數,將引發編譯錯誤.
c.通過指向基類對象的子真調用函數:
可以調用子類的成員函數,儘管指標指向基類對象.
直接或簡介地訪問子類的成員變數,後果不可預知
d.名字隱藏
子類的成員函數隱藏基類的同名的成員函數.
#include <iostream>#include <string>using namespace std;class Base{public: Base(int data = 0):m_data(data){} void print(void) const { cout << m_data << endl; }private: int m_data;};class Derived:public Base {public: Derived(int data,const string& info): Base(data),m_info(info){} void show(void) const { print(); cout << m_info << endl; } void foo(void) { cout << "Derived::foo(void)" << endl; // m_info = "abc"; }private: string m_info;};int main(void){ Base b(100); Derived *pd = static_cast<Derived*>(&b); /*子類的指標指向父類*/ /*pd->show();*/ /*這裡可以成功調用但是調用的結果是未定義的 因為編譯器在調用的時候只看類型. */ pd = NULL; pd->foo(); //這裡是可以的,因為編譯器在編譯的時候只看類型. ((Derived*)0)->foo(); /*函數並不存在於對象中,調用成員函數的時候, 只要調用的類型是對的,就可以根據類型調用相應的 成員函數.但是這種情況之下不能訪問成員變數*/ return 0;}
2. 虛函數和名字隱藏
class 類名
{
virtual 傳回型別 函數名(形參表){...}
}
的成員函數,稱為虛函數或方法
覆蓋:
如果子類的成員函數和基類的虛函數具有相同的函數原型,那麼該成員
函數就也是虛函數,無論其是否有virtual關鍵字,且對基類的虛函數
構成覆蓋.
還有一種就是如果沒有virtual的時候,只要函數名相同就會形成覆蓋.
3.多態
如果子類提供了對基類虛函數的有效覆蓋,那麼通過一個指向子類對象的基類指標,
或者引用子類對象的基類引用,調用該虛函數,實際被調用的將是子類中覆蓋
版本,而非基類中的原始,這種現象稱之為多態.
多態的重要意義在於,一般的情況下,調用哪個類的成員函數是由調用者指標或引用
本身的類型決定的,而當多態發生的時候,調用哪個類的成員函數則
完全由調動者指標或引用的實際目標對象的類型決定的.
4.有效虛函數的覆蓋要滿足如下的條件
該函數必須是成員函數,既不能是全域函數也不能是靜態成員函數.
該函數必須在基類中用vitual關鍵字聲明為虛函數
覆蓋版本與基類版本必須擁有完全相同的簽名,即是函數名,行參表和常屬性嚴格一致.
如果基類版本返回基礎資料型別 (Elementary Data Type),那麼覆蓋版本必須返回相同的類型的資料.
如果基類版本返回類類型對象的指標或引用,那麼覆蓋版本可以返回
其子類類型對象的指標或引用.