构造函数

   
先看看构造函数的调用顺序规则,只要我们在平时编程的时候遵守这种约定,任何关于构造函数的调用问题都能解决;构造函数的调用顺序总是如下:
1.基类构造函数。如果有多个基类,则构造函数的调用顺序是某类在类派生表中出现的顺序,而不是它们在成员初始化表中的顺序。
2.成员类对象构造函数。如果有多个成员类对象则构造函数的调用顺序是对象在类中被声明的顺序,而不是它们出现在成员初始化表中的顺序。
3.派生类构造函数。

析构函数

   析构函数的调用顺序与构造函数的调用顺序正好相反,将上面3个点反过来用就可以了,首先调用派生类的析构函数;其次再调用成员类对象的析构函数;最后调用基类的析构函数。
    析构函数在下边3种情况时被调用:
    1.对象生命周期结束,被销毁时(一般类成员的指针变量与引用都i不自动调用析构函数);
    2.delete指向对象的指针时,或delete指向对象的基类类型指针,而其基类虚构函数是虚函数时;
    3.对象i是对象o的成员,o的析构函数被调用时,对象i的析构函数也被调用。

下面用例子来说说构造函数的的调用顺序:

#include "stdafx.h"
#include "iostream"
using namespace std;
class Base
{
public:Base(){ std::cout<<"Base::Base()"<<std::endl; }~Base(){ std::cout<<"Base::~Base()"<<std::endl; }
};class Base1:public Base
{
public:Base1(){ std::cout<<"Base1::Base1()"<<std::endl; }~Base1(){ std::cout<<"Base1::~Base1()"<<std::endl; }
};class Derive
{
public:Derive(){ std::cout<<"Derive::Derive()"<<std::endl; }~Derive(){ std::cout<<"Derive::~Derive()"<<std::endl; }
};class Derive1:public Base1
{
private:Derive m_derive;
public:Derive1(){ std::cout<<"Derive1::Derive1()"<<std::endl; }~Derive1(){ std::cout<<"Derive1::~Derive1()"<<std::endl; }
};int _tmain(int argc, _TCHAR* argv[])
{Derive1 derive;return 0;
}

运行结果是:

Base::Base()
Base1::Base1()
Derive::Derive()
Derive1::Derive1()
Derive1::~Derive1()
Derive::~Derive()
Base1::~Base1()
Base::~Base()

那么根据上面的输出结果,笔者稍微进行一下讲解,构造函数的调用顺序是;首先,如果存在基类,那么先调用基类的构造函数,如果基类的构造函数中仍然存在基类,那么程序会继续进行向上查找,直到找到它最早的基类进行初始化;如上例中类Derive1,继承于类Base与Base1;其次,如果所调用的类中定义的时候存在着对象被声明,那么在基类的构造函数调用完成以后,再调用对象的构造函数,如上例中在类Derive1中声明的对象Derive m_derive;最后,将调用派生类的构造函数,如上例最后调用的是Derive1类的构造函数。

virtual析构函数

下面来说一说为多态基类声明virtual析构函数:
在C++中,构造函数不能声时为虚函数,这是因为编译器在构造对象时,必须知道确切类型,才能正确的生成对象,因此,不允许使用动态束定;其次,在构造函数执行之前,对象并不存在,无法使用指向此此对象的指针来调用构造函数,然而,析构函数是可以声明为虚函数;C++明白指出,当derived class对象经由一个base class指针被删除,而该base class带着一个non-virtual析构函数,其结果未有定义---实际执行时通常发生的是对象的derived成分没被销毁掉。

看下面的例子:

class Base
{
public:Base(){ std::cout<<"Base::Base()"<<std::endl; }~Base(){ std::cout<<"Base::~Base()"<<std::endl; }
};class Derive:public Base
{
public:Derive(){ std::cout<<"Derive::Derive()"<<std::endl; }~Derive(){ std::cout<<"Derive::~Derive()"<<std::endl; }
};int _tmain(int argc, _TCHAR* argv[])
{Base* pBase = new Derive(); //这种base classed的设计目的是为了用来"通过base class接口处理derived class对象"delete pBase;return 0;
}

输出的结果是:

Base::Base()
Derive::Derive()
Base::~Base()

从上面的输出结果可以看出,析构函数的调用结果是存在问题的,也就是说析构函数只作了局部销毁工作,这可能形成资源泄漏败坏数据结构等问题;那么解决此问题的方法很简单,给base class一个virtual析构函数;

class Base
{
public:Base(){ std::cout<<"Base::Base()"<<std::endl; }virtual ~Base(){ std::cout<<"Base::~Base()"<<std::endl; }
};class Derive:public Base
{
public:Derive(){ std::cout<<"Derive::Derive()"<<std::endl; }~Derive(){ std::cout<<"Derive::~Derive()"<<std::endl; }
};int _tmain(int argc, _TCHAR* argv[])
{Base* pBase = new Derive();delete pBase;return 0;
}

输出结果是:

Base::Base()
Derive::Derive()
Derive::~Derive()
Base::~Base()

可能上面的输出结果正是我们所希望的吧!由此还可以看出虚函数还是多态的基础,在C++中没有虚函数就无法实现多态特性;因为不声明为虚函数就不能实现“动态联编”,所以也就不能实现多态啦!

转载地址:http://blog.csdn.net/bresponse/article/details/6914155

转载于:https://www.cnblogs.com/alice123/articles/5704434.html

浅谈构造函数与构析函数的调用顺序(转载)相关推荐

  1. 上机实验三:构造函数和构析函数

    写在前面:一开始我的名字没有改 所以部分截图的水印为我的用户id,第二次编辑时截图的水印是我的昵称,没有拿来别人的. 1.实验任务: 2.实验过程及代码: #include "twj.h&q ...

  2. 函数图像在图形计算机的应用,浅谈图形计算器在高中函数教学中的应用

    浅谈图形计算器在高中函数教学中的应用 陈理宏广州市花都区教研室(510800) 摘要:函数是高中一个重要内容,在这个内容的学习中应用图形计算器的函数功能和绘图功能,有利于学生加深对函数知识的理解,挖掘 ...

  3. java同名函数_浅谈Java 继承接口同名函数问题

    在Java中如果一个类同时继承接口A与B,并且这两个接口中具有同名方法,会怎么样? 动手做实验: interface A{ void fun(); } interface B{ void fun(); ...

  4. python hasattr函数_浅谈python中的getattr函数 hasattr函数

    hasattr(object, name) 作用:判断对象object是否包含名为name的特性(hasattr是通过调用getattr(ojbect, name)是否抛出异常来实现的). 示例: & ...

  5. Python实例浅谈之三Python与C/C++相互调用

    参考:http://blog.csdn.net/taiyang1987912/article/details/44779719 Python实例浅谈之三Python与C/C++相互调用 二.Pytho ...

  6. C++浅谈构造函数和析构函数

    构造函数 构造函数是一个特殊的成员函数,名字与类名相同,创建类类型对象时由编辑器自动调用,保证每个数据成员都有一个合适的初始值,并且在对象的生命周期内只调用一次. 构造函数是特殊的成员函数,需要注意的 ...

  7. C中堆管理—浅谈malloc,free,calloc,realloc函数之间的区别

    2019独角兽企业重金招聘Python工程师标准>>> 在进行C/C++编程的时候,需要程序员对内存的了解比较好清楚,经常需要操作的内存可分为下面几个类别: 堆栈区(stack):由 ...

  8. php array in array,浅谈PHP array_search 和 in_array 函数效率问题

    问题 在一个接口中,发现非常耗时,排查原因发现 array_search 查找数组中的元素的 key 时,效率随着数组变大,耗时增加.特别是大数组时,非常耗时.在函数 in_array 也有这个问题. ...

  9. 浅谈构造函数(c#)

    一:何为构造函数? 构造函数具有与类相同的名称却无任何返回类型,是在创建给定类型的对象时执行的类方法. 二:构造函数作用? 它通常初始化新对象的数据成员. 三:构造函数何时被调用? 构造函数是在类实例 ...

最新文章

  1. uniapph5配置index.html模板路径不生效解决办法
  2. 腾讯离职,迪士尼给发了offer
  3. android布局优化方案,Android启动优化-布局优化
  4. Java Eclipse进行断点调试
  5. linux go 安装
  6. 【Floyed】廉价最短路径
  7. pd对焦速度_捕捉爆炸瞬间!魅蓝Note6双PD对焦速度逆天
  8. 具体案例 快速原型模型_工业/产品设计流程案例---智能手表设计:从创意到模型(一)...
  9. Spring 创建Bean的三种方式
  10. Ruby On Rails --环境搭建之回眸一笑
  11. solr查询如何支持多个fq 多条件查询
  12. wifi连接上不能上网 手机WiFi连接上不能上网的解决办法
  13. 矩阵转置行列式的运算规律
  14. Docker与Jib(maven插件版)实战
  15. 生活大爆炸版石头剪刀布-简单模拟
  16. linux kali安装应用商店
  17. Hashtable简述
  18. Java使用graphhopper完成路线规划
  19. 详解CAN总线:CAN总线报文格式—遥控帧
  20. 函数和lambda表达式

热门文章

  1. 指针、数组、函数阶段小结
  2. 【C语言】控制台窗口图形界面编程(七):鼠标事件
  3. 【Protocol Buffer】Protocol Buffer入门教程(八):Windows平台部署Protobuf环境
  4. 【linux系统编程】进程间通信:信号中断处理
  5. 大脑构造图与功能解析_解析地轨、隐藏轨推拉门及折叠门的构造做法,收藏学习...
  6. php表达式生成工具,thinkPHP5.0数据查询表达式生成技巧
  7. C语言 指针 类型的用法大汇总(指针/引用/取值) *与
  8. 如何在QT中读取串口数据
  9. 找最大公约数和最小公倍数(c语言实现)
  10. Shell(3)——截取某些字符、默认值处理