C++中多态中构造函数与析构函数的调用
做个实验,看一下成员变量的构造析构,父类子类的构造析构,以及虚函数对调用的影响。
#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++中多态中构造函数与析构函数的调用的更多相关文章
- C++C++中构造函数与析构函数的调用顺序
http://blog.csdn.net/xw13106209/article/details/6899370 1.参考文献 参考1: C++继承中构造函数.析构函数调用顺序及虚函数的动态绑定 参考2 ...
- C++中构造函数和析构函数的调用顺序
一般而言,析构函数调用的顺序和构造函数调用顺序相反,但是,对象的存储类别可以改变调用析构函数的顺序.举例说明: CreateAndDestroy类的定义 CreateAndDestroy类的成员函数的 ...
- C++学习笔记(7)----类的数组中构造函数和析构函数的调用顺序
C++类的数组中构造函数和析构函数的调用顺序(2) 对于如下的代码: #include<iostream> using namespace std; class CBase { priva ...
- C++ 构造函数和析构函数的调用顺序、虚析构函数的作用
构造函数和析构函数的调用顺序 构造函数的调用顺序: 当建立一个对象时,首先调用基类的构造函数,然后调用下一个派生类的构造函数,依次类推,直至到达最底层的目标派生类的构造函数为止. 析构函数的调用书序: ...
- C++类中函数(构造函数、析构函数、拷贝构造函数、赋值构造函数)
[1]为什么空类可以创建对象呢? 示例代码如下: #include <iostream> using namespace std; class Empty { }; void main() ...
- C++中:默认构造函数、析构函数、拷贝构造函数和赋值函数——转
对于一个空类,编译器默认产生4个成员函数:默认构造函数.析构函数.拷贝构造函数和赋值函数.1.构造函数:构造函数是一种特殊的类成员,是当创建一个类的时候,它被调用来对类的数据成员进行初始化和分配内存. ...
- C++继承,多重继承,虚继承的构造函数以及析构函数的调用顺序问题
#include <iostream> using namespace std; class A{ int data_a; public: A(){ data_a = ; cout < ...
- C++:派生类的构造函数和析构函数的调用顺序
一.派生类 在C++编程中,我们在编写一个基类的派生类时,大致可以分为四步: • 吸收基类的成员:不论是数据成员还是函数成员,派生类吸收除基类的构造函数和析构函数之外的全部成员. • 改造基类函数:在 ...
- 【C++】不要在构造函数或析构函数内调用虚函数
这个问题来自于<Effective C++>条款9:永远不要在构造函数或析构函数中调用虚函数 . 假设有如下代码: class Transaction {// 所有交易的基类 public ...
- C++构造函数和析构函数的调用顺序
1.构造函数的调用顺序 基类构造函数.对象成员构造函数.派生类本身的构造函数 2.析构函数的调用顺序 派生类本身的析构函数.对象成员析构函数.基类析构函数(与构造顺序正好相反) 3.特例 局部对象,在 ...
随机推荐
- python中numpy的random模块
1. rand(d0,d1,.....,dn)产生[0,1]的浮点随机数,括号里面的参数可以指定产生数组的形状 例如:np.random.rand(3,2)则产生 3×2的数组,里面的数是0-1 ...
- PAT 乙级1030 完美数列(25) C++版
1030. 完美数列(25) 时间限制 300 ms 内存限制 65536 kB 代码长度限制 8000 B 判题程序 Standard 作者 CAO, Peng 给定一个正整数数列,和正整数p,设这 ...
- 1121 Damn Single (25 分)
1121 Damn Single (25 分) "Damn Single (单身狗)" is the Chinese nickname for someone who is bei ...
- win10 专业版 git bash 闪退问题终极解决方案
问题描述 Win10 64位专业版安装git 2.x之后出现 Git闪退,安装1.x出现bash: /dev/null: No such device or address fatal: open / ...
- DNS解析分析
一.基本概念 域名系统: 域名系统(英文:Domain Name System,缩写:DNS)是因特网的一项服务.它作为将域名和IP地址相互映射的一个分布式数据库,能够使人更方便地访问互联网.DNS使 ...
- Redis 穿透和雪崩
Redis穿透 出现原因:频繁的查询一个不存在的数据,由于缓存不命中,每次都要查询持久层,从而失去缓存保护后端的意义 解决方法: 部署过滤器拦截: 将数据库中数据的存在的Id存入列表,放入缓存中,每次 ...
- C#多线程学习笔记之(abort与join配合使用)
今天刚开始学多线程,尽管以前用过一点点,但是只是照着网上代码抄,没有真正理解,现在回过头来想研究研究,慢慢弄懂,下面就是我在网上所找资料的例子,相信大家都看过,做了小点改动 View Code nam ...
- windows10配置python
官网下载:https://www.python.org python3---->Download Windows x86-64 executable installer python2----& ...
- CS229 6.3 Neurons Networks Gradient Checking
BP算法很难调试,一般情况下会隐隐存在一些小问题,比如(off-by-one error),即只有部分层的权重得到训练,或者忘记计算bais unit,这虽然会得到一个正确的结果,但效果差于准确BP得 ...
- 《Linux 性能及调优指南》3.2 CPU瓶颈
翻译:飞哥 ( http://hi.baidu.com/imlidapeng ) 版权所有,尊重他人劳动成果,转载时请注明作者和原始出处及本声明. 原文名称:<Linux Performance ...