C++如何在構(gòu)造函數(shù)和析構(gòu)函數(shù)中調(diào)用虛擬函數(shù)
C++構(gòu)造函數(shù)和析構(gòu)函數(shù)中調(diào)用虛擬函數(shù)
C++構(gòu)造器可以為虛擬函數(shù)嗎?
不行。
因為構(gòu)造器調(diào)用的時候會設(shè)置當(dāng)前類的虛表地址,然后如果構(gòu)造函數(shù)本身為虛擬函數(shù),那么調(diào)用構(gòu)造函數(shù)就需要提前訪問虛表,此時虛表指針還沒有指向虛表,就沒法訪問虛表。
構(gòu)造函數(shù)中可以調(diào)用虛擬函數(shù)嗎?
可以。
但是調(diào)用虛擬函數(shù)就是調(diào)用跟調(diào)用普通函數(shù)效果一樣。
因為子類在創(chuàng)建的時候是先調(diào)用父類的構(gòu)造器,父類的構(gòu)造器先設(shè)置好父類的虛表地址,然后再執(zhí)行構(gòu)造器中的代碼,然后在回到子類構(gòu)造器,先將虛表地址替換為子類的虛表地址,然后執(zhí)行子類構(gòu)造器的代碼。
因此如果在父類構(gòu)造器中調(diào)用虛函數(shù),那么此時是從父類的虛表中查找函數(shù)地址,查找到的還是父類的虛函數(shù)地址。因此會調(diào)用父類的虛函數(shù),而不會調(diào)用子類的虛函數(shù)。
析構(gòu)函數(shù)中可以調(diào)用虛擬函數(shù)嗎?
可以。
但是調(diào)用虛擬函數(shù)跟調(diào)用普通函數(shù)沒啥區(qū)別。
因為析構(gòu)的時候先執(zhí)行子類的析構(gòu)函數(shù),再執(zhí)行父類的析構(gòu)函數(shù),在執(zhí)行當(dāng)前類的析構(gòu)函數(shù)的時候會先將虛表地址設(shè)置為當(dāng)前類的虛表地址,然后再從虛表里查找函數(shù)地址,因此找到的只能是當(dāng)前的虛函數(shù)的地址。
父類的析構(gòu)函數(shù)為什么要為虛函數(shù)?
因為如果父類析構(gòu)函數(shù)不為虛函數(shù),那么當(dāng)對象析構(gòu)的時候只會調(diào)用指針當(dāng)前類型的析構(gòu)函數(shù),不會調(diào)用父類或者子類的析構(gòu)函數(shù),會導(dǎo)致資源泄漏。
如果父類的析構(gòu)函數(shù)為虛函數(shù),那么子類的析構(gòu)函數(shù)在析構(gòu)的時候會先調(diào)用子類的析構(gòu)函數(shù),再調(diào)用父類的析構(gòu)函數(shù)。這樣子就不會存在資源泄漏。
注:
(1)將子類和父類構(gòu)造器和析構(gòu)器調(diào)用串起來是編譯器實現(xiàn)的
(2)子類和父類都有自己的虛表。子類或者父類的構(gòu)造器和析構(gòu)器在最開始都是將虛表設(shè)置為當(dāng)前類的虛表。然后才真正調(diào)用構(gòu)造函數(shù)和析構(gòu)函數(shù)里的代碼。
C++構(gòu)造函數(shù)和析構(gòu)函數(shù)的調(diào)用順序
1、構(gòu)造函數(shù)的調(diào)用順序
基類構(gòu)造函數(shù)、對象成員構(gòu)造函數(shù)、派生類本身的構(gòu)造函數(shù)
2、析構(gòu)函數(shù)的調(diào)用順序
派生類本身的析構(gòu)函數(shù)、對象成員析構(gòu)函數(shù)、基類析構(gòu)函數(shù)(與構(gòu)造順序正好相反)
3、特例
- 局部對象,在退出程序塊時析構(gòu)
- 靜態(tài)對象,在定義所在文件結(jié)束時析構(gòu)
- 全局對象,在程序結(jié)束時析構(gòu)
- 繼承對象,先析構(gòu)派生類,再析構(gòu)父類
- 對象成員,先析構(gòu)類對象,再析構(gòu)對象成員
#include "stdafx.h" #include <iostream> using namespace std; class ?Clock { public: ?? ?Clock() ?? ?{ ?? ??? ?cout << "clock的構(gòu)造函數(shù)" << ","; ?? ?} ?? ?~Clock() ?? ?{ ?? ??? ?cout << "clock的析構(gòu)函數(shù)" << ","; ?? ?} }; class Date { public: ?? ?Date() ?? ?{ ?? ??? ?cout << "date的構(gòu)造函數(shù)" << ","; ?? ?} ?? ?~Date() ?? ?{ ?? ??? ?cout << "date的析構(gòu)函數(shù)" << ","; ?? ?} }; void main() { ? ? Clock c; ?? ?Date d; ?? ?system("pause"); }
在使用構(gòu)造函數(shù)和析構(gòu)函數(shù)時,需要特別注意對它們的調(diào)用時間和調(diào)用順序。
在一般情況下,調(diào)用析構(gòu)函數(shù)的次序正好與調(diào)用構(gòu)造函數(shù)的次序相反:最先被調(diào)用的構(gòu)造函數(shù),其對應(yīng)的(同一對象中的)析構(gòu)函數(shù)最后被調(diào)用,而最后被調(diào)用的構(gòu)造函數(shù),其對應(yīng)的析構(gòu)函數(shù)最先被調(diào)用。
可以簡記為:先構(gòu)造的后析構(gòu),后構(gòu)造的先析構(gòu),它相當(dāng)于一個棧,先進(jìn)后出
總結(jié)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
VC++實現(xiàn)View內(nèi)容保存為圖片的方法
這篇文章主要介紹了VC++實現(xiàn)View內(nèi)容保存為圖片的方法,涉及VC++中Bitmap類的save方法相關(guān)使用技巧,需要的朋友可以參考下2016-08-08基于Matlab實現(xiàn)離散系統(tǒng)分岔圖的繪制
這篇文章主要介紹了如何利用Matlab實現(xiàn)離散分岔圖的繪制,文中的示例代碼講解詳細(xì),對我們學(xué)習(xí)Matlab有一定的幫助,需要的可以參考一下2022-04-04VSCode斷點調(diào)試CMake工程項目的實現(xiàn)步驟
這篇文章主要介紹了VSCode斷點調(diào)試CMake工程項目的實現(xiàn)步驟,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-03-03C++內(nèi)存四區(qū)之代碼區(qū)、全局區(qū)、棧區(qū)和堆區(qū)
C++編譯器會把代碼直接分為四個小區(qū),弄懂這四小區(qū)對我們理解內(nèi)存有所幫助,所以下面這篇文章主要給大家介紹了關(guān)于C++內(nèi)存四區(qū)之代碼區(qū)、全局區(qū)、棧區(qū)和堆區(qū)的相關(guān)資料,需要的朋友可以參考下2021-07-07C++實現(xiàn)Window環(huán)境聊天室功能
這篇文章主要為大家詳細(xì)介紹了C++實現(xiàn)Window環(huán)境聊天室功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-06-06