C++ 构造函数和析构函数的调用顺序、虚析构函数的作用
构造函数和析构函数的调用顺序
构造函数的调用顺序:
当建立一个对象时,首先调用基类的构造函数,然后调用下一个派生类的构造函数,依次类推,直至到达最底层的目标派生类的构造函数为止。
析构函数的调用书序:
当删除一个对象时,首先调用该派生类的析构函数,然后调用上一层基类的析构函数,依次类推,直到到达最顶层的基类的析构函数为止。
简单的说,构造函数是“自上向下”调用,析构函数是“自下而上”调用。
演示代码如下:
#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++ 构造函数和析构函数的调用顺序、虚析构函数的作用的更多相关文章
- C++继承,多重继承,虚继承的构造函数以及析构函数的调用顺序问题
#include <iostream> using namespace std; class A{ int data_a; public: A(){ data_a = ; cout < ...
- C++C++中构造函数与析构函数的调用顺序
http://blog.csdn.net/xw13106209/article/details/6899370 1.参考文献 参考1: C++继承中构造函数.析构函数调用顺序及虚函数的动态绑定 参考2 ...
- C++构造函数和析构函数的调用顺序
1.构造函数的调用顺序 基类构造函数.对象成员构造函数.派生类本身的构造函数 2.析构函数的调用顺序 派生类本身的析构函数.对象成员析构函数.基类析构函数(与构造顺序正好相反) 3.特例 局部对象,在 ...
- C++中构造函数和析构函数的调用顺序
一般而言,析构函数调用的顺序和构造函数调用顺序相反,但是,对象的存储类别可以改变调用析构函数的顺序.举例说明: CreateAndDestroy类的定义 CreateAndDestroy类的成员函数的 ...
- C++:派生类的构造函数和析构函数的调用顺序
一.派生类 在C++编程中,我们在编写一个基类的派生类时,大致可以分为四步: • 吸收基类的成员:不论是数据成员还是函数成员,派生类吸收除基类的构造函数和析构函数之外的全部成员. • 改造基类函数:在 ...
- C++学习笔记(7)----类的数组中构造函数和析构函数的调用顺序
C++类的数组中构造函数和析构函数的调用顺序(2) 对于如下的代码: #include<iostream> using namespace std; class CBase { priva ...
- 基类的析构函数写成virtual虚析构函数
虚函数作用:动态绑定,实现多态效果. 场景问题: 派生类中有资源需要回收,而在编程中采用多态,由基类的指针指向派生类,则在释放的时候,如果基类的析构函数不是virtual,则派生类的析构函数得不到释放 ...
- c++学习笔记4,派生类的构造函数与析构函数的调用顺序(一)
測试源代码: //測试派生类的构造函数的调用顺序何时调用 //Fedora20 gcc version=4.8.2 #include <iostream> using namespace ...
- 不要在基类析构函数中调用纯虚函数,否则运行时会报错“pure virtual method called”
如上. 这是因为:delete派生类对象时,先调用派生类的析构函数,然后再调用基类的析构函数:此时如果调用纯虚函数的话,派生类的对象已经被破坏了,所以会报错. http://www.cnblogs.c ...
随机推荐
- openstack controller ha测试环境搭建记录(十五)——创建实例
# source demo-openrc.sh # ssh-keygenGenerating public/private rsa key pair.Enter file in which to sa ...
- 一元线性回归分析及java实现
http://blog.csdn.net/hwwn2009/article/details/38414911 一元线性回归分析及java实现 2014-08-07 11:02 1072人阅读 评论(0 ...
- 小偷网站工具--Teleport Ultra
可以克隆别人网站的工具 http://jingyan.baidu.com/article/219f4bf7dce58bde442d3836.html
- 《算法导论》归并排序----merge-sort
伪代码请见<算法导论>2.3节 merge-sort实现: public class MergeSort { public static void sort(double [ ...
- X-003 FriendlyARM tiny4412 uboot移植之添加相应目录文件
X-003 FriendlyARM tiny4412 uboot移植之添加相应目录文件 <<<<<<<<<<<<<< ...
- 功率W与dBm的对照表及关系(转)
源:功率W与dBm的对照表及关系 功率W与dBm的对照表 dBm Watts dBm Watts 0 ...
- Eclipse发布Maven项目到远程服务器
pom.xml中的配置依赖有两种: 一.tomcat-maven.plugin <plugin> <groupId>org.codehaus.mojo</groupId& ...
- 使用命令创建github代码仓库,push本地仓库到github远程代码仓库
1.利用命令创建github远程代码仓库 在将本地代码push到github远程代码仓库之前,总是需要新建github代码仓库,在将本地仓库关联到github远程仓库.其中最为繁琐的操作是建立gith ...
- java web开发中的奇葩事web.xml中context-param中的注释
同事提交了代码.结果除同事之外,其他人全部编译报错.报错说web.xml中配置的一个bean 没有定义.按照报错提示,各种找,无果. 由于代码全部都是提交到svn主干,之前也没有做过备份,只能一步一步 ...
- mysql授权远程用户连接(权限最小化原则)
1.进入MySQL,创建一个新用户root,密码为root: 格式:grant 权限 on 数据库名.表名 to 用户@登录主机 identified by "用户密码"; gra ...