【C++】浅析析构函数(基类中)为什么要写成虚基类?
為什么有了虛析構(gòu)函數(shù),就能先調(diào)用子類的析構(gòu)函數(shù)?
class A {virtual ~A(){}
};class B : A {virtual ~B(){}
};A *p = new B();
delete p;
唯一差別是,每個析構(gòu)函數(shù)結(jié)束時(shí)會自動(隱含地)調(diào)上父類的析構(gòu)函數(shù),而普通虛函數(shù)并不會
本質(zhì)上 當(dāng)類里面有定義虛函數(shù)時(shí),編譯器會給類增加一個虛函數(shù)表,里面來存放虛函數(shù)指針,這樣就增加了類的存儲空間
會發(fā)現(xiàn),當(dāng)基類的析構(gòu)函數(shù)不為虛函數(shù)時(shí),當(dāng)基類對象操控派生類對象以及對象成員時(shí),當(dāng)程序結(jié)束時(shí)會發(fā)現(xiàn),派生類的析構(gòu)沒有調(diào)用,存在潛在的內(nèi)存泄漏問題。(一句話,保證delete即指針時(shí),正確運(yùn)行析構(gòu)函數(shù))
1.首先說一下,析構(gòu)順序
派生類–> 成員類 --> 基類
2.為什么需要把基類設(shè)置為虛析構(gòu)
因?yàn)槎鄳B(tài)
? 在c++中,可以使用父類指針指向子類,產(chǎn)生多態(tài)行為
代碼
#include <iostream>
class TestFather{
public:~TestFather() {std::cout << "~TestFather()" << std::endl;}
};
class TestChild : public TestFather {
public:~TestChild() {std::cout << "~TestChild()" << std::endl;}
};int main() {TestFather* p = new TestChild();delete p;
}//
執(zhí)行結(jié)果
~TestFather()
原因就是,你直接給編譯器一個TestFather指針,delete的時(shí)候,編譯器一看這不就是TestFather,直接調(diào)用TestFather析構(gòu)函數(shù)
換成虛析構(gòu)呢
代碼
#include <iostream>
class TestFather{
public:virtual ~TestFather() {std::cout << "~TestFather()" << std::endl;}
};
class TestChild : public TestFather {
public:~TestChild() {std::cout << "~TestChild()" << std::endl;}
};int main() {TestFather* p = new TestChild();delete p;
}///
執(zhí)行結(jié)果
~TestChild()
~TestFather()
正確了,在delete的時(shí)候,編譯器會先看TestFather的析構(gòu)函數(shù)是不是虛函數(shù),如果是的話才會產(chǎn)生正常的析構(gòu)順序行為,派生類–>成員類–>基類
3. 虛析構(gòu)函數(shù)的本質(zhì)
虛析構(gòu)其實(shí)也就是虛函數(shù)加上析構(gòu)函數(shù),本質(zhì)就是會維護(hù)一個虛表和指向虛表的指針,在上面代碼中TestFather這里面的虛表就只有~TestFather()這一個函數(shù),使用虛函數(shù)代表會增加一個指針的內(nèi)存開銷
4. 默認(rèn)的析構(gòu)函數(shù)
當(dāng)我們不定義虛構(gòu)函數(shù)的時(shí)候,編譯器會默認(rèn)生成一個什么都不做的析構(gòu)函數(shù),但是注意了默認(rèn)生成的析構(gòu)函數(shù)就是普通函數(shù)不是虛函數(shù)!!!因?yàn)樘摵瘮?shù)會帶來額外開銷,c++追求的是速度
5. 純虛構(gòu)析構(gòu)函數(shù)
就是純虛函數(shù)加上析構(gòu)函數(shù),一般我們把函數(shù)設(shè)置純虛函數(shù)都是不想這個類實(shí)例化,抽象出來的頂層父類,并且這個純虛函數(shù)不能實(shí)現(xiàn)。但是在純虛析構(gòu)這里不同
代碼
#include <iostream>
class TestFather{
public:virtual ~TestFather() = 0;
};
TestFather::~TestFather() {std::cout << "~TestFather()" << std::endl;
}class TestChild : public TestFather {
public:~TestChild() {std::cout << "~TestChild()" << std::endl;}
};int main() {TestFather* p = new TestChild();delete p;
}//結(jié)果和上面的相同
6. 總結(jié):
明確你的類會不會被繼承,當(dāng)作基類使用,把類的析構(gòu)函數(shù)都設(shè)置為虛函數(shù)和不設(shè)置為虛函數(shù)都是不好的
? 1.如果你的類會被繼承,當(dāng)作基類,那么一定要把基類析構(gòu)函數(shù)設(shè)置為虛函數(shù)
? 2.如果你的類不會被繼承,單純的類,那么不需要把析構(gòu)函數(shù)設(shè)置為析構(gòu)函數(shù),因?yàn)闀速M(fèi)空間,多一個虛表指針
總結(jié)
以上是生活随笔為你收集整理的【C++】浅析析构函数(基类中)为什么要写成虚基类?的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【SLAM后端】—— ceres优化相机
- 下一篇: 回不去了是什么歌啊?