C++中多态中构造函数与析构函数的调用

时间:2023-01-16 13:34:54

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

 #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&plus;&plus;C&plus;&plus;中构造函数与析构函数的调用顺序

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

  2. C&plus;&plus;中构造函数和析构函数的调用顺序

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

  3. C&plus;&plus;学习笔记&lpar;7&rpar;----类的数组中构造函数和析构函数的调用顺序

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

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

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

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

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

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

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

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

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

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

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

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

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

  10. C&plus;&plus;构造函数和析构函数的调用顺序

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

随机推荐

  1. 浩瀚科技 定制现场无线手持打印PDA手持终端扫描条码开单解决方案

    PDA通过扫描商品条码移动开单,实现便携式办公,伴随式销售,是深圳市浩瀚技术有限公司的一款最新安卓微POS产品,PDA能通过WIFI无线局域网.GPRS互联网直接与主机电脑连接,让公司业务人员能随时随 ...

  2. UVA Knight Moves

    题目例如以下: Knight Moves  A friend of you is doing research on the Traveling Knight Problem (TKP) where ...

  3. Word Ladder 解答

    Question Given two words (beginWord and endWord), and a dictionary's word list, find the length of s ...

  4. 漂亮的表格样式&lpar;使用CSS样式表控制表格样式&rpar;

    根据WEB2.0风格,设计了几个表格样式,我希望你喜欢. WEB2.0推广使用div开放式布局.但并不是完全放弃使用形式,在数据表现形式而言是一个不错的选择. 本节将介绍如何使用现在CSS样式表来控制 ...

  5. Linux内核 hlist&lowbar;head&sol;hlist&lowbar;node结构解析

    内核中的定义: struct hlist_head {    struct hlist_node *first;}; struct hlist_node {    struct hlist_node ...

  6. php目录函数

    1.创建 mkdir()mkdir(目录地址,权限模式,是否递归创建)默认不支持递归创建,用第三个参数true表示递归创建 <?php header("content-type:tex ...

  7. JMeter元件的作用域和执行顺序

    元件的作用域 配置元件:会影响其作用范围内的所有元件,作用范围是最大的,只要创建就对所有元件起作用. 前置处理器:在其作用范围内的每一个Sample元件之前执行: 定时器:对其作用范围内的每一个Sam ...

  8. salesforce零基础学习(八十一)更改标准字段的label名称(Admin)

    我们在开发中往往需要考虑国际化功能,salesforce 提供了国际化功能,在search部分搜索translate,便可以找到translate部分,从而对需要的进行translate.比如pick ...

  9. WPF App&period;xaml&period;cs常用模板,包括:异常捕获,App只能启动一次

    App.xaml.cs中的代码每次都差不多,故特地将其整理出来直接复用: using System; using System.Configuration; using System.Diagnost ...

  10. Oracle 执行报错表空间或临时表空间不足&comma;降低水位线方法

    Oracle 执行语句插入临时表报表空间不足,在增加表空间到最大后依然报错,经分析应该为创建的临时表水位线未清除导致,查询降低水位线方法如下: 原文地址:http://blog.itpub.net/2 ...