构造函数和析构函数的调用顺序

构造函数的调用顺序:

当建立一个对象时,首先调用基类的构造函数,然后调用下一个派生类的构造函数,依次类推,直至到达最底层的目标派生类的构造函数为止。

析构函数的调用书序:

当删除一个对象时,首先调用该派生类的析构函数,然后调用上一层基类的析构函数,依次类推,直到到达最顶层的基类的析构函数为止。

简单的说,构造函数是“自上向下”调用,析构函数是“自下而上”调用。

演示代码如下:

#include<iostream>
using namespace std; class Base{
public:
Base(){cout<<"创建Base基类。"<<endl;}
~Base() {cout<<"删除Base基类。"<<endl;}
};
class Child : public Base{
public:
Child() {cout<<"创建Child派生类。"<<endl;}
~Child() {cout<<"删除Child派生类。"<<endl;}
}; int main()
{
cout<<"*********构造函数调用顺序示例***********"<<endl;
Child *C1 = new Child;
cout<<"*********析构函数调用顺序示例***********"<<endl;
delete C1;
}

运行结果如下图:

虚析构函数的作用

通过基类的指针来删除派生类的对象时,基类的析构函数应该是虚的。

原因:在公有继承中,基类对派生类及其对象的操作,只能影响到那些从基类继承下来的成员。如果想要用基类对非继承成员进行操作,则要把基类的这个操作(函数)定义为虚函数。析构函数同样需要如此。

如果用基类的指针来删除派生类的对象,而这个基类有一个非虚的析构函数,则结果是未定义的。后果是对象的派生部分不会被销毁,然而,基类部分很可能已被销毁,这就导致产生了“部分析构”的情况,这是一个内存泄露。

可以通过如下代码来说明:

#include<iostream>
using namespace std; class Base{
public:
Base(){cout<<"创建Base基类。"<<endl;}
~Base() {cout<<"删除Base基类。"<<endl;} /*非虚析构函数*/
};
class Child : public Base{
public:
Child() {cout<<"创建Child派生类。"<<endl;}
~Child() {cout<<"删除Child派生类。"<<endl;}
}; int main()
{
cout<<"*********非虚析构函数调用示例***********"<<endl;
Base *C1 = new Child;
delete C1;
}

运行结果如下,此时删除C1指针时,只调用了Base类的析构函数,没有调用Child类的析构函数。

当更改Base基类的析构函数为虚函数时,代码如下:

#include<iostream>
using namespace std; class Base{
public:
Base(){cout<<"创建Base基类。"<<endl;}
virtual ~Base() {cout<<"删除Base基类。"<<endl;} /*虚析构函数*/
};
class Child : public Base{
public:
Child() {cout<<"创建Child派生类。"<<endl;}
~Child() {cout<<"删除Child派生类。"<<endl;}
}; int main()
{
cout<<"*********虚析构函数调用示例***********"<<endl;
Base *C1 = new Child;
delete C1;
}

此时运行结果如下,先调用了Child派生类的析构函数,再调用了Base基类的析构函数。

但是,一般如果不做基类的类的析构函数一般不声明为虚函数,因为虚函数的实现要求对象携带额外的信息,这些信息用于在运行时确定该对象应该调用哪一个虚函数。典型情况下,这一信息具有一种被称为 vptr(virtual table pointer,虚函数表指针)的指针的形式。vptr 指向一个被称为 vtbl(virtual table,虚函数表)的函数指针数组,每一个包含虚函数的类都关联到 vtbl。当一个对象调用了虚函数,实际的被调用函数通过下面的步骤确定:找到对象的
vptr 指向的 vtbl,然后在 vtbl 中寻找合适的函数指针。这样子会使类所占用的内存增加。

C++ 构造函数和析构函数的调用顺序、虚析构函数的作用的更多相关文章

  1. C++继承,多重继承,虚继承的构造函数以及析构函数的调用顺序问题

    #include <iostream> using namespace std; class A{ int data_a; public: A(){ data_a = ; cout < ...

  2. C++C++中构造函数与析构函数的调用顺序

    http://blog.csdn.net/xw13106209/article/details/6899370 1.参考文献 参考1: C++继承中构造函数.析构函数调用顺序及虚函数的动态绑定 参考2 ...

  3. C++构造函数和析构函数的调用顺序

    1.构造函数的调用顺序 基类构造函数.对象成员构造函数.派生类本身的构造函数 2.析构函数的调用顺序 派生类本身的析构函数.对象成员析构函数.基类析构函数(与构造顺序正好相反) 3.特例 局部对象,在 ...

  4. C++中构造函数和析构函数的调用顺序

    一般而言,析构函数调用的顺序和构造函数调用顺序相反,但是,对象的存储类别可以改变调用析构函数的顺序.举例说明: CreateAndDestroy类的定义 CreateAndDestroy类的成员函数的 ...

  5. C++:派生类的构造函数和析构函数的调用顺序

    一.派生类 在C++编程中,我们在编写一个基类的派生类时,大致可以分为四步: • 吸收基类的成员:不论是数据成员还是函数成员,派生类吸收除基类的构造函数和析构函数之外的全部成员. • 改造基类函数:在 ...

  6. C++学习笔记(7)----类的数组中构造函数和析构函数的调用顺序

    C++类的数组中构造函数和析构函数的调用顺序(2) 对于如下的代码: #include<iostream> using namespace std; class CBase { priva ...

  7. 基类的析构函数写成virtual虚析构函数

    虚函数作用:动态绑定,实现多态效果. 场景问题: 派生类中有资源需要回收,而在编程中采用多态,由基类的指针指向派生类,则在释放的时候,如果基类的析构函数不是virtual,则派生类的析构函数得不到释放 ...

  8. c++学习笔记4,派生类的构造函数与析构函数的调用顺序(一)

    測试源代码: //測试派生类的构造函数的调用顺序何时调用 //Fedora20 gcc version=4.8.2 #include <iostream> using namespace ...

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

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

随机推荐

  1. MySQL 1054错误 Unknown column .... in 'on clause'

    ERROR 1054 (42S22): Unknown column ... in 'on clause' 原因: MySQL5.0 Bug, 要把联合的表用括号包含起来才行: 例: SELECT ( ...

  2. 单向链表(C#)

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.D ...

  3. EM 期望最大化算法

    (EM算法)The EM Algorithm EM是我一直想深入学习的算法之一,第一次听说是在NLP课中的HMM那一节,为了解决HMM的参数估计问题,使用了EM算法.在之后的MT中的词对齐中也用到了. ...

  4. iOS友盟三方登陆

    Umeng三方登陆个人总结 Demo地址:https://github.com/haozheMa/UmengThirdLoginDemo这里仅以微信.QQ和新浪微博作为例子首先根据官方文档 导入以下依 ...

  5. 修改maven本地仓库的位置

  6. #Pragma Pack(n)与内存分配

    #pragma pack(n) 解释一: 每个特定平台上的编译器都有自己的默认"对齐系数"(也叫对齐模数).程序员可以通过预编译命令#pragma pack(n),n=1,2,4, ...

  7. enum的java例子

    Grade.java package com.zhiyuan.myenum; /** * <p>Title: 枚举类 * <p>Company: * @description ...

  8. tableview的reloadData应注意

    http://blog.csdn.net/ouyangtianhan/article/details/7835041 http://stackoverflow.com/questions/160715 ...

  9. Delphi 数据类型的说明

    简单类型包括实数类型(Real) 和有序类型(Ordinal),有序类型又包括整数类型,字符类型,布尔类型,枚举类型和子界类型等. 数据类型                       范围      ...

  10. S3C2440启动代码2440init.s彻底解析

    可以选择nand启动和nor启动,这两者之间的关系通过一个按键来选择 这个OM0有何玄机,在数据手册中有这么一段 位宽RAM启动了(当然,还得设置一些东西,下面就说), Nanaflash启动经历的过 ...