109.C++类内初始化

发布时间 2023-07-18 12:36:32作者: CodeMagicianT

109.C++类内初始化

C++11规定,可以为数据成员提供一个类内初始值。创建对象时,类内初始值用于初始化数据成员。像下面这样,cursor和height的类内初始值均为0。

class Screen
{
private:
	int cursor = 0;
	int height = 0;
};

1.不能用圆括号给类内初始值的原因

C++ primer(第5版)中写道:类内初始值的提供必需以=或者花括号{}的形式。不能用园括号()。

关于这一点,可以参考网上的一个说法,如下:
由于无法避免下面的这种情况,这相当于对于int z(int);函数的声明,所以C++把用圆括号进行类内初始值定义为非法。

class Widget
{
private:
	typedef int x;
	int z(x);
};

2.=和花括号{}初始化的区别

2.1内置类型和类类型

对于这两者而言,=和{}初始化的区别不大,测试如下。

#include <iostream>     // std::cout
#include <string>
#include <vector>
using namespace std;

int main()
{
	std::cout << "*****内置类型*****" << std::endl;

	int ival = 1;

	int ival2{ 1 };
	int ival3 = { 1 };//实际上先构造一个{ 1 }匿名对象然后拷贝给ival3

	std::cout << "ival = " << ival << std::endl;
	std::cout << "ival2 = " << ival2 << std::endl;
	std::cout << "ival3 = " << ival3 << std::endl;

	std::cout << "*****类*****" << std::endl;

	string str = "aa";

	string str2{ "aa" };
	string str3 = { "aa" };//实际上先构造一个{ "aa" }匿名对象然后拷贝给str3

	std::cout << "str = " << str << std::endl;
	std::cout << "str2 = " << str2 << std::endl;
	std::cout << "str3 = " << str3 << std::endl;

	system("pause");
	return 0;
}

输出:

*****内置类型*****
ival = 1
ival2 = 1
ival3 = 1
*****类*****
str = aa
str2 = aa
str3 = aa
请按任意键继续. .

2.2类模板

对于类模板而言,我们可以看看实际上初始化列表{}和=初始化的过程:

先看初始化列表{}:

std::vector<std::string> vs{ "ssss" ,"dddd"};

以看到,上面的初始化的最后一步是在vector中插入初始化列表中元素

template <class _Iter, enable_if_t<_Is_iterator_v<_Iter>, int> = 0>
_CONSTEXPR20 vector(_Iter _First, _Iter _Last, const _Alloc& _Al = _Alloc()) : _Mybase(_Al)
{
	insert(begin(), _First, _Last);
}

再看=的初始化过程:

因为它实际上是一个拷贝构造的过程,所以=的右边必须是一个同类型的值,如下所示。vs3可以看成是一个’std::vector类型的变量,那么只能用std::vector类型的变量来初始化它,比如下面的vs_tmp。

std::vector<string> vs_tmp;
std::vector<string> vs3 = vs_tmp;

注意,千万不能这样:std::vector<string> vs2 = "eee";
上述初始化最后调用的是vector的拷贝构造函数,如下:

总结:

  • 初始化列表,列表中的元素就是模板的元素,如vector<string> tmp_vec= {"ddd","www"}
  • =初始化,只能用同类型,如只能用vector类型初始化vector类型

3.类内初始值的初始化列表{}方式

我在实际上调试时发现如下这样的一个问题:类内初始值的初始化列表{}方式编译器会报错。定义的类如下。
这让我很迷惑,因为在上面的测试中是可以的?后来才发现,因为我用的是VS2013,而它并不是完全支持C++11标准,所以对类内初始值用初始化列表的形式可能还不支持,换一个编译器后,不再报错。

class Wind_mgr
{
public:
	void putsData()
	{
		str.push_back("aaa");
	}
private:
	std::vector<std::string> str{ "bbb" };//Error,无法从“const char [4]”转换为“const std::allocator<_Ty>”
};

最后附上vector的几种初始化形式:

初始化格式 说明
vector v1 生成一个空vector
vector v2(V1) v2包含v1的所有元素副本
vector v2 = v1 等价于V2(V1)
vector v3(n,val) v3被初始化为n个val值,即v3有n个重复的元素
vector v4(n) v4是一个有n个元素的vector,只是n个元素均为值初始化值
vector v5 v5的大小就是初始化列表的大小,每个元素的值是初始化列表的值
vector v5 = 等价于V5
vector v6 (first, last) 将迭代器[first,last)区间的元素拷贝到v6

参考:C++类内初始值的初始化形式