1. 程式人生 > >C++二階構造

C++二階構造

轉載:原文地址 https://blog.csdn.net/qq_20233867/article/details/79155817


1 建構函式的回顧

  • 關於建構函式:
    • 類的建構函式用於物件的初始化;
    • 建構函式與類同名並且沒有返回值;
    • 建構函式在物件定義時自動被呼叫。

2 問題

1.如何判斷建構函式的執行結果?(目前無法判斷)
2.在建構函式中執行return語句會發生什麼?(建構函式直接 返回,執行結束)
3.建構函式執行結束是否意味著物件構造成功?(不)

程式設計實驗:異常的建構函式

#include <stdio.h>

class Test
{
    int mi;
    int mj;
    bool mStatus;
public:
    Test(int i, int j) : mStatus(false)
    {
        mi = i;

        return;

        mj = j;

        mStatus = true;
    }
    int getI()
    {
        return mi;
    }
    int getJ()
    {
        return
mj; } int status() { return mStatus; } }; int main() { Test t1(1, 2); if( t1.status() ) { printf("t1.mi = %d\n", t1.getI()); printf("t1.mj = %d\n", t1.getJ()); } return 0; }

    3 你該知道的真相

    • 建構函式:
      • 只提供自動化初始化成員變數的機會;
      • 不能保證初始化邏輯一定成功;
      • 執行return語句後建構函式立即結束。

    真相的意義:建構函式能決定的只是物件的初始狀態,而不是物件的誕生!!

    4 半成品物件

    • 半成品物件的概念:
      • 初始化操作不能按照預期完成而得到的物件;
      • 半成品物件是合法C++物件,也是bug的重要來源。

    5 二階構造

    工程開發中的構造可分為:

    • 資源無關的初始化操作

    • 不可能出現異常情況的操作。
  • 需要使用系統資源的操作

    • 可能出現異常情況,如:記憶體申請,訪問檔案。

    這裡寫圖片描述

    這裡寫圖片描述

    這裡寫圖片描述

    程式設計實驗:二階構造初探

    #include <stdio.h>
    
    class TwoPhaseCons 
    {
    private:
        TwoPhaseCons() // 第一階段建構函式
        {   
        }
        bool construct() // 第二階段建構函式
        { 
            return true; 
        }
    public:
        static TwoPhaseCons* NewInstance(); // 物件建立函式
    };
    
    TwoPhaseCons* TwoPhaseCons::NewInstance() 
    {
        TwoPhaseCons* ret = new TwoPhaseCons();
    
        // 若第二階段構造失敗,返回 NULL    
        if( !(ret && ret->construct()) ) 
        {
            delete ret;
            ret = NULL;
        }
    
        return ret;
    }
    
    
    int main()
    {
        TwoPhaseCons* obj = TwoPhaseCons::NewInstance();
    
        printf("obj = %p\n", obj);
    
        delete obj;
    
        return 0;
    }
    

    程式設計實驗:陣列類的加強

    IntArray.h

    #ifndef _INTARRAY_H_
    #define _INTARRAY_H_
    
    class IntArray
    {
    private:
        int m_length;
        int* m_pointer;
    
        IntArray(int len);
        IntArray(const IntArray& obj);
        bool construct();
    public:
        static IntArray* NewInstance(int length); 
        int length();
        bool get(int index, int& value);
        bool set(int index ,int value);
        ~IntArray();
    };
    
    #endif
    
      

      IntArray.cpp

      #include "IntArray.h"
      
      IntArray::IntArray(int len)
      {
          m_length = len;
      }
      
      bool IntArray::construct()
      {
          bool ret = true;
      
          m_pointer = new int[m_length];
      
          if( m_pointer )
          {
              for(int i=0; i<m_length; i++)
              {
                  m_pointer[i] = 0;
              }
          }
          else
          {
              ret = false;
          }
      
          return ret;
      }
      
      IntArray* IntArray::NewInstance(int length) 
      {
          IntArray* ret = new IntArray(length);
      
          if( !(ret && ret->construct()) ) 
          {
              delete ret;
              ret = 0;
          }
      
          return ret;
      }
      
      int IntArray::length()
      {
          return m_length;
      }
      
      bool IntArray::get(int index, int& value)
      {
          bool ret = (0 <= index) && (index < length());
      
          if( ret )
          {
              value = m_pointer[index];
          }
      
          return ret;
      }
      
      bool IntArray::set(int index, int value)
      {
          bool ret = (0 <= index) && (index < length());
      
          if( ret )
          {
              m_pointer[index] = value;
          }
      
          return ret;
      }
      
      IntArray::~IntArray()
      {
          delete[]m_pointer;
      }
      
        

        main.cpp

        #include <stdio.h>
        #include "IntArray.h"
        
        int main()
        {
            IntArray* a = IntArray::NewInstance(5);    
        
            printf("a.length = %d\n", a->length());
        
            a->set(0, 1);
        
            for(int i=0; i<a->length(); i++)
            {
                int v = 0;
        
                a->get(i, v);
        
                printf("a[%d] = %d\n", i, v);
            }
        
            delete a;
        
            return 0;
        }
        
          

          小結

          • 建構函式只能決定物件的初始化狀態;
          • 建構函式中初始化操作的失敗不影響物件的誕生;
          • 初始化不完全的半成品物件是bug的重要來源;
          • 二階構造人為的將初始化過程分為兩部分;
          • 二階構造能夠確保建立的物件都是完整初始化的。