做个实验,看一下成员变量的构造析构,父类子类的构造析构,以及虚函数对调用的影响。

 #include <iostream>
using namespace std; class Member
{
public:
Member(int n):m_n1(n)
{
cout<<"Member::Member("<<m_n1<<")"<<endl;
}
~Member()
{
cout<<"Member::~Member("<<m_n1<<")"<<endl;
}
private:
const int m_n1;
}; class Base
{
public:
Base():m_m1()
{
cout<<"Base::Base()"<<endl;
OnConstruct();
}
~Base() //这里目前不是虚函数
{
cout<<"Base::~Base()"<<endl;
OnDistruct();
}
virtual void OnConstruct()
{
cout<<"Base::OnConstruct()"<<endl;
}
virtual void OnDistruct()
{
cout<<"Base::OnDistruct()"<<endl;
}
virtual void Foo1()
{
cout<<"Base::Foo1()"<<endl;
}
void Foo2()
{
cout<<"Base::Foo2()"<<endl;
} private:
Member m_m1;//这是个类对象
}; class Drived:public Base
{
public:
Drived():m_m2()
{
cout<<"Drived::Drived()"<<endl;
OnConstruct();
}
~Drived()
{
cout<<"Drived::~Drived()"<<endl;
OnDistruct();
}
virtual void OnConstruct()
{
cout<<"Drived::OnConstruct()"<<endl;
}
virtual void OnDistruct()
{
cout<<"Drived::OnDistruct()"<<endl;
}
virtual void Foo1()
{
cout<<"Drived::Foo1()"<<endl;
}
void Foo2()//这个不是虚函数
{
cout<<"Drived::Foo2()"<<endl;
}
private:
Member m_m2;//这是个类对象
}; int main(int argc, char *argv[])
{
Base* p = new Drived;
p->Foo1();
p->Foo2();
delete p;
return ;
}

这段代码的运行输出为:

 Member::Member()  //父类的初始化列表被执行
Base::Base() //父类构造
Base::OnConstruct()//父类构造中只会调用父类的函数。父类构造完毕
Member::Member() //子类构造的初始化列表
Drived::Drived() //子类构造
Drived::OnConstruct()//子类构造中只会调用子类的函数。子类构造完毕
Drived::Foo1()//发生多态,调用子类重写的函数
Base::Foo2() //未多态,调用父类版本的函数
Base::~Base() //父类开始析构
Base::OnDistruct()//父类析构只会调用父类中的函数
Member::~Member()//父类成员反初始化

同学们可以看到,子类的析构没有被执行,怎么让它能值执行呢?把父类的析构修饰为virtual即可:

     ~Base() //这里目前不是虚函数

这样在执行一遍,可以看到结果如果(注释出来的是新增的输出):

 Member::Member()
Base::Base()
Base::OnConstruct()
Member::Member()
Drived::Drived()
Drived::OnConstruct()
Drived::Foo1()
Base::Foo2()
Drived::~Drived() //子类析构,在父类之前执行
Drived::OnDistruct()//子类析构只会调用子类的函数
Member::~Member() //子类成员反初始化
Base::~Base()
Base::OnDistruct()
Member::~Member()

小结一下:

通过父类指针指向子类对象实现多态。

多态的时候,父类析构修饰为虚函数,以保证子类析构被调用。

构造顺序是:先父类后子类(这是最主要流程,后两条都再此前提下);初始化列表在构造前执行;构造函数中值调用本类的函数(无论是否为虚函数)。

析构顺序是:先子类后父类(注意虚析构);析构中只调用本类的函数;本类析构后再析构初始化列表中的成员。

												

C++中多态中构造函数与析构函数的调用的更多相关文章

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

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

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

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

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

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

  4. C++ 构造函数和析构函数的调用顺序、虚析构函数的作用

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

  5. C++类中函数(构造函数、析构函数、拷贝构造函数、赋值构造函数)

    [1]为什么空类可以创建对象呢? 示例代码如下: #include <iostream> using namespace std; class Empty { }; void main() ...

  6. C++中:默认构造函数、析构函数、拷贝构造函数和赋值函数——转

    对于一个空类,编译器默认产生4个成员函数:默认构造函数.析构函数.拷贝构造函数和赋值函数.1.构造函数:构造函数是一种特殊的类成员,是当创建一个类的时候,它被调用来对类的数据成员进行初始化和分配内存. ...

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

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

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

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

  9. 【C++】不要在构造函数或析构函数内调用虚函数

    这个问题来自于<Effective C++>条款9:永远不要在构造函数或析构函数中调用虚函数 . 假设有如下代码: class Transaction {// 所有交易的基类 public ...

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

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

随机推荐

  1. Dubbo(1)简介和Zookeeper安装

    一.简介: Dubbo主页地址  http://dubbo.io/ Dubbo百度百科:https://baike.baidu.com/item/Dubbo/18907815?fr=aladdin 二 ...

  2. java设计模式-责任链

    背景:要把<script>等<>html标签替换掉:把敏感词屏蔽或者替换等: 1.刚开始可能这么写: public class Main { public static voi ...

  3. jquery add()方法

    <html><meta charset="utf-8"><head><script type="text/javascript& ...

  4. GVRP

    一.GARP和GVRP GARP全称是通用属性注册协议(Generic Attribute Registration Protocol),它为处于同一个交换网内的交换成员之间提供了分发.传播.注册某种 ...

  5. 03-IP网际协议

    IP I P是T C P / I P协议族中最为核心的协议.所有的 T C P.U D P.I C M P及I G M P数据都以I P数据报格式传输. 不可靠( u n r e l i a b l ...

  6. BrowserSync前端同步测试工具

    安装教程

  7. [UE4]纯函数的执行时机

    一.纯函数是在需要的时候被调用 二.纯函数内不应当修改任何数据 三.如果同一个函数需要多个得到多个纯函数的返回值,则多个纯函数的调用顺序不是固定的,并且一个纯函数的调用顺序也不应当影响下一个纯函数的返 ...

  8. [UE4]在当前角色正前方2米处生成一个Actor

  9. [UE4]Delay的使用技巧:改变引擎执行顺序

    如果要游戏一开始就让机器人开火,但这是引擎还没有执行到武器的创建步骤,就可以使用“Delay”并设置函数的等待时间,让引擎先执行创建枪的步骤,然后机器人开火就没问题了.

  10. SQLServer: 解决“错误15023:当前数据库中已存在用户或角色”

    首先介绍一下sql server中“登录”与“用户”的区别,“登录”用于用户身份验证,而数据库“用户”帐户用于数据库访问和权限验证.登录通过安全识别符 (SID) 与用户关联.将数据库恢复到其他服务器 ...