cpp列表初始化是什么
形式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 #include <iostream> using namespace std;class A {public : A (int num) : a_ (num) { cout << a_ << endl; } private : const int a_; }; int main () { A a (12 ) ; }
即,在构造函数后,使用列表的方式来初始化成员变量。
构造函数内部执行顺序
调用构造函数
基类构造函数
进入左括号前,按照成员在类内声明的顺序,调用默认构造函数初始化成员变量。这就是隐藏的列表初始化。也是列表初始化时按声明顺序调用构造函数的原因。
执行构造函数内部语句
出构造函数,构造函数完成
其实,列表初始化一直都在,只是我们在代码中忽略了。
示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 #include <iostream> using namespace std;class Test {public : Test () { cout << "constructor called" << endl; } Test (const Test& t) { cout << "copy constructor called" << endl; } Test& operator =(const Test& t) { cout << "assignment operator called" << endl; return *this ; } }; class Base {public : Base () { cout << "call base constructor" << endl; } }; class B : public Base {public : B (Test ele) : t_ (ele) { cout << "call B constructor" << endl; } private : Test t_; }; int main () { Test t; cout << "==========" << endl; B b (t) ; }
结果:
1 2 3 4 5 6 7 @└────> # ./a.out constructor called ========== copy constructor called // 传参的拷贝构造 call base constructor // 调用基类构造函数 copy constructor called // 列表初始化 call B constructor // 子类构造函数内语句
列表初始化顺序
列表初始化顺序并不取决于在构造函数中列表的顺序,而取决于该成员在类中声明的顺序。
示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 #include <iostream> using namespace std;class Test1 {public : Test1 () = default ; Test1 (const Test1& t) { cout << "Test1 copy constructor called" << endl; } }; class Test2 {public : Test2 () = default ; Test2 (const Test2& t) { cout << "Test2 copy constructor called" << endl; } }; class Test3 {public : Test3 () = default ; Test3 (const Test3& t) { cout << "Test3 copy constructor called" << endl; } }; class A {public : A (Test1 ele1, Test2 ele2, Test3 ele3) : t2_ (ele2), t1_ (ele1), t3_ (ele3) {} private : Test3 t3_; Test1 t1_; Test2 t2_; }; int main () { Test1 t1; Test2 t2; Test3 t3; cout << "==========" << endl; A a (t1, t2, t3) ; }
结果:
1 2 3 4 5 6 7 8 @└────> # ./a.out ========== Test3 copy constructor called // A 的构造函数中的参数复制,因为是从右边的参数开始先拷贝,所以先构造 ele3,再 ele2,最后 ele1 Test2 copy constructor called Test1 copy constructor called Test3 copy constructor called // 按照类中声明的顺序,先拷贝给 t3_,再 t1_,最后 t2_。 Test1 copy constructor called Test2 copy constructor called
区别
如上面所说,在构造函数中使用 :a_(num) 的形式,对成员变量进行初始化。而在大括号中用等号来对成员变量进行赋值,是赋值行为,并非初始化。这个可以使用下面的例子来验证:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 #include <iostream> using namespace std;class Test {public : Test () { cout << "constructor called" << endl; } Test (const Test& t) { cout << "copy constructor called" << endl; } Test& operator =(const Test& t) { cout << "assignment operator called" << endl; return *this ; } }; class A {public : A (Test ele) { t_ = ele; } private : Test t_; }; class B {public : B (Test ele) : t_ (ele) {} private : Test t_; }; int main () { Test t; cout << "==========" << endl; A a (t) ; cout << "==========" << endl; B b (t) ; }
输出:
1 2 3 4 5 6 7 8 9 @└────> # ./a.out constructor called ========== copy constructor called // A 中 ele 的拷贝构造 constructor called // A 中 t_ 的构造函数 assignment operator called // A 中 = ele 的赋值调用 ========== copy constructor called // B 中 ele 的拷贝构造 copy constructor called // B 中 t_ 的初始化(拷贝构造)
可以看到上面对于 A 来说,是先调用构造函数再调用赋值函数,而对于 B 来说就是拷贝构造函数。所以列表的形式是初始化 ,不同于在大括号内赋值 。
列表初始化可以为 const 变量赋初值,但是大括号内赋值不行。