本文主要说明对象创建时构造函数的执行顺序,对象成员的初始化顺序;对象销毁时析构函数的执行顺序,对象成员的销毁顺序。
“对象的构造从类层次的最根处开始,在每一层中,首先调用基类的构造函数,然后调用成员对象的构造函数。析构则严格按照与构造相反的次序执行,该次序是唯一的,否则编译器将无法自动执行析构过程。
一个有趣的现象是,成员对象初始化的次序完全不受它们在初始化表中次序的影响,只由成员对象在类中声明的次序决定。这是因为类的声明是唯一的,而类的构造函数可以有多个,因此会有多个不同次序的初始化表。如果成员对象按照初始化表的次序进行构造,这将导致析构函数无法得到唯一的逆序。”(引用自References[1])
从这里看,每种语言特性的存在必有其原因,学习这些特性就是理解这些特性存在的原因。
下面的一段代码是对上面这段话的说明,其中有4个类Foo,Bar,Base,Derived,它们的构造函数、拷贝构造函数、析构函数都有信息输出。
#include <iostream>
using namespace std;
class Foo
{
public:
Foo() { cout << "Foo constructor" << endl; }
Foo(const Foo &foo) { cout << "Foo copy constructor" << endl; }
~Foo() { cout << "Foo deconstructor" << endl; }
};
class Bar
{
public:
Bar() { cout << "Bar constructor" << endl; }
Bar(const Bar &bar) { cout << "Bar copy constructor" << endl; }
~Bar() { cout << "Bar deconstructor" << endl; }
};
class Base
{
public:
Base() { cout << "Base constructor" << endl; }
~Base() { cout << "Base deconstructor" << endl; }
};
class Derived : public Base
{
public:
Derived() { cout << "Derived constructor without arguments" << endl; }
Derived(const Foo &foo, const Bar &bar);
Derived(const Bar &bar, const Foo &foo);
~Derived() { cout << "Derived deconstructor" << endl; }
private:
Foo m_foo;
Bar m_bar;
};
Derived::Derived(const Foo &foo, const Bar &bar) :
m_foo(foo),
m_bar(bar)
{
cout << "Derived constructor with argument[Foo foo, Bar bar] passed by references" << endl;
}
Derived::Derived(const Bar &bar, const Foo &foo) :
m_bar(bar),
m_foo(foo)
{
cout << "Derived constructor with argument[Bar bar, Foo foo] passed by references" << endl;
}
int main (int argc, char** argv)
{
Foo foo;
Bar bar;
cout << "test case 1:" << endl;
Derived deri_1; // (1)
cout << "test case 2:" << endl;
Derived deri_2(foo, bar); // (2)
cout << "test case 3:" << endl;
Derived deri_3(bar, foo); // (3)
cout << "test case end" << endl;
return 0;
}
执行结果是:
打印出的信息可分为几部分:
(1)创建对象foo和bar,执行Foo,Bar的构造函数
(2)TestCase1:创建对象deri_1,首先执行基类Base的构造函数,其次执行成员m_foo,m_bar的构造函数来构造成员,最后调用自身的构造函数(无参数)。
(3)TestCase2:创建对象deri_2,调用顺序与case1顺序相同。
(4)TestCase3:创建对象deri_3,调用顺序与case1顺序相同。注意到deri_2,deri_3的创建执行的是不同的Derived构造函数,虽然构造函数参数的顺序不同,但是构造成员的顺序是相同的。
(5)销毁对象deri_3,deri_2,deri_1,析构函数执行顺序相同,与构造对象的顺序相反。C++标准规定以对象声明相反的顺序销毁这些对象。
(6)销毁对象bar,foo。
编译运行环境:
$ uname -a
Linux localhost.localdomain 2.6.18-308.el5 #1 SMP Fri Jan 27 17:17:51 EST 2012 x86_64 x86_64 x86_64 GNU/Linux
$ g++ --version
g++ (GCC) 4.1.2 20080704 (Red Hat 4.1.2-52)
References:
[1]高质量C++编程指南:http://oss.org.cn/man/develop/c&c++/c/c.htm
[2]http://stackoverflow.com/q/15948381/1145750
转载本文请注明作者和出处http://garyelephant.me,请勿用于任何商业用途!
Author:GaryGao关注互联网、自动化、软件团队
分享到:
相关推荐
C++中的构造函数、析构函数剖析 在C+ + 中, 构造函数是一个在构件对象的时 候调用的特殊的函数, 其目的是对对象进行初始 化工作, 从而使对象被使用之前可以处于一种合 理的状态。析构函数是在撤消对象时, 收回对象 ...
4、请设计一个析构函数,同时输出“析构函数被调用” 5、设计一个成员函数 int dayDiff(CTime t) ,用于计算当前对象与形参t之间的相隔的天数,注意相隔天数为大于等于0的正整数。注意闰年的问题。 6、设计一...
某工厂使用一种圆柱形的铁桶来运输色拉油,但是关于该油桶的容量已经模糊,现在工人们测得了油桶直径和高(由键盘输入),请帮工人们计算...4、析构函数,该函数暂时不做额外处理工作,但需要输出“析构函数被调用”
此word文档主要讲解的是C++的构造函数和洗过后函数。配合几个例子,希望能给初学者一些帮助。
C++实现 类string的 普通构造函数, 拷贝构造函数 析构函数 和赋值函数
C++简单类的实现,包括构造函数,析构函数以及拷贝构造函数
c++中关于构造函数与析构函数部分的课件,有助于初学者自学。
C++实验四——构造函数与析构函数 (1) 定义一个正方形类,该类包括:正方形的边长(取值范围为1-30个“*”),四个成员函数,分别为:取边长、设置边长、画正方形和在构造这些类对象时能初始化正方形边长。 编写主函数...
问题描述: 在电脑前,大家经常忘记时间,不管是惬意的网上冲浪,还是凝神专注自己的作业,耽误了重要的事情总让人遗憾。那么我们就来制作自己的电子闹钟提示你,真正做到"闹钟在手,万事无忧"。...
构造函数不能声明为虚函数,析构函数可以声明为虚函数。
我刚学C++构造函数与析构函数,现在自己写了一段代码,和你们分享
string 类实现,构造函数、析构函数、操作符重载等 txt文件,复制到cpp中即可编译运行
C++类对象的拷贝构造函数 C++类对象的拷贝构造函数 C++类对象的拷贝构造函数 C++类对象的拷贝构造函数 C++类对象的拷贝构造函数 C++类对象的拷贝构造函数
数据结构 C++ 详细注释 构造函数与析构函数 类型转换.rar
C++高级程序设计实验报告三:类和对象—构造函数与析构函数 实验三类和对象—构造函数与析构函数: 1.理解掌握this指针的作用和用法; 2.理解掌握构造函数的定义和作用; 3.掌握构造函数的使用; 4.理解掌握拷贝...
C++构造函数与析构函数.pdf
C++对象模型 第1章 关于对象 第2章 构造函数语意学 第3章 Data语意学 第4章 Function语意学 第5章 构造、析构、拷贝语意学 第6章 执行期语意学 第7章 站在对象模型的尖端 第8章 C++对象模型总结 ...8.5.5 虚析构函数
本程序包含构造函数和析构函数,可以把构造函数和析构函数的作用区分开
C++构造函数_析构函数和赋值操作符学习小结