2015-10-19 76 views
4

假設我定義了一個類Foo,它沒有實現默認的構造函數。 另外,我有一個類Bar,它「擁有」的Foo一個實例:如何正確初始化非默認構造類成員?

class Foo() { 
    private: 
    int m_member; 
    public: 
    Foo(int value) : m_member(value) { } 
}; 

class Bar() { 
    private: 
    Foo m_foo; 
    public: 
    Bar(/* ... */) { 
     int something; 
     /* lots of code to determine 'something' */ 
     /* should initialize m_foo to 'Foo(something)' here */ 
    } 
}; 

如圖所示將不會運行的代碼,因爲Bar試圖調用的Foo默認構造函數。

現在我想要做的是讓Bar的構造函數首先確定something,然後將結果傳遞給Foo的構造函數。

解決此問題的一種方法是讓Bar僅擁有指向Foo的引用/指針,並在確定m_something後對其進行初始化。但是,我想避免這樣做,以明確m_foo的使用期限完全取決於擁有班級的生命週期。

另一種方法是在Foo中實現默認構造函數,並稍後設置值,這也是我也想避免的,因爲Foo的任何實例都應該具有有效的成員值(任何時候)。

實現此目的的正確方法是什麼?我堅持在這裏參考/指針?

回答

12

最好的想法是創建幫助函數,它將計算出一些內容,然後在構造函數初始化列表中初始化m_foo

class Bar { 
    private: 
    Foo m_foo; 
    public: 
    Bar(/* ... */) : m_foo(calculate_something()) { 
    } 
private: 
    static int calculate_something() 
    { 
     int something = 0; 
     // lot of code to calculate something 
     return something; 
    } 
}; 
+0

感謝您的回答。我也考慮過這樣做,但是在這種情況下,我必須將'Bar'的大部分初始化操作移到幫助函數中,因爲'something'依賴於此。 – madmax1

+1

@ madmax1不好。然後,只需要獨立計算一些東西,或者使用你的一個想法(指針或默認的可構造的'Foo')。 – ForEveR

2

這是否複雜的初始化代碼實際上屬於Bar?考慮讓一個分開類來完成初始化可能是一件好事。像

class Bar { 
    public: 
    Bar(int param, Foo foo): m_foo(foo) { 
     // do just some very simple calculations, or use only constructor initialization list 
    } 
    ... 
} 

class BarBuilder { 
    public: 
    BarBuilder(/*...*/) { 
     // do all calculations, boiling down to a few parameters for Bar and Foo 
     Foo foo(fooParameter); 
     m_result = new Bar(barParameter, foo); // give Foo here explicitly 
    } 
    Bar getResult() { return *m_result; } 
    private: 
    Bar* m_result; // or better use unique_ptr 
} 

這樣的東西也開闢了道路,可能是在情況下很有用,例如,你並不總是需要所有的複雜計算全Builder模式。

這裏假定所有的類都是可複製構建的,但是你可以或多或少的輕鬆修改它以支持你所需要的東西。

相關問題