C++基础之虚析构函数原理
结论
虚函数表指针 + 虚函数表 共同实现
演示
VS2017(32位)
基类有析虚构函数
一段代码演示
#include <iostream>
#include <memory>
class shape
{
public:
virtual ~shape()
{
std::cout << "~shape\n\n";
}
};
class circle : public shape
{
public:
~circle()
{
std::cout << "~circle\n\n";
}
};
int main(int argc, char *argv[], char *env[])
{
std::unique_ptr<shape> pshape(new(std::nothrow) circle);
return 0;
}
circle 继承 基类shape, main函数中用一个派生类的对象赋值给基类的指针 。
内存模型
circle的内存模型如下:
1>class circle size(4):
1> +---
1> 0 | +--- (base class shape)
1> 0 | | {vfptr}
1> | +---
1> +---
1>
1>circle::$vftable@:
1> | &circle_meta
1> | 0
1> 0 | &circle::{dtor}
基类的析构函数是虚函数,故排在最前面的是虚函数表指针,接着是基类成员,然后是派生类成员。
注意:虚函数表中,存放了 派生类的的析构函数的地址(&circle::{dtor})。
分析
当发生析构时,派生类首先调用派生类的析构函数,再调用基类的析构函数。
pshape指向的派生类的对象,正因为存在虚函数表指针,析构时,根据虚函数表指针指向虚函数表中的析构函数(&circle::{dtor}),这样,就能精准定位派生类的析构函数。
基类无析构函数的情况
既然基类没有虚析构函数,尽管基类存在虚函数,发生析构时,派生类的虚函数表中没有存放析派生类的析构函数的地址,所以不能精准定位派生类的析构函数的地址,派生类的释放可能存在内存隐患。
一段代码
相对上面的代码,基类的析构函数去掉,额外增加一个虚函数。
#include <iostream>
class shape
{
public:
~shape()
{
std::cout << "~shape\n\n";
}
virtual void run(){}
};
class circle : public shape
{
public:
~circle()
{
std::cout << "~circle\n\n";
}
};
int main(int argc, char *argv[], char *env[])
{
std::unique_ptr<shape> pshape(new(std::nothrow) circle);
return 0;
}
内存模型
1>class circle size(4):
1> +---
1> 0 | +--- (base class shape)
1> 0 | | {vfptr}
1> | +---
1> +---
1>
1>circle::$vftable@:
1> | &circle_meta
1> | 0
1> 0 | &shape::run
C++基础之虚析构函数原理的更多相关文章
- C++中基类虚析构函数的作用及其原理分析
虚析构函数的理论前提是 执行完子类的析构函数,那么父类的虚构函数必然会被执行. 那么当用delete释放一个父类指针所实例化的子类对象时,如果没有定义虚析构函数,那么将只会调用父类的析构函数,而不会调 ...
- 虚析构函数? vptr? 指针偏移?多态数组? delete 基类指针 内存泄漏?崩溃?
五条基本规则: 1.如果基类已经插入了vptr, 则派生类将继承和重用该vptr.vptr(一般在对象内存模型的顶部)必须随着对象类型的变化而不断地改变它的指向,以保证其值和当前对象的实际类型是一致的 ...
- C/C++中的虚析构函数和私有析构函数的使用
代码: #include <iostream> using namespace std; class A{ public: A(){ cout<<"construct ...
- C++中基类的析构函数为什么要用virtual虚析构函数
知识背景 要弄明白这个问题,首先要了解下C++中的动态绑定. 关于动态绑定的讲解,请参阅: C++中的动态类型与动态绑定.虚函数.多态实现 正题 直接的讲,C++中基类采用virtual虚析构函数是 ...
- 基类的析构函数写成virtual虚析构函数
虚函数作用:动态绑定,实现多态效果. 场景问题: 派生类中有资源需要回收,而在编程中采用多态,由基类的指针指向派生类,则在释放的时候,如果基类的析构函数不是virtual,则派生类的析构函数得不到释放 ...
- C++虚函数原理
类中的成员函数分为静态成员函数和非静态成员函数,而非静态成员函数又分为普通函数和虚函数. Q: 为什么使用虚函数 A: 使用虚函数,我们可以获得良好的可扩展性.在一个设计比较好的面向对象程序中,大多数 ...
- C++虚函数表与虚析构函数
1.静态联编和动态联编联编:将源代码中的函数调用解释为要执行函数代码. 静态联编:编译时能确定唯一函数.在C中,每个函数名都能确定唯一的函数代码.在C++中,因为有函数重载,编译器须根据函数名,参数才 ...
- 【C++】C++中基类的析构函数为什么要用virtual虚析构函数?
正面回答: 当基类的析构函数不是虚函数,并且基类指针指向一个派生类对象,然后通过基类指针来删除这个派生类对象时,如果基类的析构函数不是虚析构函数,那么派生类的析构函数就不会被调用,从而产生内存泄漏 # ...
- C++(四十一) — 多态、虚函数、虚析构函数、纯虚函数
1.多态 面向对象程序设计中,多态性表现为: (1)重载多态:函数重载.运算符重载: (2)运行多态:通过基类的指针(或引用)调用不同派生类的同名函数,表现出不同的行为: (3)模板多态:参数多态, ...
随机推荐
- Python中关于join函数的陷阱?
目录 说明 数据说明 正确示例 错误示例 解决办法 说明 最近在用Python的join函数连接多个列表时,出现了如下两个错误,即合并类型不一致.折腾了很久才找到原因,真是基础不牢,地动山摇. Typ ...
- FASTA/Q序列处理神器---seqkit
该软件对于处理FASTA/Q十分方便,省去自己编写脚本 安装 1 conda install seqkit 使用 序列操作(seq) 1 ## 取方向序列 2 seqkit seq test.fa - ...
- C++类虚函数内存分布(这个 你必须懂)
转自:http://www.cnblogs.com/jerry19880126/p/3616999.html C++类内存分布 书上类继承相关章节到这里就结束了,这里不妨说下C++内存分布结构,我们来 ...
- 利用charles映射解决夜神模拟器安装xposed-v89-sdk25-x86.zip
最近在玩xposed框架,前前后后搞了两天,浪费一个周末,总算把踩过的坑都踩了一遍.. 比如大家肯定遇到的的一个问题:夜神模拟器打开xposed安装器之后,为什么下载不了xposed-v89-sdk2 ...
- STM32 CAN用队列缓冲接收的例子
[1]CAN接收用队列缓冲的例子: 发单帧没有问题,多帧或者连续发两帧就有问题.
- 【STM32】晶振,主时钟,外设频率介绍
首先,我用的是STM32F407,下方所有图片都是出自这芯片的文档,如果型号和我不同,需要找到对应的芯片说明文档,也许会有出入 先看一张时钟图 这里会着重说明高速的部分,低速(不管内部还是外部)只给R ...
- gitlab之实战部署
#:准备Java环境,安装jdk root@ubuntu:~# cd /usr/local/src/ root@ubuntu:/usr/local/src# ls jdk-8u191-linux-x6 ...
- oracle 以SYSDBA远程连接数据库
在服务器用sysdba登陆 grant sysdba to system 然后在远程就可以sysdba登陆数据库了
- springboot整合jetty
1.jetty介绍 通常我们进行Java Web项目开发,必须要选择一种服务器来部署并运行Java应用程序,Tomcat和Jetty作为目前全球范围内最著名的两款开源servlet容器,该怎么选呢. ...
- ssm+mysql+jsp打造在线考试系统WeKnow-学生端
一.登陆模块 前台提交账号和密码传到后台处理控制层 1.1 首先是控制器 @RequestMapping(value="/studentLogin", method=Request ...