C++初始化列表
C++初始化列表
定义一个类对象时,常常使用初始化列表实例化一个对象,在进入构造函数函数体之前对成员变量完成初始化操作。普通成员变量既可以在初始化中初始化,也可以在函数体重赋值;const成员变量只能在初始化列表中赋值。下面对初始化列表进行一个简单介绍:
- 使用初始化列表
1 #include <iostream> 2 3 using namespace std; 4 5 class InitTest{ 6 public: 7 InitTest(int x,int y,int z) : a(x),b(y),c(z){} 8 public: 9 void Print() const{ 10 cout<<"a = "<<a<<endl; 11 cout<<"b = "<<b<<endl; 12 cout<<"c = "<<c<<endl; 13 } 14 private: 15 int a; 16 int b; 17 int c; 18 }; 19 20 int main(int argc, char** argv) 21 { 22 InitTest test(10,20,30); 23 test.Print(); 24 25 return 0; 26 }
成员变量被正确赋值,输出:
- 初始化列表必须使用场景1——const成员变量
1 class InitTest{ 2 public: 3 InitTest(int x,int y,int z){ 4 5 a = x; // error C2758: “InitTest::a”: 必须在构造函数基/成员初始值设定项列表中初始化 6 b = y; 7 c = z; 8 } 9 private: 10 const int a; 11 int b; 12 int c; 13 };
1 class InitTest{ 2 public: 3 InitTest(int x,int y,int z) : a(x){ // OK 4 b = y; 5 c = z; 6 } 7 public: 8 void Print() const{ 9 cout<<"a = "<<a<<endl; 10 cout<<"b = "<<b<<endl; 11 cout<<"c = "<<c<<endl; 12 } 13 private: 14 const int a; 15 int b; 16 int c; 17 };
- 初始化列表必须使用场景2——成员变量或基类未声明默认构造函数
成员变量未声明默认构造函数
1 #include <iostream> 2 3 using namespace std; 4 5 class InitTest{ 6 public: 7 InitTest(int x,int y,int z) : a(x),b(y),c(z){} 8 public: 9 void Print() const{ 10 cout<<"a = "<<a<<endl; 11 cout<<"b = "<<b<<endl; 12 cout<<"c = "<<c<<endl; 13 } 14 private: 15 int a; 16 int b; 17 int c; 18 }; 19 20 class HaveInitTest{ 21 InitTest test1; 22 public: 23 HaveInitTest(){} 24 }; 25 26 int main(int argc, char** argv) 27 { 28 HaveInitTest havetest; // error C2512: “InitTest”: 没有合适的默认构造函数可用 29 30 return 0; 31 }
1 #include <iostream> 2 3 using namespace std; 4 5 class InitTest{ 6 public: 7 InitTest(int x,int y,int z) : a(x),b(y),c(z){} 8 public: 9 void Print() const{ 10 cout<<"a = "<<a<<endl; 11 cout<<"b = "<<b<<endl; 12 cout<<"c = "<<c<<endl; 13 } 14 private: 15 int a; 16 int b; 17 int c; 18 }; 19 20 class HaveInitTest{ 21 InitTest test1; 22 public: 23 HaveInitTest() : test1(0,0,0){} 24 }; 25 26 int main(int argc, char** argv) 27 { 28 HaveInitTest havetest; // OK 29 30 return 0; 31 }
基类未声明默认构造函数
1 #include <iostream> 2 3 using namespace std; 4 5 class InitTest{ 6 public: 7 InitTest(int x,int y,int z) : a(x),b(y),c(z){} 8 private: 9 int a; 10 int b; 11 int c; 12 }; 13 14 class DerivedFromInitTest : public InitTest{ 15 public: 16 DerivedFromInitTest(){} 17 }; 18 19 int main(int argc, char** argv) 20 { 21 DerivedFromInitTest dervetest; // error C2512: “InitTest”: 没有合适的默认构造函数可用 22 23 return 0; 24 }
1 #include <iostream> 2 3 using namespace std; 4 5 class InitTest{ 6 public: 7 InitTest(int x,int y,int z) : a(x),b(y),c(z){} 8 private: 9 int a; 10 int b; 11 int c; 12 }; 13 14 class DerivedFromInitTest: public InitTest{ 15 public: 16 DerivedFromInitTest() : InitTest(0,0,0){} 17 }; 18 19 int main(int argc, char** argv) 20 { 21 DerivedFromInitTest derivetest; // OK 22 23 return 0; 24 }
最简单的解决方法是将InitTest的构造函数声明为:InitTest(int x = 0,int y = 0,int z = 0)。
- 初始化列表必须使用场景3——声明为引用类型的成员变量
1 #include <iostream> 2 3 using namespace std; 4 5 class InitTest{ 6 public: 7 InitTest(int &x, int y, int z){ 8 a = x; // error C2758: “InitTest::a”: 必须在构造函数基/成员初始值设定项列表中初始化 9 b = y; 10 c = z; 11 } 12 private: 13 int &a; 14 int b; 15 int c; 16 };
1 class InitTest{ 2 public: 3 InitTest(int &x, int y, int z) : a(x){ // OK 4 b = y; 5 c = z; 6 } 7 private: 8 int &a; 9 int b; 10 int c; 11 };
数据成员初始化顺序
数据成员按照他们在类中的声明顺序来初始化,而不是按照在初始化列表中出现的顺序。
1 #include <iostream> 2 3 using namespace std; 4 5 class InitTest{ 6 public: 7 InitTest(const int a, const int b) : x(a),y(b){} 11 private: 12 int x; 13 int y; 14 }; 15 16 int main(int argc, char** argv) 17 { 18 InitTest test(10,20); // test.x = 10, test.y = 20 19 20 return 0; 21 }
1 #include <iostream> 2 3 using namespace std; 4 5 class InitTest{ 6 public: 7 InitTest(const int a, const int b) : y(b),x(a + y){} 8 private: 9 int x; 10 int y; 11 }; 12 13 int main(int argc, char** argv) 14 { 15 InitTest test(10,20); // test.x未初始化, test.y = 20 16 17 return 0; 18 }
!总结:初始化列表中,先声明数据不依赖后声明数据来初始化。