27,二阶构造模式(构造函数二阶构造)------对象初始化

模式------------即方法

1. 构造函数的回顾

(1)关于构造函数

  ①类的构造函数用于对象的初始化

  ②构造函数类同名并且没有返回值(思考:无返回值如何判断构造函数的执行结果?)

  ③构造函数对象定义自动被调用

问题:

 1,如何判断构造函数的执行结果?  ---普通函数可以返回值

2,构造函数中执行return会发生什么?------普通函数立即返回,后面的函数不执行

3,构造函数执行结束是否意味着对象构造成功?-------

编程实验以上问题:

 1 #include<stdio.h> 
 2 /*   1,没有办法判断构造函数的执行结果
 3      2,构造函数中执行return会发生什么?构造函数执行之后,不意味着对象构造成功
 4 */
 5 // 模式即方法
 6 class Test
 7 {
 8     int mi;
 9     int mj;
10 
11 public:
12 
13     Test(int i, int j)    //1,构造函数中执行return会发生什么? 
14     {                     //答:直接返回,Test t1(1,2)有问题,初始状态有问题,没有影响构造函数的诞生,只是不能知道t1能不能用
15                           //所以没有办法判断构造函数的执行结果
16         mi = i;
17 
18         return;           
19 
20         mj = j;              //这行代码没有执行--------mj变为随机数,mj成员未完成初始化
21     }
22 
23     int getI()
24     {
25         return mi;
26     }
27 
28     int getJ()
29     {
30         return mj;
31     }
32 };
33 
34 int main()
35 {
36     Test t1(1,2);
37 
38     printf("t1.mi=%d
",t1.getI());    //1
39     printf("t1.mj=%d
", t1.getJ());   //5689365
40 
41     return 0;
42 }

回答:构造函数的真相

  ①构造函数只提供自动初始化成员变量的机会,但不能保证初始化逻辑一定成功只能决定对象的初始状态,而不是对象的诞生

  ②构造函数执行return语句后,构造函数执行结束,但是不意味着对象构造成功。

那么怎么解决?????

 1 #include<stdio.h> 
 2 /*  
 3     判断对象构造是否成功------方案:类中增加成员-mStatus-----强行让构造函数有个返回值mStatus
 4     */
 5 //           模式即方法
 6 class Test
 7 {
 8     int mi;
 9     int mj;
10 
11     bool mStatus;   //成员变量记录类的初始状态
12 
13 public:
14     Test(int i, int j)  : mStatus(false)   //类的成员变量mStatus的初始化
15     {
16         mi = i;
17 
18         return;                              //mj变为随机数,mj成员未完成初始化
19 
20         mj = j;
21 
22         mStatus = true;                 //对象构造成功,mStatus返回true
23     }
24     int getI()
25     {
26         return mi;
27     }
28     int getJ()
29     {
30         return mj;
31     }
32 
33     int status()  //功能函数
34     {
35         return mStatus;
36     }
37 };
38 
39 int main()
40 {
41     Test t1(1, 2);
42 
43     if (t1.status())//构造未完成,status为false
44     {
45         printf("t1.mi=%d
", t1.getI());//i被正确初始化
46         printf("t1.mj=%d
", t1.getJ());//j为随机值
47     }
48     return 0;
49 }

2. 半成品对象

(1)初始化操作不能按照预期完成得到的对象

(2)半成品对象合法C++对象也是bug的重要来源

段错误:指访问的内存超出了系统给这个程序所设定的内存空间,例如访问了不存在的内存地址、访问了系统保护的内存地址(比如0地址)、访问了只读的内存地址等等情况。

内存申请不成功,产生段错误,但是有的错误只产生一次,该怎么解决这种问题???

人为的将构造分为两步

3. 二阶构造---(用于杜绝半成品对象)

(1)工程开发中的构造过程

  ①资源无关的初始化操作阶段

      ----------不会出现异常情况的操作(比如将成员变量的值设置为初始值)

  ②需要使用系统资源的操作      

      -------可能出现异常,如内存申请(堆空间),访问文件等。

二阶构造,对象只在堆空间产生,不能在栈上产生,往往实际工程对象是非常大的,不适合放在栈空间(栈空间有限)

     

为什么要用对象创建函数???

 因为构造函数是Private外界不能调用,所以要通过对象创建函数(stati 静态成员函数内部可以访问类的私有成员
 static TwoPhaseCons* NewInstance();      //对象创建函数 -----------返回对象指针

实例:

 1 #include<stdio.h> 
 2 
 3 
 4 
 5 class TwoPhaseCons
 6 {
 7 private:
 8     TwoPhaseCons()        //第一阶段构造函(简单的赋值操作)            c++构造函数可以担任二阶构造的一阶构造函数
 9     {
10     }
11     bool construct()      //第二阶段构造函数(系统资源申请,打开文件,网络)                普通成员函数
12     {
13         return true;
14     }
15 public:
16                                             //构造函数时Private外界不能调用,通过对象创建函数(静态成员函数内部可以访问类的私有成员函数)
17    static TwoPhaseCons* NewInstance();      //对象创建函数 ----------- 返回对象指针
18                                                                                                   
19 };
20 
21 //对象创建函数实现
22 TwoPhaseCons* TwoPhaseCons::NewInstance()           
23 {
24     TwoPhaseCons* ret = new TwoPhaseCons();     //堆空间创建对象,调用构造函数----执行第一阶段构造--(静态成员函数内部可以访问类的私有成员)
25                                                                                                
26      
27     //r若第二阶段构造失败,返回NULL
28     if (!(ret && ret->construct()))             //construct----进行资源申请-------执行二阶构造
29     {
30         delete ret;                              //删除半成品对象
31         ret = NULL;
32     }
33 
34     return ret;                                //返回对象,资源申请成功-----合法对象NewInstance()申请成功
35 }
36 
37 int main() 
38 {
39    // TwoPhaseCons obj;                           //error  
40 
41   //  TwoPhaseCons* obj =new NewInstance();       //error 触发构造函数自动调用,但是构造函数是私有的,不能在外部main()自动调用,只能调用创建函数
42 
43      TwoPhaseCons* obj= TwoPhaseCons::NewInstance();   //只能调用静态创建函数-----因为要调用私有的构造函数,所以必须定义静态创建函数,实现在类的外部(mian)调用
44 
45     printf("obj=%p
",obj);                            //可以得到合法可用的对象----位于堆空间
46 
47     return 0;
48 }

【编程实验】数组类的加强   IntArray

//IntArray.h

 1 #ifndef  _INTARRAY_H
 2 #define  _INTARRAY_H
 3 
 4 class IntArray
 5 {
 6 private:
 7     int m_length;                           //数组长度
 8     int* m_pointer;                         //数组数据
 9 
10     IntArray(int len);                       //一阶构造
11     IntArray(const IntArray& obj);           //一阶构造        
12     bool construct();                        //实现第二阶段的构造
13 
14 public:
15     static IntArray* NewInstance(int length);     //对象创建函数
16 
17     int length();                                  //获取数组长度                                            
18     bool get(int index, int& value);              //获取对应位置的数组元素值
19     bool set(int index, int value);               //设置对应位置的数组元素为参数value
20     void free();
21 };
22 
23 #endif
24  

////IntArray.cpp

 1 #include"IntArray.h"
 2 
 3 //第一阶段存放不存在错误的操作
 4 //可能失败的操作放在第二阶段
 5 
 6 IntArray :: IntArray(int len)         //作用域分辨符::
 7 {
 8     m_length = len;
 9 }
10 
11 bool IntArray::construct()             //构造函数
12 {
13     bool ret = true;
14      
15     m_pointer = new int[m_length];      //数据指针指向堆空间里的一段内存:数组作用,保存整形数组
16     
17     if (m_pointer)                      // 要判断内存是否申请成功
18      {
19         for (int i = 0; i < m_length; i++)    //将数组所有值设置为0
20         {
21             m_pointer[i] = 0;
22         }
23     }
24     else
25     {
26         ret = false;
27     }
28     return ret;
29 }
30 
31 int IntArray :: length()
32 {
33     return m_length;
34 }
35 
36 bool IntArray :: get(int index, int& value)    //安全性体现----得到对应位置的数组元素值 ---index为指定位置
37 {
38     bool ret = (0 <= index) && (index <= length());     
39 
40     if (ret)
41     {
42         value = m_pointer[index];              //通过引用返回值
43     } 
44 
45     return ret;
46 }
47 
48 IntArray* IntArray::NewInstance(int length)       ///对象创建函数
49 {
50     IntArray* ret = new IntArray(length);
51    
52     //r若第二阶段构造失败,返回NULL
53     if (!(ret && ret->construct()))
54     {
55         delete ret;
56         ret = 0;
57     }
58 
59     return ret;
60 }
61 
62 
63 bool IntArray :: set(int index, int value)             //设置对应位置的数组元素为参数value
64 {
65     bool ret = (0 <= index) && (index <= length());
66     if (ret)
67     {
68         m_pointer[index]=value;                      //数组成员重新赋值
69     }
70     return ret;
71 }
72 
73 void IntArray::free()
74 {
75     delete[] m_pointer;       //释放堆空间
76 }

//main.c

 1 #include<stdio.h>
 2 #include "IntArray.h"
 3 
 4 
 5 int main() {
 6     
 7         
 8 //调用创建函数
 9     IntArray* a = IntArray::NewInstance(5);
10     printf("a.length=%d
",a->length());
11 
12     a->set(0, 1);
13 
14     for (int i = 0; i <a->length() ; i++)                                          
15     {
16         int v = 0;
17 
18         a->get(i, v);
19 
20         printf("a[%d]=%d
",i,v);
21     }
22 
23 
24     return 0;
25 }

4. 小结

(1)构造函数只能决定对象初始化状态

(2)构造函数初始化操作的失败不影响对象的诞生

(3)初始化不完全半成品对象bug的重要来源

(4)二阶构造人为的将初始化过程分为两个部分

(5)二阶构造能够确保创建的对象都是完整初始化的

原文地址:https://www.cnblogs.com/liuyueyue/p/13376771.html