文章参考:
爱编程的大丙 (subingwen.cn)
C++中有多种数据类型,如:变量、数组、对象。这些数据类型各自的初始化方式,并没有统一的方法。为了简化初始化过程,C++11提出了一种统一的初始化方法,即列表初始化
。
1. 统一的初始化
1.1 C++98
在C++98中,有两种情况可以使用列表初始化:
- 普通的数组。
- 可以直接使用内存拷贝函数
memcpy()
的对象。
EG:
// 数组初始化
int arr1[] = {1, 2, 3, 4, 5};
double arr2[] = {1.1, 1.2, 1.3};
// 对象的初始化
struct Person{
int id;
double salary;
}zhangSan{1, 3333};
1.2 C++11
在C++11中,列表初始化的运用变得更加的灵活。
EG:
-
类使用成员初始化列表进行初始化:
#include <iostream> using namespace std; class Test{ private: int _num; public: Test(int num); Test(const Test& test); }; // 一般构造函数 Test::Test(int num): _num(num){ cout << "common construction function" << endl; } // 拷贝构造函数 Test::Test(const Test& test){ _num = test._num; cout << "copy construction function" << endl; } int main(void){ Test t1(1); // 调用一般构造函数 Test t2 = 2; // 这是一个特殊情况,见下文: Test t3 = Test(2); // 和上一句本质上是一样的,见下文 Test t4(t1); // 调用拷贝构造函数 Test t5 = t2; // 调用拷贝构造函数 Test t6 = {3}; // 成员初始化列表,调用一般构造函数 Test t7{4}; // 成员初始化列表,调用一般构造函数 Test t8 = {t1}; // 成员初始化列表,调用拷贝构造函数 Test t9{t2}; // 成员初始化列表,调用拷贝构造函数 return 0; }
Test t2 = 2
:该指令会被编译器改写为Test t2 = Test(2)
。注意:之后并没有调用拷贝构造函数或移动构造函数(即通过匿名对象(右值)来给左值变量进行初始化),这时C++语法的一种特例,编译器直接令t2
和Test(2)
等同,完全等价于Test t2(2)
,因此只会调用一次普通的构造函数。综上:Test t2 = 2
等价于Test t2(2)
。
-
new
对象时使用成员初始化列表进行初始化:int * p = new int{520}; double b = double{52.134}; int * array = new int[3]{1,2,3};
p
:指向了一个new的内存,并使用成员初始化列表初始化为520。b
:对匿名对象使用列表初始化后,再进行拷贝初始化。array
:在堆内分配了一块内存,使用成员初始化列表将的堆多个元素进行初始化。
-
作用于函数返回值:
#include <iostream> #include <cstring> using namespace std; class Person{ private: int _id; string _name; public: Person(){} Person(int id, string name): _id(id), _name(name){} void show_msg(); }; void Person::show_msg(){ cout << "id: " << _id << "\t" << "name: " << _name << endl; } // 使用成员初始化列表,直接匿名返回对象 Person get_case(){ return {1, "zhangSan"}; } int main(void){ Person p = get_case(); p.show_msg(); return 0; }
2. 列表初始化细节
列表初始化有两种情况:
- 聚合体:可以直接进行初始化。
- 非聚合体:必须要有对应的构造函数。
2.1 聚合体
聚合体可以直接使用列表初始化,无需对应的构造函数。
要成为聚合体,需要同时满足以下五个条件,否则就是非聚合体:
-
没有自定义的构造函数。
-
没有私有/保护属性的非静态成员。如果有静态成员,那么该静态成员不能通过列表初始化进行初始化,因为静态成员的初始化是先于类的初始化,在编译阶段完成的,而列表初始化是在运行阶段进行的,因此要对静态成员进行独立的初始化。
struct Test1{ int a; int b; private: int c; }t1{1, 2, 3}; // error,因为存在私有/保护属性的非静态成员,无法使用初始化列表进行初始化。 struct Test2{ int a; int b; private: static int c; }t1{1, 2, 3}; // error,因为 静态成员无法使用初始化列表进行初始化 struct Test2{ int a; int b; private: static int c; }t1{1, 2}; int Test2::c = 3; // 需要对静态成员进行单独初始化。
-
没有基类。
-
没有虚函数。
-
类中不能有使用
{}
和=
直接初始化的非静态成员(注意:从C++14开始,即使有,也可以使用列表初始化。
)
2.2 非聚合体
非聚合体也可以使用列表初始化,但前提是要有对应的构造函数,列表初始化会自动调用对应的构造函数进行初始化。
Eg:
#include <iostream>
using namespace std;
struct T1{
private:
int _a;
public:
int _b;
T1(int a, int b): _a(a), _b(b){}
};
int main(void){
T1 t = {1, 2}; // 列表初始化调用了自定义的构造函数
return 0;
}
注意:
即使当前类的某个成员是非聚合体,当前类也可以是聚合体。也就是说:聚合体/非聚合体不是嵌套的概念。
#include <iostream>
using namespace std;
struct T1{
private:
int _a;
public:
int _b;
};
struct T2{
public:
T1 t;
int _a;
int _b;
};
int main(void){
T2 t = {{}, 1, 2};
return 0;
}
这里尽管T2
的成员变量t
是非聚合体,但T2依旧是聚合体,在使用列表初始化时,通过{}
来初始化t变量,其实就是调用了默认的无参构造函数。
3. std::initializer_list
3.1 概述
引入:有时我们在传递参数时,需要传递多个相同类型、数量不定的参数,这时我们可以使用数组、vector
、list
等。在C++11中,为我们提供了一个更加轻量级的模板类std::initializer_list
来实现这一功能。
特点:
- 内部定义了
iterator
等容器必须的概念,且遍历时得到的迭代器是只读
的。 - 可以接收长度任意的初始化列表,但元素类型必须一致。
- 有三个成员接口:
begin()
end()
size()
- 只能被整体初始化或赋值。
3.2 作为普通函数参数
#include <iostream>
using namespace std;
void traversal(initializer_list<int> var){
auto it = var.begin();
for (; it != var.end(); ++temp){
cout << *it << " ";
}
cout << endl;
}
int main(void){
traversal({1, 2, 3, 4, 5});
return 0;
}
std::initializer_list
在遍历时得到一个只读的迭代器,因此如果想要修改值,只能通过值覆盖的方式。
std::initializer_list
的效率较高,因为它并不是保存了初始化列表中元素的拷贝,而是仅仅存储了初始化列表中元素的引用。
3.3 作为构造函数
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class Test
{
private:
vector<string> m_names;
public:
Test(initializer_list<string> list)
{
for (auto it = list.begin(); it != list.end(); ++it)
{
cout << *it << " ";
m_names.push_back(*it);
}
cout << endl;
}
};
int main(void)
{
Test t({ "jack", "lucy", "tom" });
return 0;
}
标签:初始化,聚合体,int,列表,Test,构造函数
From: https://www.cnblogs.com/beasts777/p/17879350.html