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 ...
随机推荐
- implemented loader.php
http://stackoverflow.com/questions/11787176/manage-url-routes-in-own-php-framework This is how i imp ...
- HTML学习(三)文本格式化
HTML文本格式化HTML 可定义很多供格式化输出的元素,比如粗体和斜体字.例1:此例演示如何在一个 HTML 文件中对文本进行格式化<html> <body> <b&g ...
- 18、手把手教你Extjs5(十八)模块记录的拖放删除、拖放复制新增
网页当中的拖放(drag-drop)是比较有趣的操作,extjs5中很好的封装了拖放的动作,也有各种类来支持,但是要学好“拖放”这个东西真是很难,特别是象我这样英语不好的人,看不太懂官网上的说明,做一 ...
- $_SERVER参数的含义
$_SERVER是由服务器创建的,包含了头信息.参数.路径等信息,以下是一些键代表的含义: $_SERVER['PHP_SELF'] #当前正在执行脚本的文件名,与 document root相关.$ ...
- 《数据结构与算法分析:C语言描述》读书笔记------练习1.1 求第K大的数
求一组N个数中的第k个最大者,设k=N/2. import java.util.Random; public class K_Max { /** * @param args */ //求第K大的数,保 ...
- 设计模式笔记之一:MVP架构模式入门(转)
写在前面:昨天晚上,公司请来专家讲解了下MVP,并要求今后各自负责的模块都要慢慢的转到MVP模式上来.以前由于能力有限,没有认真关注过设计模式.框架什么的,昨晚突然兴趣大发,故这两天空闲时间一直在学习 ...
- iOS开发——delegate的相关警告
警告:Assigning to 'id<...Delegate>' from incompatible type '...ViewController *const_strong' 解决方 ...
- Masonry布局框架的使用
Masonry是一个轻量级的布局框架 拥有自己的描述语法 采用更优雅的链式语法封装自动布局 简洁明了 并具有高可读性.比我们使用自动布局,繁琐的约束条件,好用多了.下面我们来学学masonry的使用方 ...
- 【转】20条Linux命令面试问答
问:1 如何查看当前的Linux服务器的运行级别? 答: ‘who -r’ 和 ‘runlevel’ 命令可以用来查看当前的Linux服务器的运行级别. 问:2 如何查看Linux的默认网关? 答: ...
- CLR VIA C#: 基元类型、 引用类型 和 值类型
一.基元类型 . 引用类型 和 值类型的区别: 1.基元类型(primitive type):编译器直接支持的数据类型: 基元类型 直接映射到 FCL 中存在的类型. C# 小写是基元类型,例如:st ...