文中一系列思考和内容引发自以下问题:
我需要在一个类的构造函数中调用另一个对象的构造函数,并使用this初始化其中的一个引用成员。
主要遇到的问题:
1. 构造函数的初始化列表中能访问this吗?
很明显c++创建一个对象分为两部分,创建内存和调用构造函数。
显然在初始化列表中,当前对象占用的内存已经创建好了,ok,this是可以访问的,只是其中的某些成员是没有初始化的(因为没有构造函数还没执行完,只能说对象是部分有效的)。
那也间接说明一个问题,在构造函数的函数体中使用this是完全可靠的,所有编译器可以自动初始化的成员都完成了初始化(比如基类的成员、带有默认构造函数的成员,注意具体初始化顺序是由类成员定义顺序确定的),但当前类的部分未在初始化列表中初始化的且没有默认构造函数类成员变量(比如常见的c++内置类型,int、float、指针等)的值是未定义的。
2. 构造函数参数与成员同名
构造函数的形式如下:带有一个和类成员同名的参数。打印输出只是为了验证成员变量是否初始化。
class A
{
public:
A(int a): a(a){cout<<a<<endl;}
private:
int a;
};
由于初始化列表中不能直接出现this,所以编译器会处理这种重名的情况。也就说,你不能在构造函数的初始化列表中显式用this做限定符,比如下面代码是无法通过编译的:
A:this->a(a){}
3. 如何在一个类的构造函数汇中调用另一个构造函数
构造函数是不允许嵌套调用的,但可以调用不同的重载形式。比如下面代码:(注意这是一道面试题目)
struct CLS
{
int m_i;
CLS( int i ) : m_i(i){}
CLS(){CLS(0);}
};
int main()
{
CLS obj;
cout << obj.m_i << endl;
return 0;
}
输出是多少?
---------------------------------------------------------------------------
答案是未知,因为m_i是未初始化的变量,是个野值。
"CLS(0);"的语句表示创建一个临时的CLS对象,并把该对象的成员m_i初始化为0。当前对象的值并没有初始化。
如果需要实现构造函数类调用另一个构造函数,需要借助于placement new运算符。代码如下:
struct CLS
{
int m_i;
CLS( int i ) : m_i(i){}
CLS()
{
new (this)CLS(0);
}
};
如果你对placement new不了解,建议看看c++ primer或者TCPL。
在c++11中可以直接通过委托或继承构造函数的形式实现上面功能。
struct CLS
{
int m_i;
CLS( int i ) : m_i(i){}
CLS():CLS(0){}
};
4. 解决方案
写到这里。我对于构造函数的初始化列表中引用this的情况基本了解,可以用下面代码解决本文开始提出的问题。
class Context;
class Ref
{
public:
Ref(Context&context):context(context){}
private:
Context &context;
};
class Context
{
public:
Context():ref(*this){}
private:
Ref ref;
};
复述下开始的问题:我需要在一个类的构造函数中调用另一个对象的构造函数,并使用this初始化其中的一个引用成员。
类Context会在其构造函数的初始化列表中通过this调用Ref的构造函数。
5. 参考资料
[1] 从一道题谈C++中构造函数调用构造函数 http://www.cnblogs.com/chio/archive/2007/10/20/931043.html
[2] c++ 一个构造函数 调用 另一个 构造函数 http://www.cnblogs.com/ayanmw/archive/2012/08/20/2647808.html