引言:

我们都知道类的一个很明显的特性是多态,比如我们声明一个水果的基类:

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析构函数的更多相关文章

  1. Effective C++(7) 为多态基类声明virtual析构函数 or Not

    问题聚焦: 已经对一个对象执行了delete语句,还会发生内存泄漏吗? 先来看个demo: // 计时器类 class TimeKeeper { public: TimeKeeper(); ~Time ...

  2. 为多态基类声明virtual析构函数

    一个函数的返回值为基类指针,而当指针指向一个派生类对象,接下来派生类对象被这个基类指针删除的时候,就出现了局部销毁的问题.因为C++指出,当派生类经由一个基类指针被删除,而该基类指针带着一个non-v ...

  3. effective c++(07)之为多态基类声明virtual析构函数

    class TimeKeeper { public: TimeKeeper() ; ~TimeKepper() ; ... } ; class AtomicClock:public TimeKeepe ...

  4. Effective C++_笔记_条款07_为多态基类声明virtual析构函数

    (整理自Effctive C++,转载请注明.整理者:华科小涛@http://www.cnblogs.com/hust-ghtao/) 这个规则只适用于polymorphic(带多态性质的)base ...

  5. Effective C++ -----条款07:为多态基类声明virtual析构函数

    polymorphic(带多态性质的)base classes应该声明一个virtual析构函数.如果class带有任何virtual函数,它就应该拥有一个virtual析构函数. Classes的设 ...

  6. 【C++】为多态基类声明virtual析构函数

    来自<Effective C++>条款07:为多态声明virtual析构函数 当derived class对象经由一个base class指针被删除,而该base class带着一个non ...

  7. 条款7:为多态基类声明virtual析构函数

    C++明确指出:当派生类对象是由一个基类指针释放的,而基类中的析构函数不是虚函数,那么结果是未定义的.其实我们执行时其结果就是:只调用最上层基类的析构函数,派生类及其中间基类的析构函数得不到调用. # ...

  8. NO.6: 为多态基类声明virtual析构函数

    注意:polymorphic base class 应该具有虚析构函数,如果class带有任何virtual函数,也应具有虚析构函数 class不具备polymorphic属性则不应该声明virtua ...

  9. Effective C++学习笔记 条款07:为多态基类声明virtual析构函数

    一.C++明确指出:当derived class对象经由一个base class指针被删除,而该base class带着一个non-virtual析构函数,其结果未定义——实际执行时通常发生的是对象的 ...

随机推荐

  1. c语言typedef关键字的理解

    1.typedef的定义 很多人认为typedef 是定义新的数据类型,这可能与这个关键字有关.本来嘛,type 是数据类型的意思:def(ine)是定义的意思,合起来就是定义数据类型啦. 不过很遗憾 ...

  2. (二)学习C#之内存管理

    一.当你运行你的程序通常都会访问哪些内存空间呢? 电脑自言自语道,“这个人要声明一个整数”或“这个人个方法”或“这个人要创建一个对象” 1.这些信息究竟是存在内存里的什么地方呢? 2.或者说用于描述这 ...

  3. iOS--跳转到APPstore评分

    本代码适用于iOS7之后的版本: NSString *str = [NSString stringWithFormat:@"itms-apps://itunes.apple.com/app/ ...

  4. Win32汇编环境配置

    放假了,发现自己知识面窄,趁有时间就打算折腾下Win32汇编.其实在学校也上过汇编课,是基于dos的.那时老师不务正业,老跟我们讲政治经济文化,唯独不怎么讲课;再加上自己的问题,导致了dos汇编学得好 ...

  5. 积和式Permanent在Mathematica中的运算

    Permanent[m_List] := With[{v = Array[x, Length[m]]}, Coefficient[Times @@ (m.v), Times @@ v]] 参考资料:  ...

  6. Android onTouchEvent事件中onTouch方法返回值介绍

    1.若return false说明没有成功执行onTouch事件,在执行完onTouch里面的代码之后,onTouch事件并没有结束.因此某些组件如Gallery会自动执行它所在view里onTouc ...

  7. AsyncEnumerableExtensions.cs z

    public static class Extensions { public static async Task ForEachAsync<T, U>(this IEnumerable& ...

  8. svn版本控制-windows篇

    一.准备工作 1.获取 Subversion 服务器程序(服务端) 到官方网站(http://subversion.tigris.org/)下载最新的服务器安装程序.目前最新的是1.5版本,具体下载地 ...

  9. 转载:MATLAB画图常用调整代码

    %单y轴 plot(t*1e+,abs(iGG)/max(abs(iGG)),); axis([-,,,]) xlabel('时间/ns'); ylabel('幅度/a.u.'); ,'FontNam ...

  10. 【恒天云】OpenStack和CloudStack对比研究报告

    摘自恒天云:http://www.hengtianyun.com/download-show-id-8.html 1. 概述 常见的IaaS开源平台有OpenStack.CloudStack.Euca ...