【C++深度剖析教程4】C++的二阶构造模式
今天學習的是C++中的二階構造模式,二階構造模式只是設計模式中的簡單的模式,是一種軟件設計的方法,并沒有我們想象的那么高深,設計模式也是一樣,只不過是一系列的設計方法,只要我們懂得了原理,那么一切都是相通的。
回顧:構造函數的回顧
關于構造函數:
- 類的構造函數用于對象的初始化
- 構造函數與類同名并且沒有返回值
- 構造函數在對象定義時自動被調用
問題:
1.如何判斷構造函數的執行結果?
2.在構造函數中執行return語句會發生什么?
3.構造函數執行結束是否意味著對象構造成功?
下面我們以碼實例來分析問題:
#include <stdio.h>class Test {int mi;int mj; public:Test(int i, int j){mi = i;mj = j;}int getI(){return mi;}int getJ(){return mj;} };int main() { Test t1(1, 2);printf("t1.mi = %d\n", t1.getI());printf("t1.mj = %d\n", t1.getJ());return 0; }這就是一個普普通通的代碼,用來初始化兩個變量的。編譯輸出結果為:
t1.mi = 1 t1.mj = 2現在我在構造函數中加一個return語句如下:
#include <stdio.h>class Test {int mi;int mj; public:Test(int i, int j){mi = i;return;mj = j;}int getI(){return mi;}int getJ(){return mj;} };int main() { Test t1(1, 2);printf("t1.mi = %d\n", t1.getI());printf("t1.mj = %d\n", t1.getJ());return 0; }執行結果為:
t1.mi = 1 t1.mj = 2527220很顯然mj變成了一個隨機數,那么說明構造函數在構造對象t1時,執行到return語句后就返回了,并沒有繼續執行,那么到底是不是這樣的呢?我們來做一個試驗就知道了,添加一個bool型變量來判斷構造函數執行到哪里去了,代碼如下:
#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 語句后構造函數立即結束
從而我們知道,構造函數能決定的只是對象的初始狀態,而不是對象的誕生!!!,上面的代碼我們加了return語句后,t1這個對象就沒有真正的被完全構造,所以不能正常使用這個對象。
這樣的對象,我們叫它:半成品對象.
半成品對象的概念:
-
初始化操作不能按照預期完成二得到的對象
-
半成品對象是合法的C++對象,但是同時它也是Bug的重要來源
一般企業中最難以調試的Bug,一是野指針(后面文章會寫),其次就是這個半成品對象帶來的Bug。
二階構造
那么我們該如何避免這樣的Bug呢?下面就引出二階構造的含義:
- 工程開發中的構造過程可分為
- 資源無關的初始化操作
*不可能出現異常情況的操作 - 需要使用系統資源的操作
*可能出現異常情況,如:內存申請,訪問文件
- 資源無關的初始化操作
二階構造大體流程:
實例代碼如下:
我們來分析一下以上代碼:
二階構造示例:
第一階段構造函數與第二階段構造函數放到private里面了,外部無法調用。
但是在public中,定義的是static 型的NewInstance函數,返回TwoPhaseCons類型的對象,那么通過它就可以調用private里面的構造函數。例如在NewInstance函數里可以有如下代碼: TwoPhaseCons* ret = new TwoPhaseCons();,因為處于NewInstance內部,所以它可以調用構造函數。
通過判斷語句:if( !(ret && ret->construct()) ) 可以判斷兩個階段的構造過程是否都沒有錯誤。
而在main函數中有一句話:TwoPhaseCons* obj = TwoPhaseCons::NewInstance();這是調用NewInstance()函數創建obj 對象,因為構造函數TwoPhaseCons為private類型,所以想創建對象,必須用public中的靜態創建函數:static TwoPhaseCons* NewInstance(); // 對象創建函數而不能像之前那樣直接用構造函數創建對象了如:TwoPhaseCons obj;
上面的程序的運行結果為:
obj = 0x8a0d008
這說明,我們在上面合法的創建看了對象obj。
同時我們也可以看出,用了二階構造模式后,對象只能在堆空間上進行構造而不能在棧空間上構造,這樣好么?答案是肯定的,因為工程上的對象往往是巨大的,一般都會放到堆空間上進行構造。
總結:
- 構造函數只能決定對象的初始化狀態
- 構造函數中初始化操作的失敗不影響對象的誕生
- 初始化不完全的半成品對象是Bug的主要來源
- 二階構造人為的將初始化過程分成兩部分
- 二階構造能夠確保創建的對象都是完整初始化的
想獲得各種學習資源以及交流學習的加我:
qq:1126137994
微信:liu1126137994
可以共同交流關于嵌入式,操作系統,C++語言,C語言,數據結構等技術問題!
總結
以上是生活随笔為你收集整理的【C++深度剖析教程4】C++的二阶构造模式的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 互联网日报 | 蚂蚁集团成立整改工作组;
- 下一篇: s3c2440移植MQTT