第20课 - 初始化列表的使用
0. 问题
类中是否可以定义 const 成员?
下面的类定义是否合法?如果合法,ci 的值是什么,存储在哪里?
1 class Test 2 { 3 private: 4 const int ci; 5 public: 6 int getCI() { return ci;} 7 };
1 #include <stdio.h> 2 3 class Test 4 { 5 private: 6 const int ci; 7 public: 8 Test() 9 { 10 ci = 10; 11 } 12 int getCI() 13 { 14 return ci; 15 } 16 }; 17 18 19 int main() 20 { 21 Test t; 22 23 printf("t.ci = %d ", t.getCI()); 24 25 return 0; 26 }
在C中:const 修饰的变量必须在定义的时候进行初始化,不能在定义之后对其进行赋值操作,违背了const 的含义。
在C++中:构造函数内部是对成员变量进行赋值操作,而不是初始化。初始化需要初始化列表。
1. 类成员的初始化
(1)C++ 中提供了初始化列表,可以对成员变量进行初始化
(2)语法规则:
ClassName::ClassName():m1(v1), m2(v2,v3),m3(v3) { //其它初始化操作 }
1 // 构造函数是对变量进行赋值操作,初始化列表是进行初始化操作,两个是不同的概念 2 3 #include <stdio.h> 4 5 class Test 6 { 7 private: 8 int i; 9 int j; 10 const int k; 11 public: 12 int getI() 13 { 14 return i; 15 } 16 int getJ() 17 { 18 return j; 19 } 20 int getK() 21 { 22 return k; 23 } 24 25 Test() : k(10) 26 { 27 printf("invoke consttuctor! "); 28 i = 1; 29 j = 2; 30 } 31 }; 32 33 int main(void) 34 { 35 Test t1; 36 37 printf("t1.getI() = %d, t1.getJ() = %d, t1.getK() = %d ", t1.getI(), t1.getJ(), t1.getK()); 38 39 return 0; 40 }
(3)注意事项
① 成员的初始化顺序与成员的声明顺序相同,而与初始化列表中的位置无关
② 初始化列表先于构造函数的函数体执行
1 #include <stdio.h> 2 3 class value 4 { 5 private: 6 int m_i; 7 public: 8 value(int val) : m_i(100) 9 { 10 printf("in value! "); 11 printf("m_i = %d ", m_i); 12 m_i = val; 13 } 14 15 int getM_i() 16 { 17 return m_i; 18 } 19 }; 20 21 class Test 22 { 23 private: 24 value m1; 25 value m2; 26 public: 27 Test() : m1(1), m2(2) // 初始化列表,对m1, m2进行初始化。初始化还是调用value类中的构造函数,但还是先执行value中的初始化列表 28 { 29 printf("in Test! "); 30 } 31 32 int get() 33 { 34 return m1.getM_i(); 35 } 36 }; 37 38 int main(void) 39 { 40 Test t1; 41 42 printf("t1.get() = %d ", t1.get()); 43 44 return 0; 45 }
2. 类中的 const 成员
(1)类中的 const 成员会被分配空间,局部对象会分配栈空间、动态对象会分配堆空间、全局对象会分配静态存储空间(和const int i; 不同)
(2)类中的 const 成员的本质是只读变量,可以通过指针隐式的修改。编译器无法直接得到 const 成员的初始值,因此无法进入符号表成为真正意义上的常量
(3)类中的 const 成员只能在初始化列表中指定初始值
1 #include <stdio.h> 2 3 class Value 4 { 5 private: 6 int mi; 7 public: 8 Value(int i) 9 { 10 printf("i = %d ", i); 11 mi = i; 12 } 13 14 int getI() 15 { 16 return mi; 17 } 18 }; 19 20 class Test 21 { 22 private: 23 const int ci; 24 Value m2; 25 Value m3; 26 Value m1; 27 public: 28 Test() : m1(1), m2(2), m3(3), ci(100) // 成员变量的初始化 29 { 30 printf("Test::Test() "); 31 } 32 33 int getCI() 34 { 35 return ci; 36 } 37 38 int setCI(int v) 39 { 40 // 说明ci是个只读变量,可以通过指针修改内存值 41 int* p = const_cast<int*>(&ci); 42 *p = v; 43 } 44 }; 45 46 int main() 47 { 48 Test t; 49 50 printf("t.ci = %d ", t.getCI()); 51 52 t.setCI(10); 53 54 printf("t.ci = %d ", t.getCI()); 55 56 return 0; 57 }
【小插曲】初始化与赋值不同
(1)初始化:对正在创建的对象进行初值设置
(2)赋值: 对已经存在的对象进行值设置
3. 小结
(1)类中可以使用初始化列表对成员进行初始化
(2)初始化列表先于构造函数体执行
(3)类中可以定义 const 成员变量
(4)const 成员变量必须在初始化列表中指定初始值
(5)const 成员变量为只读变量