• 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)二阶构造能够确保创建的对象都是完整初始化的

  • 相关阅读:
    每天学习算法二
    每天学习算法 一
    数据量基础
    SQL server数据库创建代码,filegroup文件组修改,
    SQL学习笔记之 数据库基础(一)
    Oracle的查询-条件表达式
    Oracle的查询-单行查询
    Oracle 的查询-scott用户介绍
    Oracle的基本操作-序列的使用
    Oracle的基本操作-修改表结构、数据的增删改查
  • 原文地址:https://www.cnblogs.com/liuyueyue/p/13376771.html
Copyright © 2020-2023  润新知