C++中重载构造函数的互相调用初始化成员变量的问题

C++中重载构造函数的互相调用初始化成员变量的问题

写一个类的时候,我们可能会希望有多重不同的初始化方式,此时就用到了重载构造函数。例如:

class TestConstructor
{
public:
	int value;

public:
	TestConstructor();
	TestConstructor(int);
};

这样我们可以有两种方式来初始化一个TestConstructor对象。
两个重载构造函数实现的代码可以分别是:

TestConstructor::TestConstructor()
{
	this->value = 10;
}
    		 
TestConstructor::TestConstructor(int value)
{
	this->value = value;
}

不能直接互相调用的重载构造函数

对于上边的这个无参构造函数,我们可以直接初始化value为10,但是如果参数很多,重载构造函数很多,那么就不可能每个都写一遍一模一样的赋值操作(其实也可以,就是有些丑,而且如果发生改动,则有可能会因为疏忽而出错)。所以,我们希望能够减少重复的赋值操作,例如调用其他的重载构造函数,就像这样,

TestConstructor::TestConstructor()
{
	TestConstructor(10);
}

TestConstructor::TestConstructor(int value)
{
	this->value = value;
}

但是这样可以嘛?我们试一下,为了方便查看实际生成的对象,我们在构造函数里输出对象的指针地址。

#include <iostream>

using namespace std;

class TestConstructor
{
public:
	int value;

public:
	TestConstructor();
	TestConstructor(int);
};

TestConstructor::TestConstructor()
{
	TestConstructor(10);
	cout << "constructor1:" << this << endl;
}

TestConstructor::TestConstructor(int value)
{
	this->value = value;
	cout << "constructor2:" << this << endl;
}

int main()
{
	TestConstructor *t = new TestConstructor();
	cout << t->value << endl;
	cout << t << endl;
	delete t;

	return 0;
}

运行结果:
constructor2:0x7fff81eb3494
constructor1:0x5586774bce70
0
0x5586774bce70

可以看出,在构造函数中调用重载构造函数时,被调用的构造函数重新创建了一个新的对象,所以不能用这种方法。

使用一个private的函数初始化成员变量

在我之前的项目中,为了解决这个问题,我采用了另外写一个private的函数的方法,把一些需要反复初始化的部分扔进了一个private的函数里。例如,

class TestConstructor
{
private:
	void initialize(int);

public:
	int value;

public:
	TestConstructor();
	TestConstructor(int);
};

void TestConstructor::initialize(int value)
{
	this->value = value;
}

TestConstructor::TestConstructor()
{
	this->initialize(10);
	cout << "constructor1:" << this << endl;
}

TestConstructor::TestConstructor(int value)
{
	this->initialize(value);
	cout << "constructor2:" << this << endl;
}

这个当然是一种解决方案。不过,最近用cppcheck analysis的时候,总是提示我 Member variable "xxx" is not initialized in the constructor., 这促使我思考了一下是否有更好的方法解决该问题。

使用带有默认参数的构造函数

在C++的函数声明中可以设置默认参数,所以一种可行的方法就是用含默认参数的构造函数来代替重载构造函数。如:

class TestConstructor
{
public:
	int value;

public:
	TestConstructor(int value = 10);
};

TestConstructor::TestConstructor(int value)
{
	this->value = value;
}

(NOTE:注意默认参数通常放在函数声明上,并且只能写一次,即声明写了,定义部分就不能再写)

使用placement new运算符调用重载构造函数

C++提供在预先分配好的内存上创建对象的方法,即placement new运算符。在C++中,构造函数的执行实际上分为两个阶段,分别是初始化阶段和计算阶段,其中初始化阶段先于计算阶段。在进入计算阶段前,所有的成员变量都已经完成了初始化,所以内存也都已经按需分配好,此时我们可以在this指针指向的这块内存上调用重载构造函数创建一个新的对象,覆盖掉原来的对象。

#include <iostream>

using namespace std;

class TestConstructor
{
public:
	int value;

public:
	TestConstructor();
	TestConstructor(int value);
};

TestConstructor::TestConstructor()
{
	new (this)TestConstructor(10);
	cout << "constructor1:" << this << endl;
}

TestConstructor::TestConstructor(int value)
{
	this->value = value;
	cout << "constructor2:" << this << endl;
}

int main()
{
	TestConstructor *t = new TestConstructor();
	cout << t->value << endl;
	cout << t << endl;
	delete t;

	return 0;
}

运行结果:
constructor2:0x55bece811e70
constructor1:0x55bece811e70
10
0x55bece811e70

使用C++11的委托构造函数(在初始化列表位置调用)

据我了解这是C++11中加入的功能,名为委托构造函数。其将重载构造函数放置在初始化列表的位置调用。

#include <iostream>

using namespace std;

class TestConstructor
{
public:
	int value;

public:
	TestConstructor();
	TestConstructor(int);
};

TestConstructor::TestConstructor():TestConstructor(10)
{
	cout <<"constructor1:"<< this << endl;
}
    		 
TestConstructor::TestConstructor(int value)
{
	this->value = value;
	cout <<"constructor2:"<<this << endl;
}

int main()
{
	TestConstructor *t = new TestConstructor();
	cout << t->value << endl;
	cout << t << endl;
	delete t;

	return 0;
}

运行结果:
constructor2:0x5594d644de70
constructor1:0x5594d644de70
10
0x5594d644de70

##总结
对于重载构造函数的互相调用初始化成员变量的问题,我们可以

  1. 使用一个私有函数初始化成员变量
  2. 使用带有默认参数的构造函数
  3. 使用placement new运算符调用重载构造函数
  4. 使用C++11的委托构造函数(在初始化列表位置调用)
  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值