1. 程式人生 > >C++解析(15):二階構造模式

C++解析(15):二階構造模式

0.目錄

1.建構函式與半成品物件

2.二階構造

3.小結

1.建構函式與半成品物件

關於建構函式:

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

問題:

  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;
}

輸出結果為空。

建構函式:

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

建構函式能決定的只是物件的初始狀態而不是物件的誕生!!

半成品物件的概念:

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

2.二階構造

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

  • 資源無關的初始化操作
    1. 不可能出現異常情況的操作
  • 需要使用系統資源的操作
    1. 可能出現異常情況,如:記憶體申請,訪問檔案

二階構造:

二階構造示例一:

二階構造示例二:

示例程式碼:

#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;
}

執行結果為:

[[email protected] Desktop]# g++ test.cpp
[[email protected] Desktop]# ./a.out 
obj = 0xd4f010

若是二階構造失敗了呢?

#include <stdio.h>

class TwoPhaseCons 
{
private:
    TwoPhaseCons() // 第一階段建構函式
    {   
    }
    bool construct() // 第二階段建構函式
    { 
        return false; 
    }
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;
}

執行結果為:

[[email protected] Desktop]# g++ test.cpp
[[email protected] Desktop]# ./a.out 
obj = (nil)

會返回一個空。

使用二階構造模式後,物件只能在堆空間上建立,不能在棧上產生了。這恰恰是工程裡面最重要的一個決定,因為在工程中,物件往往是比較巨大的,不適合放在棧空間當中,都應該放到堆空間裡面去。

3.小結

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