c++学习笔记------继承与多态5
C++继承与多态(5)
虚析构函数
一. 两个问题:
-
问题一: 哪些函数不能实现成虚函数?
首先要认识虚函数的依赖:
1.虚函数能产生地址,存储在vftable当中
2.对象必须存在(vfptr->vftable->虚函数地址,而vfptr存储在对象的内存空间中)根据虚函数的依赖条件可以分析得出:
1.构造函数
(1) virtual+构造函数(不可以)
(2) 构造函数中(调用的任何函数,都是静态绑定的)调用虚函数,也不会发生静态绑定 (3) 派生类对象的构造过程,先调用的是基类的构造函数,然后才调用派生类的构造函数
2.static静态成员方法
静态成员方法不依赖对象 -
问题二: 关于虚析构函数, 什么时候基类的析构函数必须实现成虚函数?
解答:基类的指针(引用)指向堆上new出来的派生类对象的时候, delete pb(基类的指针),
它调用析构函数的时候,必须发生动态绑定,否则会导致派生类的析构函数无法调用举个例子分析一下问题二
简单定义基类Base和其派生类Derive
class Base { public: Base(int data = 10) :ma(data) { cout << "Base(int data = 10)" << endl; } void show() { cout << "Base::show()" << endl; } ~Base() { cout << "~Base()" << endl; } protected: int ma; }; class Derive : public Base { public: Derive(int data = 20) :Base(data), mb(data) { cout << "Derive(int data = 20)" << endl; } virtual void show() { cout << "Derive::show()" << endl; } // 基类的析构函数是虚函数,那么派生类的析构函数自动成为虚函数 ~Derive() { cout << "~Derive()" << endl; } private: int mb; };
主函数部分
int main() { Base* pb = new Derive(10); pb->show(); delete pb; // 派生类的析构函数没有调用 }
-
case1: 基类Base的析构函数不是虚函数时
由以上结果可知,派生类的析构函数没有调用, 这是因为delete需要先调用析构函数(释放外部占用的内存资源(如果需要的话)),然后才会释放内存(free), 而调用析构函数pb->~Base() , 找到的是基类的析构函数,发生的是静态绑定。
-
case2: 基类Base的析构函数是虚函数时
由以上结果可知,delete调用pb->~Base()时发生了动态绑定,pb获得了派生类对象空间前四个字节的值(即vfptr,指向派生类的虚函数表),利用vfptr访问派生类的虚函数表,所以调用的也是派生类的析构函数
以上例子很好说明当基类的指针pb指向一个new出来的派生类的对象时,基类的析构函数必须写成虚函数确保delete pb, 在调用析构函数时发生动态绑定,能够调用派生类的析构函数,避免派生类对象无法析构,造成内存泄漏。
-
原文地址:https://www.cnblogs.com/ChenFei-Blogs/p/15241403.html
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- IPC—进程间通信的基础概念
- Python Django开发 经验技巧总结(一)
- Python SQLite 基本操作和经验技巧(二)
- AkShare-股票数据-主要股东
- 进程间通信的方式(1)
- Python Django开发 经验技巧总结(二)
- 进程间通信的方式(2)
- AkShare-股票数据-机构持股
- View的滑动方式 详细介绍
- AkShare-期货数据-分时数据
- Python 爬取留言板留言(三):多进程版+selenium模拟
- View事件分发、滑动冲突 详解
- Python Django开发 异常及其解决办法(一)
- 带你彻底搞懂-View的工作原理!
- Python 批量下载BiliBili视频 打包成软件