C++构造函数体内初始化与列表初始化的区别

本文探讨C++构造函数体内初始化与列表初始化的区别:
结论是:
若某个类(下文的class B)有一个类成员是类类型(下文的class A),那么
1、若类B通过构造函数体内初始化,会先调用类A的默认构造函数(无参构造函数),再调用类A的赋值运算符;
2、若类B通过初始化列表去初始化,则只调用类A的拷贝构造函数。
另外,虽然对于成员类型是内置类型的情况,通过上述两种情况去初始化是相同的,但是为了标准化,推荐使用初始化列表。
接下来,进入验证正题:
下面分别陈列类A和类B的声明:

class A {
public:
	A() {
		cout << "A Default constructor" << endl;
	}
	A(int a) {
		mA_a = a;
		cout << "A constructor" << endl;
	}
	A(const A&) {
		cout << "A copy constructor" << endl;
	}
	A& operator=(const A& a) {
		cout << "A assign operator" << endl;
		this->mA_a = a.mA_a;
		return *this;
	}
	~A() {
		cout << "A deconstructor" << endl;
	}
private:
	int mA_a;
};

1.此时类B采用的是在构造函数内初始化:

class B {
public:
	B() {
		cout << "B Default Constructor" << endl;
	}
	B(A &a) {
		cout << "come into B" << endl;
		_a = a;
		cout << "B Constructor" << endl;
	}
private:
	A _a;
};
int main(){
	A a;
	B b(a);
	return 0;
}

对应的输出为:
在这里插入图片描述
有图可得:
第一行的“A Default constructor”是构造a调用的无参数构造函数。
此处经过大佬点拨,再详细说明下
第二行的“A Default constructor”是因为进入到类B对应的构造函数体内后,编译器首先会插入一些对成员变量的初始化,也就是编译器会隐形的对未初始化的成员变量进行默认初始化,这里类B有一个类型为类A的成员变量_a,那么初始化它的时候会调用类A的默认构造函数,所以会有第二个“A Default constructor”出现。再才是执行类B对应的构造函数的函数体,从而出现结果中的第3-5行的内容。所以,通过在构造函数体内初始化,首先会调用该成员的默认构造函数(无参构造函数,即结果中的第二行),然后再调用其赋值运算符。

2.此时类B采用的是在初始化列表中初始化:

class B {
public:
	B() {
		cout << "B Default Constructor" << endl;
	}
	B(A &a) : _a(a){
		cout << "come into B" << endl;
		cout << "B Constructor" << endl;
	}
private:
	A _a;
};

对应的输出为:
在这里插入图片描述
与第一种的输出相比,没有了赋值运算符“A assign operator”,也没有了第二个“A Default Constructor”,改变的是新添了“A copy constructor”。这是因为列表中的初始化操作先于函数体执行,而这里应该调用的便是拷贝构造函数。所以,通过初始化列表去初始化成员,只会调用该成员的拷贝构造函数(成员类型是某类类型)或者对应的构造函数(成员类型是内置类型)。

总结:

以下几种情况必须使用初始化列表去初始化类成员:

  • 当初始化一个reference member时,即成员类型是引用。
  • 当初始化一个const member时,即成员类型是常量。
  • 当调用一个基类的constructor,而它拥有一组参数时。如果此时不使用列表初始化,那么就需要自己重载赋值运算符。
  • 当调用一个类成员的constructor,而它拥有一组参数时。
  • 若某个类成员没有定义无参构造函数,而定义了其它的构造函数,也必须使用初始化列表。

总之,为了标准化,建议使用列表初始化。不过小心一些陷阱:
因为类成员的初始化顺序不是按照初始化列表的顺序来的,而是按照类成员的声明顺序,假如出现下列情况:

class X {
	int i;
	int j;
public:
	X(int val) :j(val), i(j) {

	}
};

由于类成员的初始化顺序是按照其声明顺序,故先初始化i,然而初始化列表中用j去初始化它,但是此时j并没有被初始化,所以会出错。

  • 15
    点赞
  • 42
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值