【C++ Priemr | 15】虛函數常見問題

1. 在成員函數中調用虛函數:

#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;
}

輸出結果:

分析:

  • 第 20 行調用 func1 成員函數。進入 func1 成員函數,執行到第 8 行,調用 func2 函數。看起來調用的應該是 CBase 類的 func2 成員函數,但輸出結果證明實際上調用的是 CDerived 類的 func2 成員函數。這是因為,在 func1 函數中,func2();等價于this -> func2();,而 this 指針顯然是 CBase* 類型的,即是一個基類指針,那么this -> func2();就是在通過基類指針調用虛函數,因此這條函數調用語句就是多態的。
  • 當本程序執行到第 8 行時,this 指針指向的是一個 CDerived 類的對象,即 d,因此被調用的就是 CDerived 類的 func2 成員函數。

?

2.?在構造函數和析構函數中調用虛函數

#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;
}

輸出結果:

分析:

  • 類 A 派生出類 B,類 B 派生出類 C。
  • 第 23 行,obj 對象生成時會調用類 B 的構造函數,在類 B 的構造函數中調用 hello 成員函數。由于在構造函數中調用虛函數不是多態,所以此時不會調用類 C 的 hello 成員函數,而是調用類 B 自己的 hello 成員函數。
  • obj 對象消亡時,會引發類 B 析構函數的調用,在類 B 的析構函數中調用了 bye 函數。類B沒有自己的 bye 函數,只有從基類 A 繼承的 bye 函數,因此執行的就是類 A 的 bye 函數。
  • 將在構造函數中調用虛函數實現為多態是不合適的。以上面的程序為例,obj 對象生成時,要先調用基類構造函數初始化其中的基類部分。在基類構造函數的執行過程中,派生類部分還未完成初始化。此時,在基類 B 的構造函數中調用派生類 C 的 hello 成員函數,很可能是不安全的。

?

2. 為什么基類中的析構函數要聲明為虛析構函數?

直接的講,C++中基類采用virtual虛析構函數是為了防止內存泄漏。具體地說,如果派生類中申請了內存空間,并在其析構函數中對這些內存空間進行釋放。假設基類中采用的是非虛析構函數,當刪除基類指針指向的派生類對象時就不會觸發動態綁定,因而只會調用基類的析構函數,而不會調用派生類的析構函數。那么在這種情況下,派生類中申請的空間就得不到釋放從而產生內存泄漏。所以,為了防止這種情況的發生,C++中基類的析構函數應采用virtual虛析構函數。

實例代碼:?

#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;
}

輸出結果:

?

實例代碼:

#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;
}

輸出結果:

?

?

參考資料:

  • C++調用虛函數的注意事項

?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/385335.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/385335.shtml
英文地址,請注明出處:http://en.pswp.cn/news/385335.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

965. 單值二叉樹

如果二叉樹每個節點都具有相同的值&#xff0c;那么該二叉樹就是單值二叉樹。 只有給定的樹是單值二叉樹時&#xff0c;才返回 true&#xff1b;否則返回 false。 示例 1&#xff1a; 輸入&#xff1a;[1,1,1,1,1,null,1] 輸出&#xff1a;true示例 2&#xff1a; 輸入&#…

信號四要素

與變量三要素&#xff08;類型、名字、值&#xff09;類似的&#xff0c;每個信號也有其必備4要素&#xff0c;分別是&#xff1a;1.編號&#xff1b;2.名稱&#xff08;即編號的宏定義&#xff09; &#xff1b;3.事件&#xff08;引起信號產生的事件&#xff0c;如段錯誤&…

958. 二叉樹的完全性檢驗

給定一個二叉樹&#xff0c;確定它是否是一個完全二叉樹。 百度百科中對完全二叉樹的定義如下&#xff1a; 若設二叉樹的深度為 h&#xff0c;除第 h 層外&#xff0c;其它各層 (1&#xff5e;h-1) 的結點數都達到最大個數&#xff0c;第 h 層所有的結點都連續集中在最左邊&a…

信號的產生

&#xff08;1&#xff09;終端按鍵產生信號&#xff08;與終端交互的進程&#xff09; Ctrl c → 2) SIGINT&#xff08;終止/中斷&#xff09; "INT" ----Interrupt Ctrl z → 20) SIGTSTP&#xff08;暫停/停止&#xff09; "T" ----Termin…

897. 遞增順序查找樹

給定一個樹&#xff0c;按中序遍歷重新排列樹&#xff0c;使樹中最左邊的結點現在是樹的根&#xff0c;并且每個結點沒有左子結點&#xff0c;只有一個右子結點。 示例 &#xff1a; 輸入&#xff1a;[5,3,6,2,4,null,8,1,null,null,null,7,9]5/ \3 6/ \ \2 4 8/ …

信號集操作函數

內核通過讀取未決信號集來判斷信號是否應被處理。信號屏蔽字mask可以影響未決信號集。而我們可以在應用程序中自定義set來改變mask。已達到屏蔽指定信號的目的。綜上&#xff1a;自定義信號集set&#xff08;也為一個字&#xff0c;64位&#xff09;通過信號集操作函數來改變信…

信號捕捉(signal、sigaction)

信號的基本屬性&#xff1a;軟中斷&#xff0c;由內核發送&#xff0c;內核處理。某個進程通過內核向另一個進程發送信號時&#xff08;引起信號產生的五個因素&#xff09;&#xff0c;另一個進程將會陷入內核進行中斷處理&#xff0c;未決信號集中相應信號置1&#xff0c;當遞…

1090 Highest Price in Supply Chain (25)(25 分)

A supply chain is a network of retailers&#xff08;零售商&#xff09;, distributors&#xff08;經銷商&#xff09;, and suppliers&#xff08;供應商&#xff09;-- everyone involved in moving a product from supplier to customer. Starting from one root suppli…

時序競態(競態條件)

產生原因&#xff1a;仍然以前文實現的sleep函數為例&#xff0c;如果進程在執行完alarm函數后&#xff0c;突然失去CPU&#xff0c;被阻塞等待&#xff08;這是有可能的&#xff0c;進程在執行過程中&#xff0c;若非原子操作&#xff0c;都有可能隨時失去CPU&#xff09;&…

1106 Lowest Price in Supply Chain (25)

A supply chain is a network of retailers&#xff08;零售商&#xff09;, distributors&#xff08;經銷商&#xff09;, and suppliers&#xff08;供應商&#xff09;-- everyone involved in moving a product from supplier to customer. Starting from one root suppli…

【Leetcode | 順序刷題 】二分查找目錄

二分查找序號題號129. 兩數相除 50. Pow(x, n) 69. x 的平方根

sigsuspend函數(mysleep函數的改進)

可以通過設置屏蔽SIGALRM的方法來控制程序執行邏輯&#xff0c;但無論如何設置&#xff0c;程序都有可能在“解除信號屏蔽”與“掛起等待信號”這個兩個操作間隙失去cpu資源。除非將這兩步驟合并成一個“原子操作”。sigsuspend函數具備這個功能。在對時序要求嚴格的場合下都應…

【Leetcode | 順序刷題】數學目錄

序號題號1 7. 整數反轉 28. 字符串轉換整數 (atoi)39. 回文數443. 字符串相乘

全局變量的異步I/O問題

全局變量的異步I/O問題同樣屬于時序競態問題&#xff0c;其本質就是多個進程或者同一個進程中的多個時序&#xff08;如主控程序和信號捕捉時的用戶處理函數&#xff09;對同一個變量進行修改時&#xff0c;它們的執行順序不一樣就會導致該變量最終的值不一樣&#xff0c;從而產…

【Leetcode | 03】String

字符串目錄序號題號33. 無重復字符的最長子串 151. 翻轉字符串里的單詞

可/不可重入函數

一個函數在被調用執行期間&#xff08;尚未調用結束&#xff09;&#xff0c;由于某種時序&#xff08;遞歸或者處理信號捕捉時等情況&#xff09;又被重復調用&#xff0c;稱之為“重入”。根據函數實現的方法可分為“可重入函數”和“不可重入函數”兩種。看如下程序。 可以看…

【Leetcode | 順序刷題】雜項目錄

序號題號類別1136. 只出現一次的數字位運算2137. 只出現一次的數字 II位運算3 260. 只出現一次的數字 III 位運算4191. 位1的個數位運算5231. 2的冪位運算6342. 4的冪位運算7 338. 比特位計數 位運算8405. 數字轉換為十六進制數位運算9371. 兩整數之和位運算10401. 二進制手表位…

SIGCHLD信號

&#xff08;1&#xff09;SIGCHLD信號產生的條件 1.子進程終止時會向父進程發送SIGCHLD信號&#xff0c;告知父進程回收自己&#xff0c;但該信號的默認處理動作為忽略&#xff0c;因此父進程仍然不會去回收子進程&#xff0c;需要捕捉處理實現子進程的回收&#xff1b; 2.子…

信號傳參

&#xff08;1&#xff09;發送信號傳參 前面已經知道從一個進程向另一個進程發送信號可以使用kill函數&#xff0c;但是kill函數在向進程發送信號的時候不能攜帶除了信號以外的其他信息&#xff0c;這時可以使用與kill相對應的sigqueue函數&#xff0c;該函數也是向一個進程發…

【Leetcode | 52】257. 二叉樹的所有路徑

給定一個二叉樹&#xff0c;返回所有從根節點到葉子節點的路徑。 說明: 葉子節點是指沒有子節點的節點。 示例: 輸入: 1 / \ 2 3 \ 5 輸出: ["1->2->5", "1->3"] 解釋: 所有根節點到葉子節點的路徑為: 1->2->5, 1->3 解法一&a…