本文针对C++构造函数进行深度探究,供大家参考,具体内容如下
1、引子:
以下代码中的输出语句输出0吗,为什么?
struct Test
{
int _a;
Test(int a) : _a(a) {}
Test()
{
Test(0);
}
};
Test obj;
cout << obj._a << endl;
输出为:-858993460
2、剖析
上面代码的输出为一个垃圾值,也就是说obj调用构造函数并没有对成员进行初始化工作,虽然默认无参构造Test()内部调用了Test(int a),但从结果看,初始化工作并不成功。这是为什么呢?
在执行构造函数时,Test()并不会调用"this"对象(即obj对象)的Test::Test(int a),而是会用Test::Test(int a)来创建一个新的临时实例对象,然后当这条语句执行完后,这个新的临时对象马上就会被销毁。这样一来,"this"对象就没有被初始化,成员_a就是垃圾值,以后使用"this"对象就有可能产生一些问题。
3.重点:构造函数互相调用
分析完这个题目之后,我们会想到另一个问题。也是我们今天重点关注的问题:
class Test
{
int _a;
int _b;
int _c;
public:
Test(int a, int b) : _a(a), _b(b),_c(0) {}
Test(int a, int b, int c);
};
如果我们C++类中有两个构造函数,分别为Test(int a, int b)和Test(int a, int b, int c)。如果我们的构造函数Test(int a, int b, int c)要完成所有成员(a,b,c)的赋值初始化工作,可以这样写:
Test::Test(int a, int b, int c)
: _a(a)
, _b(b)
, _c(c)
{
}
但是,这样写又重复了构造函数Test(int a, int b)的工作,类成员少的情况下还好,如果成员非常多,重复写的话代码量过大,而且代码可读性降低了。然而我们可以看到构造函数Test(int a, int b)已经完成了成员a和成员b的赋值初始化工作,为了减少代码量,就想着让3个参数的构造函数调用2个参数的构造函数,然后在执行一些自己的代码,这就如同派生类先调用基类的同名函数,再执行自己特有的代码。但是这种机制如何实现呢?
之前我们得出过结论:构造函数调用另一个构造函数并不能完成当前对象的初始化工作,只是初始化了临时对象。下面我们就进入本文的核心问题:如何在构造函数中调用本类的另一个构造函数来初始化当前对象?
方法一:使用placement new技术,在3个参数中显式调用2个参数的构造函数。
3参数构造函数可以这样实现:
Test::Test(int a, int b, int c)
{
new (this) Test(a, b);
...
}
构造函数分为2个执行阶段:一是在初始化列表的初始化阶段,二是在构造函数体内的赋值阶段。上述方法是在第二个阶段调用2个参数的构造函数。










