[Effective C++ --007]为多态基类声明virtual析构函数
引言:
我们都知道类的一个很明显的特性是多态,比如我们声明一个水果的基类:
class Fruit {
public:
Fruit() {};
~Fruit(){};
}
那么我们根据这个Fruit基类可以派生出以下的子类:
class Apple:public Fruit{};
class Orange:public Fruit{};
那么问题来了,如果我们想经由一个基类指针去删除一个派生类Apple,且我们有以下的方法
Fruit * foo(){
Apple * p = new Apple();
return p; // 子转父,大丈夫
}
接下来似乎顺理成章,我们只需要完成以下的main函数即可了。
int main() {
A *p = foo();
delete p;
return ;
}
但是实际运行就会发现:Apple对象并未被删除!
这是为什么呢?因为foo()返回的指针指向一个Apple对象,其中的Apple的成员变量很可能未被销毁,而且Apple的析构函数也未被执行起来。于是造成了一个局部销毁的局面。
一、解决方案
其实很简单,只需要将基类中的析构函数定义为虚函数即可。
class Fruit {
public:
Fruit() {};
virtual ~Fruit(){}; ←
}
这样在删除p的时候,会先调用Apple的析构函数,然后再调用Fruit的析构函数,最后删除整个Apple对象。
二、扩展
在书中所说:
在string等STL容器使用的时候,即时class不带virtual函数,可能还是会被是否为虚函数的问题折腾。比如我们拿string来作为一个基类声明以下的class
#include <iostream>
#include<string>
using namespace std; class D : public string
{
public:
D(string i) {};
~D() {};
string i;
}; int main()
{
D* d = new D("DD");
string *p;
p = d;
delete p; // 书中描写此处会发生内存泄露,但是十分不解,上面的p =d 是子赋给父,按理是不应该出现问题的 return ;
}
调试结果在VS环境下也不会出现错误,不清楚是为什么,还有待调查。
2014.11.11 调查结果:
在上述结果中,确实不会出现问题,因为只是单纯的删除了p,但是d中间的值有没有得到删除就不能得到确定了。
这跟我们删除d的目的是相悖的。
添加以下的代码来做说明:
class D : public string
{
public:
D(string str, int i): s(str), length(i){};
~D() {
cout << "call me";
};
private:
string s;
int length;
}; int main()
{
D* d = new D("DD", );
string *p;
p = d;
delete p; // 此时释放p,并不会调用~D(),因此原本给length赋值了5并不会被清除!!! return ;
}
三、纯虚析构函数的调用顺序
在基类存在纯虚析构函数的时候,析构函数的运作方式是:派生class的析构函数先被调用,然后再调用基类的析构函数。
#include <iostream>
#include<string> using namespace std; class A {
public:
A() {};
virtual ~A() = ;
};
A::~A() {
cout << "~A" << endl;
}
class B : public A {
public:
B() {};
~B() {
cout << "~B" << endl;
}
}; int main()
{
B* b = new B();
delete b; return ;
}
运行后输出:
~B
~A
■总结:
1.带多态性质的基类应该声明一个virtual析构函数,如果class带有任何的虚函数,那么它就应该拥有一个virtual析构函数。
2.class的设计目的如果不是作为基类使用,或不是为了具备多态性,就不应该声明virtual析构函数。
[Effective C++ --007]为多态基类声明virtual析构函数的更多相关文章
- Effective C++(7) 为多态基类声明virtual析构函数 or Not
问题聚焦: 已经对一个对象执行了delete语句,还会发生内存泄漏吗? 先来看个demo: // 计时器类 class TimeKeeper { public: TimeKeeper(); ~Time ...
- 为多态基类声明virtual析构函数
一个函数的返回值为基类指针,而当指针指向一个派生类对象,接下来派生类对象被这个基类指针删除的时候,就出现了局部销毁的问题.因为C++指出,当派生类经由一个基类指针被删除,而该基类指针带着一个non-v ...
- effective c++(07)之为多态基类声明virtual析构函数
class TimeKeeper { public: TimeKeeper() ; ~TimeKepper() ; ... } ; class AtomicClock:public TimeKeepe ...
- Effective C++_笔记_条款07_为多态基类声明virtual析构函数
(整理自Effctive C++,转载请注明.整理者:华科小涛@http://www.cnblogs.com/hust-ghtao/) 这个规则只适用于polymorphic(带多态性质的)base ...
- Effective C++ -----条款07:为多态基类声明virtual析构函数
polymorphic(带多态性质的)base classes应该声明一个virtual析构函数.如果class带有任何virtual函数,它就应该拥有一个virtual析构函数. Classes的设 ...
- 【C++】为多态基类声明virtual析构函数
来自<Effective C++>条款07:为多态声明virtual析构函数 当derived class对象经由一个base class指针被删除,而该base class带着一个non ...
- 条款7:为多态基类声明virtual析构函数
C++明确指出:当派生类对象是由一个基类指针释放的,而基类中的析构函数不是虚函数,那么结果是未定义的.其实我们执行时其结果就是:只调用最上层基类的析构函数,派生类及其中间基类的析构函数得不到调用. # ...
- NO.6: 为多态基类声明virtual析构函数
注意:polymorphic base class 应该具有虚析构函数,如果class带有任何virtual函数,也应具有虚析构函数 class不具备polymorphic属性则不应该声明virtua ...
- Effective C++学习笔记 条款07:为多态基类声明virtual析构函数
一.C++明确指出:当derived class对象经由一个base class指针被删除,而该base class带着一个non-virtual析构函数,其结果未定义——实际执行时通常发生的是对象的 ...
随机推荐
- 漫谈MySql中的事务
最近一直在做订单类的项目,使用了事务.我们的数据库选用的是MySql,存储引擎选用innoDB,innoDB对事务有着良好的支持.这篇文章我们一起来扒一扒事务相关的知识. 为什么要有事务? 事务广泛的 ...
- 新功能:Azure 负载平衡器的空闲超时现可配置了
Yves Pitsch Azure 网络首席项目经理 我们很高兴地宣布,Azure负载平衡器现在可以为云服务和虚拟机提供可配置的 TCP空闲超时支持.要配置此功能,可以使用服务管理 API.Power ...
- Java [leetcode 15] 3Sum
问题描述: Given an array S of n integers, are there elements a, b, c in S such that a + b + c = 0? Find ...
- ajax取json数据——简单的
json数据:json4.json <!DOCTYPE html> <html> <head> <meta charset="utf-8" ...
- 将你的Asp.NET应用程序嵌入到SharePoint
转:http://www.cnblogs.com/Clank/archive/2007/05/21/754073.html 为什么要将Asp.net应用程序嵌入到SharePoint?这个我们不讨论! ...
- HDU 1736 美观化文字
美观化文字 Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submi ...
- 【原创】Linux下使用SecureCRT的方法:破解&编码
1.下载SecureCRT软件 ubuntu64位:http://download.csdn.net/detail/cobps/7941145 ubuntu32位:http://download.cs ...
- Flume 与Kafka区别
今天开会讨论日志处理为什么要同时使用Flume和Kafka,是否可以只用Kafka 不使用Flume?当时想到的就只用Flume的接口多,不管是输入接口(socket 和 文件)以及输出接口(Kafk ...
- ios游戏开发--cocos2d学习(3)
------------继续上一节的内容. “接收触摸事件”: CCLayer类是用来接收触摸输入的.不过你要首先启用这个功能才可以使用它. self.isTouchEnabled = YES;//此 ...
- Java 核心技术-集合-集合框架
说在前面的话: 关于Core Java 集合方面的博文网上已经写烂了,为啥我还要写呢? 答:他们写的都很好,我也学到不少东西,如果把我当做一个系统的话,学习别人.看书.读源码是输入,但是往往形不成一个 ...