注:本文内容来源于zhice163博文,感谢作者的整理。

1.为什么基类的析构函数是虚函数?

  在实现多态时,当用基类操作派生类,在析构时防止只析构基类而不析构派生类的状况发生。

  下面转自网络:源地址 http://blog.sina.com.cn/s/blog_7c773cc50100y9hz.html

  a.第一段代码

  

#include<iostream>
using namespace std;
class ClxBase{
public:
ClxBase() {};
~ClxBase() {cout << "Output from the destructor of class ClxBase!" << endl;}; void DoSomething() { cout << "Do something in class ClxBase!" << endl; };
}; class ClxDerived : public ClxBase{
public:
ClxDerived() {};
~ClxDerived() { cout << "Output from the destructor of class ClxDerived!" << endl; }; void DoSomething() { cout << "Do something in class ClxDerived!" << endl; };
};
int main(){
ClxDerived *p = new ClxDerived;
p->DoSomething();
delete p;
return 0;
}

  运行结果:

  Do something in class ClxDerived!

  Output from the destructor of class ClxDerived!

  Output from the destructor of class ClxBase!

  这段代码中基类的析构函数不是虚函数,在main函数中用继承类的指针去操作继承类的成员,释放指针P的过程是:先释放继承类的资源,再释放基类资源.

  b.第二段代码

  

#include<iostream>
using namespace std;
class ClxBase{
public:
ClxBase() {};
~ClxBase() {cout << "Output from the destructor of class ClxBase!" << endl;}; void DoSomething() { cout << "Do something in class ClxBase!" << endl; };
}; class ClxDerived : public ClxBase{
public:
ClxDerived() {};
~ClxDerived() { cout << "Output from the destructor of class ClxDerived!" << endl; }; void DoSomething() { cout << "Do something in class ClxDerived!" << endl; }
};
int main(){
ClxBase *p = new ClxDerived;
p->DoSomething();
delete p;
return 0;
}

  输出结果:

  Do something in class ClxBase!
  Output from the destructor of class ClxBase!

这段代码中基类的析构函数同样不是虚函数,不同的是在main函数中用基类的指针去操作继承类的成员,释放指针P的过程是:只是释放了基类的资源,而没有调用继承类的析构函数.调用  dosomething()函数执行的也是基类定义的函数.

一般情况下,这样的删除只能够删除基类对象,而不能删除子类对象,形成了删除一半形象,造成内存泄漏.

在公有继承中,基类对派生类及其对象的操作,只能影响到那些从基类继承下来的成员.如果想要用基类对非继承成员进行操作,则要把基类的这个函数定义为虚函数.

析构函数自然也应该如此:如果它想析构子类中的重新定义或新的成员及对象,当然也应该声明为虚的.

  c.第三段代码:

  

#include<iostream>
using namespace std;
class ClxBase{
public:
ClxBase() {};
virtual ~ClxBase() {cout << "Output from the destructor of class ClxBase!" << endl;};
virtual void DoSomething() { cout << "Do something in class ClxBase!" << endl; };
}; class ClxDerived : public ClxBase{
public:
ClxDerived() {};
~ClxDerived() { cout << "Output from the destructor of class ClxDerived!" << endl; };
void DoSomething() { cout << "Do something in class ClxDerived!" << endl; };
}; int main(){
ClxBase *p = new ClxDerived;
p->DoSomething();
delete p;
return 0;
}

  运行结果:

  Do something in class ClxDerived!
  Output from the destructor of class ClxDerived!
  Output from the destructor of class ClxBase!

这段代码中基类的析构函数被定义为虚函数,在main函数中用基类的指针去操作继承类的成员,释放指针P的过程是:只是释放了继承类的资源,再调用基类的析构函数.调用dosomething()函数执行的也是继承类定义的函数.

如果不需要基类对派生类及对象进行操作,则不能定义虚函数,因为这样会增加内存开销.当类里面有定义虚函数的时候,编译器会给类添加一个虚函数表,里面来存放虚函数指针,这样就会增加类的存储空间.所以,只有当一个类被用来作为基类的时候,才把析构函数写成虚函数.

【转】C++析构函数为什么要为虚函数的更多相关文章

  1. C++析构函数为什么要为虚函数

    注:本文内容来源于zhice163博文,感谢作者的整理. .为什么基类的析构函数是虚函数? 在实现多态时,当用基类操作派生类,在析构时防止只析构基类而不析构派生类的状况发生. 下面转自网络:源地址 h ...

  2. 构造函数为什么不能为虚函数 &amp; 基类的析构函数为什么要为虚函数

    一.构造函数为什么不能为虚函数 1. 从存储空间角度,虚函数相应一个指向vtable虚函数表的指针,这大家都知道,但是这个指向vtable的指针事实上是存储在对象的内存空间的.问题出来了,假设构造函数 ...

  3. 不要在基类析构函数中调用纯虚函数,否则运行时会报错“pure virtual method called”

    如上. 这是因为:delete派生类对象时,先调用派生类的析构函数,然后再调用基类的析构函数:此时如果调用纯虚函数的话,派生类的对象已经被破坏了,所以会报错. http://www.cnblogs.c ...

  4. C++中为什么要将析构函数定义成虚函数

    构造函数不可以是虚函数的,这个很显然,毕竟虚函数都对应一个虚函数表,虚函数表是存在对象内存空间的,如果构造函数是虚的,就需要一个虚函数表来调用,但是类还没实例化没有内存空间就没有虚函数表,这根本就是个 ...

  5. C++析构函数定义为虚函数(转载)

    转载:http://blog.csdn.net/alane1986/article/details/6902233 析构函数执行时先调用派生类的析构函数,其次才调用基类的析构函数.如果析构函数不是虚函 ...

  6. C++中为什么构造函数不能是虚函数,析构函数是虚函数

    一, 什么是虚函数? 简单地说,那些被virtual关键字修饰的成员函数,就是虚函数.虚函数的作用,用专业术语来解释就是实现多态性(Polymorphism),多态性是将接口与实现进行分离:用形象的语 ...

  7. 从零开始学C++之虚函数与多态(二):纯虚函数、抽象类、虚析构函数

    一.纯虚函数 虚函数是实现多态性的前提 需要在基类中定义共同的接口 接口要定义为虚函数 如果基类的接口没办法实现怎么办? 如形状类Shape 解决方法 将这些接口定义为纯虚函数 在基类中不能给出有意义 ...

  8. C++ 析构函数为虚函数

    1.原因: 在实现多态时, 当用基类指针操作派生类, 在析构时候防止只析构基类而不析构派生类. 2.例子: (1). #include<iostream> using namespace ...

  9. 深入学习c++(虚函数遇到析构函数就退化了)

    1. 在构造函数和析构函数中调用的虚函数并不具备虚函数的特性 因为基类的构造函数先构造, 析构函数后析构

随机推荐

  1. C#读取Xml【转】

      XML文件是一种常用的文件格式,例如WinForm里面的app.config以及Web程序中的web.config文件,还有许多重要的场所都有它的身影.Xml是Internet环境中跨平台的,依赖 ...

  2. 在vim中执行外部命令

    11.7.5  在Vim编辑器中执行Shell命令 有时需要在Vim编辑器中执行Shell命令,例如需要验证一个Shell命令是否正确,以便写入脚本中:需要在文件中引用某个Shell命令的输入等.本小 ...

  3. ANGULAR 开发用户选择器指令

    在开发表单时,我们需要使用经常需要使用到用户选择器,用户的数据一般使用如下方式存储: 用户1,用户2,用户3   我们可以使用angular指令实现选择器. <!DOCTYPE html> ...

  4. 测试JdbcTemplate执行SQL语句和存储过程

    我在项目中需要使用到oracle的语句片段和存储过程.下面就是我的测试案例: public class DbTest extends BaseTestCase { @Resource JdbcUtil ...

  5. js控制html文字提示语的出现和隐藏

    有时我们需要在点击html输入框的时候,旁边会出现提示语.在输入字符的时候,输入框下边会出现输入了多少字符的提示. 请看下面实例. <!DOCTYPE html> <html> ...

  6. 谷歌官方SwipeRefreshLayout下拉刷新的用法。

    <Android SwipeRefreshLayout:谷歌官方SDK包中的下拉刷新> 下拉刷新在如今移动开发中应用如此广泛和普遍,以至于谷歌干脆在SDK中给予支持.在android-su ...

  7. 上传项目的更改 info.plist文件

    info.plistOpen AsSource As 添加<key>NSAppTransportSecurity</key>    <dict>        &l ...

  8. wdcp升级php版本到5.3,5.5

    官网省级方法 wget http://down.wdlinux.cn/in/php_up53.shsh php_up53.sh 看到"php update is OK"提示表示,顺 ...

  9. 远程连接Windows2008R2时服务器报Terminal Services错误的解决办法

    症状: 使用终端服务客户端连接到Windows Server2008 R2的机器时,如果客户端选项中选择了打印机(注1)时,它可能会在在系统事件日志中记录一个TerminalServices打印机错误 ...

  10. 从协议VersionedProtocol开始4——AdminOperationsProtocol、InterTrackerProtocol、JobSubmissionProtocol、TaskUmbilicalProtocol

    1.package org.apache.hadoop.mapred这四个协议都在这个包下. 2.从最简单的AdminOperationsProtocol看, void refreshQueues() ...