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