HM140 虚析构释放子对象
HM140 虚析构释放子对象
来源: 第 140 集 类和对象-多态-虚析构和纯虚析构
难度: 入门
时间限制: 1s
空间限制: 64MB
题目描述
多态里常用父类指针指向堆上的子类对象,最后 delete 父类指针。若父类析构不是虚函数,这次 delete 不会走进子类析构。子类若把姓名 new 到堆上,这块内存就会泄露。
虚析构和**纯虚析构**都能解决「父类指针释放子对象不干净」:delete 时先走子类析构,再走父类析构(与构造相反:先有父再有子,离开时先走子再走父)。二者都**必须有函数体**。纯虚析构在类内写成 virtual ~Animal() = 0; 只是声明,还要在类外写出 Animal::~Animal() { ... };只声明不实现会在链接期报「无法解析的外部符号」。普通纯虚函数可以只有 = 0,纯虚析构不行。
区别:一旦有纯虚析构,这个类就是抽象类,栈上、堆上都不能实例化。只有虚析构、又没有其它纯虚函数时,基类仍可实例化。并不是每段代码都要写虚析构:子类没有堆区数据时可以不写。
请按下面场景实现,并用父类指针 new 出猫、调用 speak、再 delete:
- 基类构造输出
Animal的构造函数调用 - 猫的构造把姓名放到堆上的
string*,并输出Cat的构造函数调用 speak输出「姓名 +小猫在说话」,例如汤姆小猫在说话- 猫的析构释放姓名并输出
Cat的析构函数调用 - 普通/虚析构的基类析构输出
Animal的析构函数调用 - 纯虚析构的实现输出
Animal的纯虚析构函数调用
读入若干操作,比较「无虚析构 / 虚析构 / 纯虚析构」。
输入格式
第一行一个整数 \(q\)(\(1 \le q \le 100\))。
接下来 \(q\) 行,每行一种操作:
NV s:基类析构**不是**虚函数,猫名为不含空白的 \(s\)(\(1 \le |s| \le 20\))V s:基类使用虚析构,猫名为 \(s\)PV s:基类使用纯虚析构(类外给出实现),猫名为 \(s\)MAKE_PURE:询问此时基类能不能实例化NEED_IMPL:询问纯虚析构要不要类外实现NO_HEAP:询问子类没有堆区数据时,虚析构是否可以不写
输出格式
NV:三行,依次为基类构造、猫构造、说话;然后只有基类析构一行(猫的析构被跳过)V:五行,构造两行、说话一行、先猫析构再基类析构PV:五行,与V相同,但最后一行是Animal的纯虚析构函数调用MAKE_PURE:CANNOTNEED_IMPL:YESNO_HEAP:YES
每行行末换行。构造、说话、析构必须由对应函数打印。
样例
输入 #1
6
NV 汤姆
V 汤姆
PV 汤姆
MAKE_PURE
NEED_IMPL
NO_HEAP
输出 #1
Animal的构造函数调用
Cat的构造函数调用
汤姆小猫在说话
Animal的析构函数调用
Animal的构造函数调用
Cat的构造函数调用
汤姆小猫在说话
Cat的析构函数调用
Animal的析构函数调用
Animal的构造函数调用
Cat的构造函数调用
汤姆小猫在说话
Cat的析构函数调用
Animal的纯虚析构函数调用
CANNOT
YES
YES
输入 #2
1
V 加菲
输出 #2
Animal的构造函数调用
Cat的构造函数调用
加菲小猫在说话
Cat的析构函数调用
Animal的析构函数调用
说明
NV少了猫的析构,堆上姓名没有释放,这就是要学虚析构的原因。- 虚析构与纯虚析构都能让
delete父指针时先析构子类。 - 有纯虚析构的类即使没有其它纯虚函数,也是抽象类。
信息
- ID
- 1139
- 难度
- (无)
- 分类
- (无)
- 标签
- (无)
- 递交数
- 0
- 已通过
- 0
- 通过率
- ?
- 上传者