【C++】虚函数
虛函數是構成C++多態的重要一步,今天來說一下虛函數!
虛函數:
在基類(或父類)中,使用virtual關鍵字對函數進行聲明為并在一個或多個派生類(子類)中被重新定義的成員函數,通過指向派生類的基類指針或引用,訪問派生類中同名覆蓋成員函數。
它的用法是這樣的:virtual + 函數返回類型 + 函數名 +(參數表) {函數體}
首先我們要知道為什么要有虛函數這個東西?
我來看下下面這兩段代碼的結果再來說結果:
class A
{
public:void fun(){cout << "class A" << endl;}
};class B : public A
{
public:void fun(){cout << "class B" << endl;}
};int main()
{A* p = new B;p->fun();return 0;
}
上述代碼很簡單,A* p = new B;創建B對象,拿A類型指針指向它,最后運行時,輸出的是
?
但是我明明創建的是B對象啊,為什么會運行class A中的fun函數呢?來看下面代碼演示:
class A
{
public:virtual void fun(){cout << "class A" << endl;}
};class B :public A
{
public:virtual void fun(){cout << "class B" << endl;}
};int main()
{A* p = new B;p->fun();return 0;
}
和上述代碼的唯一區別就是在父類A中和派生類中的fun函數中加了virtual,聲明為虛函數
,運行結果是:
?
這個運行結果就達到了我們的預期結果,但是為什么加上virtual聲明之后運行結果就不同了呢?
?虛函數的原理:
class A
{int num;
public:A(int x = 10){}virtual void fun(){cout << "class A" << endl;}
};class B :public A
{int sum;
public:B(int x = 10){}virtual void fun(){cout << "class B" << endl;}
};int main()
{B b(10);A a(50);A* p = &b;return 0;
}
來看下面的代碼分析:
?通過上面我們知道了虛函數的原理,下面我來看一下派生類中成員函數對父類的完全覆蓋和部分覆蓋的區別:
完全覆蓋(基類中所有的虛函數都在子類中被重寫)
class A
{int num;
public:A(int x = 10){}virtual void fun(){cout << "class A" << endl;}virtual void pun(){cout << "class A::pun" << endl;}
};class B :public A
{int sum;
public:B(int x = 10){}virtual void fun(){cout << "class B" << endl;}virtual void pun(){cout << "class B::pun" << endl;}};int main()
{B b(10);A* p = &b;p->fun();p->pun();return 0;
}
運行結果:都是調用B中的函數? 沒問題,符合我們的預期!
?部分覆蓋(基類部分函數在派生類中沒有進行重寫或者是派生類聲明了一些基類中沒有的虛函數):
class A
{int num;
public:A(int x = 10){}virtual void fun(){cout << "class A" << endl;}virtual void pun(){cout << "class A::pun" << endl;}
};class B :public A
{int sum;
public:B(int x = 10){}virtual void fun(){cout << "class B" << endl;}virtual void show() //將class B中的成員函數pun改成show函數{cout << "class B::pun" << endl;}};int main()
{B b(10);A* p = &b;p->fun();p->pun();return 0;
}
首先來看,p指向的函數有兩個,fun和pun,但是沒有我們剛剛改過的函數show,也就是說,如果在基類中沒有的成員函數,但是在繼承類中聲明為虛函數,也不起作用,不能通過指針來指向。
?運行結果:
?因此想要派生類和基類在函數名相同但是實現不同功能的同時,必須函數名相同,如果在派生類中重寫基類中沒有的函數,聲明為虛函數也沒用,不可以通過上述代碼中的指針或引用來調用。只可以通過實例化對象來實現對函數的調用(這塊雖然show函數聲明為虛函數,本質相當于普通成員函數)
總結:
1.父類子類虛函數之間的關系不是重載,而是重寫(同名覆蓋)。
2.父類指針指向派生類對象的地址,若在有派生類中有基類的重寫成員函數,那么父類指針就可以通過虛表去調用派生類的同名覆蓋的函數,如若派生類將 基類沒有的函數 聲明為virtual虛函數,那么就不可以通過基類的指針去之現象該函數,只可以 通過實例化派生類對象去調用這個普通成員函數。
總結
- 上一篇: 上海欢乐谷能带水和零食吗
- 下一篇: 【C++】多态(早期绑定、后期绑定)、抽