博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
条款07:为多态基类声明虚析构函数
阅读量:6429 次
发布时间:2019-06-23

本文共 1542 字,大约阅读时间需要 5 分钟。

看下面一个类:

class TimeKeeper{

public :

     TimeKeeper();

     ~TimeKeeper();

     ....

};

class AtomicClock : public TimeKeeper{...};

class WaterClock : public TimeKeeper{...};

class WristClock : public TimeKeeper{...};

         当我们使用时,我们可以采用一个工厂方法,用基类的指针指向派生类的对象:

         TimeKeeper * getTimeKeeper();

        

TimeKeeper * ptk = getTimeKeeper(); //用基类的指针指向派生类的对象

                   ....

delete ptk;

 

(注,在以后,我会说明这种依赖用户来delete的方法不是一个好方法。但是现在不是我们所要讨论的问题。我们要讨论的问题是:。。。。)

我们要讨论的是,当我们把ptk进行析构时,会发生什么事情?

 

由于ptk是一个基类的指针,当进行析构时,会调用基类的析构函数,也就是说会把ptk所指对象的基类部分进行,但是ptk实际指向了一个派生类的对象,对于派生类的数据怎么办呢?此时会产生不明确行为,这是造成内存泄露的一个绝佳方式。

 

如果我们把基类的析构函数做成虚函数,则这个问题就可以解决了:

         class TimeKeeper{

public :

     TimeKeeper();

     virtual ~TimeKeeper();

     ....

};

class AtomicClock : public TimeKeeper{...};

class WaterClock : public TimeKeeper{...};

class WristClock : public TimeKeeper{...};

        

         由于基类的析构函数是一个虚函数,则每一个派生类中的析构函数都是虚函数。当我们再次使用一个基类指针指向派生类的时候,如下:

TimeKeeper * ptk = getTimeKeeper();

....

delete ptk;

再次进行析构时,由于析构函数是一个虚函数,所以在析构时,会在运行期来决定调用哪个类的析构函数,此时,经判断是派生类的析构函数,所以会调用派生类的析构函数,此时,可以把ptk所指向的对象全部析构。

 

结论:任何class只要带有virtual函数都几乎确定应该也有一个virtual析构函数。

 

       如果一个class不含virtual函数,通常表示它并不意图被用做一个base class,即使被当作基类,也不希望用基类的指针来指向一个派生类的对象。当class不企图被当作base class,令其析构函数为virtual,往往不是一个好主意。如下类:

class Point{

public :

     Point(int xCoord, int yCoord) : x(xCoord),y(yCoord){}

     ~Point();

private:

     int x, y;

}

这样一个类的对象,会占用64个字节的内存,如果其析构函数是一个虚函数,则此类的对象,将会是96字节,这样,浪费了50%的空间。

所以许多人的心得是:只有当class内含至少一个virtual函数,才为它声明一个virtual析构函数。

 

         请记住:

  • Polymorphic base class 应该声明一个virtual析构函数。如果class带有任何virtual函数,它就应该拥有一个virtual析构函数。
  • Class的设计目的如果不是作为base class 使用,或不是为了具备多态性,就不应该声明virtual析构函数。s

转载地址:http://phnga.baihongyu.com/

你可能感兴趣的文章
深入浅出换肤相关技术以及如何实现
查看>>
Redis 基础、高级特性与性能调优
查看>>
React native 第三方组件 React native swiper
查看>>
接口幂等设计
查看>>
编程入门指南
查看>>
移动端的自适应方案—REM
查看>>
你真的懂volatile吗
查看>>
Android 编译时注解-提升
查看>>
说说 Spring AOP 中 @Aspect 的高级用法
查看>>
Workbox CLI中文版
查看>>
贝聊亿级数据库分库分表实践
查看>>
同时连接gitlab和github
查看>>
vuex源码分析
查看>>
tornado+datatables分页
查看>>
集成 Kubernetes 与 Cloud Foundry,IBM自有一套
查看>>
php 中英文字符分割
查看>>
No module named yum
查看>>
Shell处理用户输入参数----getopts
查看>>
【函数】06、装饰器的应用
查看>>
v$sysstat
查看>>