[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析构函数,其结果未定义——实际执行时通常发生的是对象的 ...
随机推荐
- WCF 服务调用RFC 出现异常
我在VS2010的WCF项目用connecter 3.0 调用 RFC 运行到 IDestinationConfiguration ID = new SAPConfig(); ...
- 【转】Windows环境下Android NDK环境搭建
原文网址:http://www.metsky.com/archives/525.html 前面介绍Windows下Android 开发环境配置,主要是面向JAVA开发环境,对只做APK上层应用开发人员 ...
- window.location.search作用
window.location.search.substr(1).split("&") 这里面的相关属性和时间还有参数能具体说明一下吗?window.location wi ...
- HDU 1394-Minimum Inversion Number(BIT)
题意: 给你n个数字的序列 每次把第一个数字放到最后 得到一个新序列 一共有n个序列求这些序列中哪个序列含最小的总的逆序数 (输出最小总逆序数) 分析: 用BIT求出初始各数的逆序数,第一个数放最后它 ...
- LA3942-Remember the Word(Trie)
题意: 有s个不同的单词,给出一个长字符串把这个字符串分解成若干个单词的连接(可重复使用),有多少种分解方法 分析: dp[i]表示i开始的字符串能分解的方法数 dp[i]=sum(dp[i+len( ...
- SGU 390-Tickets(数位dp)
题意:有标号l-r的票,要给路人发,当给的票的编号的各数位的总和(可能一个人多张票)不小k时,才开始发给下一个人,求能发多少人. 分析:这个题挺难想的,参考了一下题解,dp[i][sum][left] ...
- 对单片机的modbus RTU的详细解释(转载)
Modbus 一个工业上常用的通讯协议.一种通讯约定.Modbus协议包括RTU.ASCII.TCP.其中MODBUS-RTU最常用,比较简单,在单片机上很容易实现.虽然RTU比较简单,但是看协议资料 ...
- PHP基本语法的小结
一.PHP能做什么? PHP能做什么?我觉得它很强大,只要我能想到的,它都能做,只是我技术能力还不行╮(╯﹏╰)╭.好吧,一张图,基本了解一下吧(ps:PHP的功能不局限于此( ^_^ )) 图像有点 ...
- SystemParametersInfo
Python的模块pywin32中的win32gui.SystemParametersInfo()函数 在使用win32con.SPI_SETDESKWALLPAPER设置Wallpaper时,其第二 ...
- leetcode@ [139/140] Word Break & Word Break II
https://leetcode.com/problems/word-break/ Given a string s and a dictionary of words dict, determine ...