1、用virtual關鍵字說明的函數
2、虛函數是實現運行時多態性的基礎
3、C++中的虛函數是動態綁定的函數
4、虛函數必須是非靜態的成員函數,虛函數經過派生之後,就可以實現運行過程中的多態
Ex:
#includeusing namespace std; class Base1 { public: virtual void display() const; //虛函數 }; void Base1::display() const { cout << "Base1::display()" << endl; } class Base2::public Base1 { public: virtual void display() const; }; void Base2::display() const { cout << "Base2::display()" << endl; } class Derived: public Base2 { public: virtual void display() const; }; void Derived::display() const { cout << "Derived::display()" << endl; } void fun(Base1 *ptr) { ptr->display(); } int main() { Base1 base1; Base2 base2; Derived derived; fun(&base1); fun(&base2); fun(&derived); return 0; }
1、一般成員函數可以是虛函數
2、構造函數不能是虛函數
3、析構函數可以是虛函數
1、虛函數的聲明
virtual 函數類型 函數名(形參表)
2、虛函數聲明只能出現在類定義中的函數原型聲明中,而不能在成員函數實現的時候。
3、在派生類中可以對基類中的成員函數進行覆蓋
4、虛函數一般不聲明為內聯函數,因為對虛函數的調用需要動態綁定,而對內聯函數的處理是靜態的
5、千萬不要重寫繼承而來的非虛函數
1、派生類可以不顯式地用virtual聲明虛函數,這時系統就會用以下規則來判斷派生類的一個函數成員是不是虛函數:
(1)該函數是否與基類的虛函數有相同的名稱,參數個數及對應參數類型
(2)該函數是否與基類的虛函數有相同的返回值或者滿足類型兼容規則的指針,引用型的返回值。
2、如果從名稱、參數及返回值三個方面檢查之後,派生類的函數滿足上述條件,就會自動確定為虛函數。這時派生類的虛函數便覆蓋了基類的虛函數。
3、派生類中的虛函數還會隱藏基類中同名函數的所有其它重載形式。
4、一般習慣於在派生類的函數中也使用virtual關鍵字以增加程序的可讀性。
如果你打算允許其他人通過基類指針調用對象的析構函數(通過delete這樣做是正常的)就需要讓基類的析構函數成為虛函數,否則執行delete的結果是不確定的。
Ex:如下面的程序,如果不使用虛析構函數,那麼只會執行基類的析構函數,而不會執行派生類的析構函數
#includeusing namespace std; class Base { public: ~Base(); //不是虛函數 }; Base::~Base() { cout<< "Base destructor" << endl; } class Derived: public Base{ public: Derived(); ~Derived(); //不是虛函數 private: int *p; }; Derived::Derived() { p=new int(0); } Derived::~Derived() { cout<<"Derived Constructor"< using namespace std; class Base { public: virtual ~Base(); }; Base::~Base() { cout<< "Base destructor" << endl; } class Derived: public Base{ public: Derived(); virtual ~Derived(); private: int *p; };
1、每個多態類有一個虛表(virtual table)
2、虛表中有當前類的各個虛函數的入口地址
3、每個對象有一個指向當前類的虛表的指針(虛指針vptr)
1、構造函數中為對象的虛指針賦值
2、通過多態類型的指針或引用調用成員函數時,通過虛指針找到虛表,進而找到所調用的虛函數的入口地址
3、通過該入口地址調用虛函數
class Base{ public: virtual void f(); virtual void g(); private: int i; }; class Derived:public Base{ public: virtual void f(); //覆蓋Base::f() virtual void h(); //新增 private: int j; };