【C++ Priemr | 15】虚函数常见问题
生活随笔
收集整理的這篇文章主要介紹了
【C++ Priemr | 15】虚函数常见问题
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
1. 在成員函數(shù)中調(diào)用虛函數(shù):
#include <iostream> using namespace std; class CBase { public:void func1(){func2();}virtual void func2() { cout << "CBase::func2()" << endl; } }; class CDerived : public CBase { public:virtual void func2() { cout << "CDerived:func2()" << endl; } }; int main() {CDerived d;d.func1();return 0; }輸出結(jié)果:
分析:
- 第 20 行調(diào)用 func1 成員函數(shù)。進(jìn)入 func1 成員函數(shù),執(zhí)行到第 8 行,調(diào)用 func2 函數(shù)。看起來調(diào)用的應(yīng)該是 CBase 類的 func2 成員函數(shù),但輸出結(jié)果證明實(shí)際上調(diào)用的是 CDerived 類的 func2 成員函數(shù)。這是因?yàn)?#xff0c;在 func1 函數(shù)中,func2();等價(jià)于this -> func2();,而 this 指針顯然是 CBase* 類型的,即是一個(gè)基類指針,那么this -> func2();就是在通過基類指針調(diào)用虛函數(shù),因此這條函數(shù)調(diào)用語句就是多態(tài)的。
- 當(dāng)本程序執(zhí)行到第 8 行時(shí),this 指針指向的是一個(gè) CDerived 類的對(duì)象,即 d,因此被調(diào)用的就是 CDerived 類的 func2 成員函數(shù)。
?
2.?在構(gòu)造函數(shù)和析構(gòu)函數(shù)中調(diào)用虛函數(shù)
#include <iostream> using namespace std; class A { public:virtual void hello() { cout << "A::hello" << endl; }virtual void bye() { cout << "A::bye" << endl; } }; class B : public A { public:virtual void hello() { cout << "B::hello" << endl; }B() { hello(); }~B() { bye(); } }; class C : public B { public:virtual void hello() { cout << "C::hello" << endl; } }; int main() {C obj;return 0; }輸出結(jié)果:
分析:
- 類 A 派生出類 B,類 B 派生出類 C。
- 第 23 行,obj 對(duì)象生成時(shí)會(huì)調(diào)用類 B 的構(gòu)造函數(shù),在類 B 的構(gòu)造函數(shù)中調(diào)用 hello 成員函數(shù)。由于在構(gòu)造函數(shù)中調(diào)用虛函數(shù)不是多態(tài),所以此時(shí)不會(huì)調(diào)用類 C 的 hello 成員函數(shù),而是調(diào)用類 B 自己的 hello 成員函數(shù)。
- obj 對(duì)象消亡時(shí),會(huì)引發(fā)類 B 析構(gòu)函數(shù)的調(diào)用,在類 B 的析構(gòu)函數(shù)中調(diào)用了 bye 函數(shù)。類B沒有自己的 bye 函數(shù),只有從基類 A 繼承的 bye 函數(shù),因此執(zhí)行的就是類 A 的 bye 函數(shù)。
- 將在構(gòu)造函數(shù)中調(diào)用虛函數(shù)實(shí)現(xiàn)為多態(tài)是不合適的。以上面的程序?yàn)槔?#xff0c;obj 對(duì)象生成時(shí),要先調(diào)用基類構(gòu)造函數(shù)初始化其中的基類部分。在基類構(gòu)造函數(shù)的執(zhí)行過程中,派生類部分還未完成初始化。此時(shí),在基類 B 的構(gòu)造函數(shù)中調(diào)用派生類 C 的 hello 成員函數(shù),很可能是不安全的。
?
2. 為什么基類中的析構(gòu)函數(shù)要聲明為虛析構(gòu)函數(shù)?
直接的講,C++中基類采用virtual虛析構(gòu)函數(shù)是為了防止內(nèi)存泄漏。具體地說,如果派生類中申請(qǐng)了內(nèi)存空間,并在其析構(gòu)函數(shù)中對(duì)這些內(nèi)存空間進(jìn)行釋放。假設(shè)基類中采用的是非虛析構(gòu)函數(shù),當(dāng)刪除基類指針指向的派生類對(duì)象時(shí)就不會(huì)觸發(fā)動(dòng)態(tài)綁定,因而只會(huì)調(diào)用基類的析構(gòu)函數(shù),而不會(huì)調(diào)用派生類的析構(gòu)函數(shù)。那么在這種情況下,派生類中申請(qǐng)的空間就得不到釋放從而產(chǎn)生內(nèi)存泄漏。所以,為了防止這種情況的發(fā)生,C++中基類的析構(gòu)函數(shù)應(yīng)采用virtual虛析構(gòu)函數(shù)。
實(shí)例代碼:?
#include <iostream> #include <memory> using namespace std;class Base { public:Base() { cout << "Base Constructor" << endl; }~Base() { cout << "Base Destructor" << endl; } };class Derived : public Base { public:Derived() { cout << "Derived Constructor" << endl; }~Derived() { cout << "Derived Destructor" << endl; } };int main() {Base* p = new Derived();delete p;return 0; }輸出結(jié)果:
?
實(shí)例代碼:
#include <iostream> #include <memory> using namespace std;class Base { public:Base() { cout << "Base Constructor" << endl; }virtual ~Base() { cout << "Base Destructor" << endl; } };class Derived : public Base { public:Derived() { cout << "Derived Constructor" << endl; }virtual ~Derived() { cout << "Derived Destructor" << endl; } };int main() {Base* p = new Derived();delete p;return 0; }輸出結(jié)果:
?
?
參考資料:
- C++調(diào)用虛函數(shù)的注意事項(xiàng)
?
總結(jié)
以上是生活随笔為你收集整理的【C++ Priemr | 15】虚函数常见问题的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【C++ Primer | 13】课后习
- 下一篇: C++设计模式之策略模式(Strateg