本文最后更新于 97 天前,其中的信息可能已经有所发展或是发生改变。
本文对普通变量、普通类对象在初始化时使用()
和{}
的情况进行区分说明,以免混淆不清。
一般使用()
是使用构造函数初始化,使用{}
是使用列表初始化,如下。
1. 基本初始化(略过)
这里大概对基本初始化方式做一个归纳
1.1 默认初始化
即只声明,让其调用默认构造函数。
对于基本变量类型(如int、double…),只声明就不会定义具体的初始值。对于类对象,就会调用可以不用填参数的默认构造函数,如果没有就会报错。
此初始化方式一般被称为没有初始化,不安全,不建议使用。
int x; // 未初始化,值随机
QVector3D point; // 调用默认构造函数,成员变量初始化为默认值
1.2 赋值初始化
对变量声明后使用=
显式赋值,一般只用于普通变量
int x = 1;
2. 构造函数初始化
即利用变量或类对象的构造函数进行初始化,而如果使用了=
也被称为拷贝,会有变量复制的过程。
QVector3D point = QVector3D(1.0, 2.0, 3.0); // 通过拷贝构造函数初始化
这种方式也可以简写,直接再变量名后面使用小括号符号()
,避免拷贝。
QVector3D point(1.0, 2.0, 3.0);
注意:
-
这种方式只需要注意构造函数即可,同正常的使用函数。比如QVector3D的构造函数参数是float类型,如果使用int类型调用构造函数初始化,也会触发C++的隐式转换而转换至float类型进行初始化,与列表初始化区分开。
QVector3D point1(1, 2, 3); // 不会报错 QVector3D point2{1, 2, 3}; // 报错
-
要注意不同变量或类的构造函数,有的构造函数并非是字面意思。
std::vector
v1(10, 1); // 10个int元素, 每个都初始化为1 std::vector v2{10, 1}; // 2个int元素, 值分别是10和1
3. 列表初始化
是C++11新更新的初始化方式,使用到大括号符号{}
。目前只有列表初始化的方式会使用到{}
。
在以前,列表初始化只可以对普通数组和没有构造函数的类或结构体使用,但在C++11中支持对任何类型使用列表初始化,编译器自动选择初始化方式。
int a = {10};
double b = {3.14};
int a[] = {1, 2, 3}; // 自动创建数组a[3]并赋值
std::vector<int> vec = {1, 2};
QVector3D point = {1.0, 2.0, 3.0}; // 拷贝
也可以直接简写,不进行拷贝,这种更广泛使用。
QVector3D point{1.0, 2.0, 3.0};
std::vector<int> v2{10, 1}; // 2个int元素, 值分别是10和1
struct Point {
int x, y;
};
Point p{10, 20}; // 聚合类型
注意:
-
列表初始化会进行严格的类型检查,不支持任何隐式的类型变换。
QVector3D point2{1, 2, 3}; // int赋值给float报错
-
可以使用列表快速初始化,置列表为空会默认填充0,避免没有初始化带来的错误。
int a{}; // 初始化为 0 double b{}; // 初始化为 0.0 std::string s{}; // 初始化为空字符串 ""
-
优先调用
std::initializer_list
构造函数,相当于手动为对象的列表初始化进行自定义。struct MyClass { MyClass(std::initializer_list
list) { for (int i : list) { std::cout << i << " "; } } }; MyClass obj{1, 2, 3}; // 调用 initializer_list 构造函数,输出:1 2 3