2015-08-27 48 views
1

我有遺留代碼,其中包含許多其他子類作爲數據成員的類。其中大部分內容以不同的輸入讀入子類中的數據成員。它看起來像這樣:初始化主構造函數中的子類 - 主構造函數體與子類構造函數體

MainClass::MainClass(std::string &directory, LogClass &logClass, int mode1, int mode2, int mode3,) : 
    logClass(logClass),                       
    subClass1(directory, logClass, mode1),             
    subClass2(directory, logClass),                                  
    subClass3(logClass, subClass1, subClass2, mode1, mode2), 
    subClass4(logClass, subClass1, subClass2, subClass3, mode1, mode2, mode3), 
{ 
    if(mode2 == 0)       
    { 
     subClass3.init(); 
    } 
    subClass4.init(); 
} 

在一些子類中,初始化發生在其構造函數的主體中。在其他時候,重要數據成員的初始化發生在mainClass的主體中,如subClass3和subClass4的情況所見。

我正在改變這段代碼以包含處理先前讀入數據的轉換的其他子類。其中一些新類需要在構建其他類之前進行初始化。例如,如果我添加subClass5,它可能需要運行subClass4.init()。但是從代碼中可以看出,subClass4.init()不會在構造函數的主體中運行。

這裏有什麼好的政策可以推進?我是否應該將子類構造函數中的所有初始化引出到它們自己的init()函數中,並在主類構造函數中對它們進行正確的排序?或者我應該將所有初始化都移動到子類的構造函數和托盤中並正確地對它們進行排序?

我想弄清楚這個問題最適當的代碼設計。

+0

如果這個例子反映了遺留代碼,我會考慮重構它。每當我看到「模式」參數時,我都覺得應該通過分類來完成,或者 - 最好 - 通過使用策略或類似的模式。 – Jens

回答

0

它取決於語義init()函數。他們在做什麼?他們的構造函數是做什麼的?爲什麼兩個不同的函數(構造函數和init)用於初始化?

在我見過的很多代碼中,通常init的函數主要是由於其實現者的懶惰。他們做的屬於從構造函數,從C++的角度來看。

在另一方面,如果init()職能被用來執行的東西,是從對象構造語義不相交(例如,啓動計時器,觸發一些事件,...),也許這是件好事,他們是不相交構造函數。在這種情況下,我會改變他們的名字。

0

init()這樣的方法有助於將初始化過程委託給以後的時間,因此允許快速啓動,因爲構造函數不需要花太多時間去做init()。如果這些init方法執行代價高昂的操作,如使用密集型CPU週期或獲取昂貴的資源,則情況尤其如此。另一方面,如果你施加這樣的協議,那麼任何添加subClassX的人都必須通過調用子類的構造函數來確保正確的初始化,然後在這些子類上調用init

這個選擇完全屬於你,因爲兩種方法都有一些優點和缺點。如果你發現更多的優點而不是缺點,那就去吧!

P.S.當然,這假定構造函數足夠讓子類實例進入最小可用狀態。

+0

如果您需要在使用該對象之前調用init,它將創建一個不變量不成立的無效對象。出於性能的原因,您可以在需要時實例化對象,然後讓構造函數運行,或者使用(unique_)指針作爲成員並懶惰地創建它。 – Jens

+0

什麼是*最小可用狀態*?如果一個對象的初始化非常耗時,你可能想在另一個線程上執行它,但是資源獲取是初始化的...... –

+0

我看到了你的獨特的指針方法和惰性初始化,但是如果構造函數可以讓事情在啓動時進行,委託昂貴的'init'通常被廣泛使用的想法。例如:GUI對象渴望獲取一些位圖。這可以有效地委託給以後的時間點。 – Arun

0

構造函數應該始終建立類的不變量,不多或少。我強烈認爲,一個在施工後處於無效狀態並且必須用init()調用進行初始化的類是不合格的。

爲了測試的目的,我會考慮將子部件的構造從類中移出並提供給構造函數,或者爲它們中的每一個提供工廠。這使您可以爲子部件創建模擬,並對單元測試非常有用。