【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++】浅析析构函数(基类中)为什么要写成虚基类?相关推荐
- php dump utfp,php pchart乱码-使用REST接口获取GeoServer中的...-结合 thinkPHP 分页写成自己分页类_169IT.COM...
本页文章导读: ▪php pchart乱码 有俩种情况:①:未将中文字符编码格式修改成utf-8 (例子如下:)mb_convert_encoding($data, "html-e ...
- 编写Java程序,使用ThreadLocal类,项目中创建账户类 Account,类中包括账户名称name、 ThreadLocal 类的引用变量amount,表示存款
查看本章节 查看作业目录 需求说明: 某用户共有两张银行卡,账户名称相同,但卡号和余额不同.模拟用户使用这两张银行卡进行消费的过程,并打印出消费明细 实现思路: 项目中创建账户类 Account,类中 ...
- java有且仅有一个main_组成java Application的若干类中,有且仅有一个主类,只有主类中含有主方法main();...
[单选题]Java 应用程序入口的 main 方法,其声明格式可以是(A) [填空题]点的水平投影与正面投影的连线( ) 于 OX 轴. [单选题]-Is there anything wrong w ...
- 声明银行账户类 java_编写Java程序,使用ThreadLocal类,项目中创建账户类 Account,类中包括账户名称name、 ThreadLocal 类的引用变量amount,表示存款...
查看本章节 查看作业目录 需求说明: 某用户共有两张银行卡,账户名称相同,但卡号和余额不同.模拟用户使用这两张银行卡进行消费的过程,并打印出消费明细 实现思路: 项目中创建账户类 Account,类中 ...
- 析构函数为什么写成虚函数?
由于类的多态性,基类指针可以指向派生类的对象.如果删除该基类的指针,就会调用该指针指向的派生类的析构函数,而派生类的析构函数又会自动调用基类的析构函数,这样整个派生类的对象被完全释放.· 如果析构函数 ...
- 【Java 虚拟机原理】Java 类中的类加载初始化细节 ( 只使用类中的常量时加载类不会执行到 ‘初始化‘ 阶段 )
文章目录 一.类加载初始化时机 二.常量加载示例 三.数组加载示例 一.类加载初始化时机 类加载时机 : Java 程序执行时 , 并不是一开始将所有的字节码文件都加载到内存中 , 而是用到时才进行加 ...
- 复制类中的属性值到另一个类的相同属性中
代码有好多高级代码,现在给大家看一个,就是复制相同属性的值到另一个类. 例如:A类中有String name,int score:B类中有String name ,int score,String s ...
- 构造函数为什么一般不定义为虚函数?而析构函数一般写成虚函数的原因 ?
1.构造函数不能声明为虚函数 1)因为创建一个对象时需要确定对象的类型,而虚函数是在运行时确定其类型的.而在构造一个对象时,由于对象还未创建成功,编译器无法知道对象的实际类型,是类本身还是类的派生类等 ...
- java类使用其他类的变量_如何将java类中的变量加载到其他类
我之前已经在类之间加载了变量,但现在无法使它工作 . 首先,我有我的代码,我尝试加载它 . 包XMLTest; public class ModifyTTXML { public static voi ...
最新文章
- C 语言编程 — size_t 的意义与作用
- 堆和栈组合:双端队列c++
- python搜题软件-智慧职教mooc的APPPython程序设计基础章节测验答案
- 学python比较好的书-学习Python编程的最好的几本书
- Python进阶11-标准库介绍02
- opencv4.4.0函数手册_Cobalt strike3.0使用手册
- oracle 匿名段,这段匿名块看着没什么问题啊
- 免费体验,阿里云智能LOGO帮你解决设计难题
- python中的字典和类的区别_Python:我应该使用类还是字典?
- 流畅的python 数据模型
- Docker的主要作用
- linux随手笔记(Centos为主)
- JS高级程序设计精简版(第十章:函数)附思维导图
- VIPKID前端面试题
- 惊喜盲盒中奖iPhone 13已收到货
- PHP中级工程师面试题
- opencv 视频处理(python)
- 大批,程序员被劝退!
- TCP报文格式及三次握手详解
- Manifest merger failed with multiple errors, see logs问题处理
热门文章
- c语言求跳水运动员成绩,跳水排名_C语言编程实例_C语言_最全面的网站教程
- 量子计算机真随机数,量子真随机数发生器研究取得进展
- linux 多目录makefile,royalchen
- android百度api配置,Android Studio 配置使用百度api (附带简单样例)(示例代码)
- C/C++数组初始化的一些误区
- 前端如何查看音频的长度_重学前端基础:如何查看文档对象的所有属性?如何文档查找节点?...
- Debevec方法计算相机响应函数CRF
- 剑指offer:面试题24. 反转链表
- C++中结构体与类的区别(struct与class的区别)
- 机器学习与高维信息检索 - Note 7 - 核主成分分析(Kernel Principal Component Analysis,K-PCA)