第17课 - 对象的构造(上)
0. 问题
对象中成员变量的初始值是什么?
下面的类定义中,成员变量 i 和 j 的初始值是什么? 对象定义在 全局空间、栈上、堆上,具有不同的属性。
1 #include <stdio.h> 2 3 class Test 4 { 5 private: 6 int i; 7 int j; 8 public: 9 int getI() { return i; } // 类成员函数,直接访问 10 int getJ() { return j; } 11 }; 12 13 Test g_test; // 定义全局的对象 14 15 int main(void) 16 { 17 // bss段 18 printf("g_test.getI() = %d ", g_test.getI()); // 0 19 printf("g_test.getI() = %d ", g_test.getJ()); // 0 20 21 // 栈 22 Test test; // 定义对象 23 24 printf("test.getI() = %d ", test.getI()); // 随机值 25 printf("test.getI() = %d ", test.getJ()); // 随机值 26 27 // 堆 28 Test *pt = new Test; 29 printf("pt->getI() = %d ", pt->getI()); // 0 堆空间内的值也是随机的,这里是巧合 30 printf("pt->getI() = %d ", pt->getJ()); // 0 31 32 delete pt; 33 34 return 0; 35 }
1. 对象的初始化
1.1 从程序设计的角度看,对象只是变量,因此:
(1)在栈上创建对象时,成员变量初始化为随机值
(2)在堆上创建对象时,成员变量初始化为随机值
(3)在静态存储区创建对象时,成员变量初始化为0值
1.2 生活中的对象
(1)生活中的对象都是在初始化之后上市的
(2)初始状态(出厂设置)是对象普遍存在的一个状态
(3)问题:程序中如何对一个对象进行初始化?
1.3 对象初始化的初步尝试
(1)一般而言,对象都需要一个确定的初始状态
(2)解决方案:
① 在类中提供一个 public 的 initialize 函数
② 对象创建后立即调用 initialize 函数进行初始化
1 #include <stdio.h> 2 3 class Test 4 { 5 private: 6 int i; 7 int j; 8 9 public: 10 int getI() { return i; } 11 int getJ() { return j; } 12 13 void initialize() 14 { 15 /* int i; 作用域的问题,要看 i 作用域终止的标志 } */ 16 i = 1; 17 j = 2; 18 } 19 20 }; 21 22 Test gt; 23 24 int main() 25 { 26 gt.initialize(); 27 28 printf("gt.i = %d ", gt.getI()); 29 printf("gt.j = %d ", gt.getJ()); 30 31 Test t1; 32 33 //t1.initialize(); 34 35 printf("t1.i = %d ", t1.getI()); 36 printf("t1.j = %d ", t1.getJ()); 37 38 t1.initialize(); 39 40 Test* pt = new Test; 41 42 pt->initialize(); 43 44 printf("pt->i = %d ", pt->getI()); 45 printf("pt->j = %d ", pt->getJ()); 46 47 delete pt; 48 49 return 0; 50 51 }
1.4 存在的问题
(1)initialize 只是一个普通函数,必须显示调用
(2)如果未调用 initialize 函数或调用 initialize 函数的顺序不对,则程序的运行结果是不确定的
2. 构造函数
由上面对 对象初始化 的初步尝试之后,为了解决上述方案的缺点,产生了一个大胆的假设,能不能在创建对象时对其自动进行初始化?
(1)C++ 中可以定义与类名相同的特殊成员函数
(2)这种特殊的成员函数叫做构造函数
① 构造函数没有任何返回类型的声明
② 在定义对象时,构造函数自动被调用,用来初始化对象
1 #include <stdio.h> 2 3 class Test 4 { 5 private: 6 int i; 7 int j; 8 9 public: 10 int getI() { return i; } 11 int getJ() { return j; } 12 13 Test() // 构造函数 14 { 15 printf("Test() Begin "); 16 17 i = 1; 18 j = 2; 19 20 printf("Test() End "); 21 } 22 }; 23 24 Test gt; 25 26 int main() 27 { 28 printf("gt.i = %d ", gt.getI()); 29 printf("gt.j = %d ", gt.getJ()); 30 31 Test t1; 32 33 printf("t1.i = %d ", t1.getI()); 34 printf("t1.j = %d ", t1.getJ()); 35 36 Test* pt = new Test; 37 38 printf("pt->i = %d ", pt->getI()); 39 printf("pt->j = %d ", pt->getJ()); 40 41 delete pt; 42 43 return 0; 44 }
3. 小结
(1)每个对象在使用之前都应该初始化
(2)类的构造函数用于对象的初始化
(3)构造函数与类同名并且没有返回值
(4)构造函数在对象定义时自动被调用