Luna's blog 月亮月亮酱

C++构造函数初始化列表浅析

2018-11-11

使用初始化列表可以减少成员对象的构造次数

1. 在构造函数中使用赋值对成员对象进行初始化

测试代码:

#include <iostream>
using namespace std;
class Component
{
public:
	Component()
	{
		cout<<"Component Constructor"<<endl;
	}
	Component(const Component & t)
	{
		cout<<"Component Copy Constructor"<<endl;
	}
	Component & operator=(const Component & t)
	{
		cout<<"Component Assignment Constructor"<<endl;
		return *this;
	}
};
class Container
{
public:
	Container(const Component & m)
	{
		cout<<"Container Constructor"<<endl;
		test_member=m;
	}
	Component test_member;
};

int main()
{
	Component member;
	Container example(member);
	return 0;
}

输出结果:

Component Constructor Component Constructor Container Constructor Component Assignment Constructor

从结果中可以看出成员对象是在容器对象初始化完成后再调用赋值构造函数完成初始化的。

2.使用初始化列表

测试代码与上面的代码仅有一处不同

	Container(const Component & m):test_member(m)
	{
		cout<<"Container Constructor"<<endl;
	}

输出结果:

Component Constructor Component Copy Constructor Container Constructor

成员对象只调用了一次拷贝构造函数,这样较少了类的构造次数从而提高了效率,而且是在容器对象构造之前就已经初始化完成。

必须使用初始化列表的情况

  1. const 对象: 因为const对象的值不能改变所以必须在容器类构造之前就初始化完成(C++11标准允许在类内直接赋值初始化)。
  2. 引用类型: 引用一但初始化完成就不能改变其指向,所以必须在容器类构造之前就初始化完成(C++11标准允许在类内直接初始化成对成员变量的引用)
  3. 没有默认构造函数的类类型.
  4. 子类调用父类构造函数的情况

注意

初始化列表的初始化顺序是根据变量的声明顺序来执行的,所以最好让初始化列表的顺序与成员变量的声明顺序一致,以免给以后的调试带来麻烦。 测试代码:

#include <iostream>
class Test
{
public:
	Test():a(10),b(a)
	{
	}
	int b;
	int a;
};
int main()
{
	Test test;
	std::cout<<test.a<<" "<<test.b;
	return 0;
}

输出结果:

10 -858993460

特别是在成员变量为引用类型的时候,如果不注意初始化顺序就容易变成悬空引用。


Similar Posts

Content