2011-10-20 112 views
1

假設我需要在我的構造函數初始化任何成員變量之前調用一個空閒的GlobalInitializer()。例如:C++重構:初始化在構造函數中排序

class Foo { 
    public: 
    Foo() : bar_() 
    { 
     // calling GlobalInitializer() here is too late 
    } 
    Bar bar_; 
}; 

在Foo中調用GlobalInitializer()已經太晚了,因爲我需要在bar_初始化之前調用它。我哈克解決有關此已經創造超一流:

class MyInitializer { 
    protected: 
    MyInitializer() { 
     GlobalInitializer(); 
    } 
}; 
class UglyFoo : public MyInitializer 
{ 
    public: 
    UglyFoo() : bar_() 
    { } 
    Bar bar_; 
}; 

UglyFoo幹得不錯,但它需要這種醜陋MyInitializer類。是否有更清晰的設計模式或重構來達到相同的效果?

附加說明:除非用戶實例化Foo(),GlobalInitializer()是一個昂貴的調用,我想避免。 GlobalInitializer()中有多個警戒對多個呼叫。此外,可能還有其他類,比如說FooBar,它也需要調用GlobalInitializer(),但是在一個進程中,GlobalInitializer()實際上只會執行一次(如果Foo或FooBar被實例​​化),或者甚至不會執行一次(如果沒有Foo或FooBar的實例化)。

+3

名字'GlobalInitializer'表明,它僅需要調用一次,而不是每次都Foo'的'一個實例創建。那是對的嗎? –

+0

我想我可能在那裏選擇了一個壞名字 - 它只需要被調用一次,但只有創建Foo()的實例時(GlobalInitializer內部有多個警戒對多個調用)。這是我希望從Foo的用戶那裏得到的實現細節。 – kfmfe04

回答

4
class Foo { 
private: 
    struct Initializer { 
     Initializer() { GlobalInitializer(); } 
    }; 
    Initializer initializer__; // declare before bar__ to ensure it is constructed first 

public: 
    Foo() : bar_() 
    { 
    } 

    Bar bar_; 
}; 
+1

其實你的情況更糟,因爲它已經壞了。至少這個工程(除了清晰你可能已經明確地將'initializer__'添加到成員初始化列表中)。 – David

0

你正在做的事似乎違反了面向對象的值,因爲你的類不合理地依賴於他們之外的東西;我會建議重新設計你的類,以避免這種情況。這就是說,一個適合你的設計模型而不需要讓每個類繼承另一個類的選項就是創建MyInitializer類作爲單例對象,並將MyInitializer添加到依賴於此初始化的每個類。單例只會在第一次實例化時執行初始化。

+1

通過建議使用單身人士,您可以用另一個不好的設計修復一個不好的設計。 –

+0

@BjörnPollex是的,我絕對同意。這就是爲什麼我建議他先重新設計他的班級依賴關係......但是我直接回答他的問題,不管我的意見與你的意見一致。 – mah

0

大概你可以重構任何GlobalInitializer初始化不再是全球性的。然後,你的選擇就打開如何給你的班級提供數據。你知道,因爲globals are bad和所有。

1

您應該重新考慮您的設計。

好的設計意味着loose-coupling。如果你的對象創建依賴於不同的方法調用來工作,那麼存在嚴重錯誤。

如果你確實需要這個,你應該在bar_的構造函數中調用GlobalInitializer,但最好的方法是重新考慮你的設計。

0

碰上了我的一個夢想:改變bar_爲指針:

class Foo { 
    public: 
    Foo() 
    { 
     GlobalInitializer(); 
     // now we can call GlobalInitializer() in time 
     bar_ = new Bar; 
    } 
    ~Foo() 
    { 
     delete bar_; 
    } 

    private: 
    Bar* bar_; 
};