2017-03-14 46 views
1

我的項目使用自注冊類有兩種方式:一種是實現工廠模式,它允許迭代這些類的映射,其實現幾乎完全類似於C++ how safe are self registering classes?中描述的實現;另一種是將巨大的開關語句分離成對象圖。在後一種情況下,我剛剛創建了一個基類和一組派生類,然後我在源文件中用靜態對象實例化了每個派生類,而類的構造函數將自己註冊到一個映射中。替代自注冊類

現在我試圖將我的應用的邏輯部分移動到靜態庫中,並在兩個子項目中使用這個庫(我使用Qt,Qt Creator和gcc)。這樣做之後,除非我在某處明確地實例化這些類,否則上述類都不起作用。

所以,我正在尋找任何解決方法。實際上,另一個問題正在出現:使用自注冊技術在C++中設計應用程序是否是一個非常不好的內容?

編輯:我被要求舉一個例子。這裏被簡化代碼:

// Class for storing actions 
class ActionBase; 
class SomeObject;  
class ActionMap 
{ 
    public: 
    ActionMap(); 
    static void registerAction(int n, ActionBase* action) {} 
    void performAction (SomeObject* object, int action) { 
     m_actions[action]->perform(object); 
    } 

private: 
    std::map<int, ActionBase*> m_actions; 
}; 

// Action class - action.h 
#include "actionmap.h" 
class SomeObject; 
class ActionBase 
{ 
public: 
    ActionBase(int n, ActionBase* action) {ActionMap::registerAction(n, action); } 
    virtual ~ActionBase() = 0; 
    virtual void perform(SomeObject* object) = 0; 
}; 

template<int N> 
class Action : public ActionBase 
{ 
public: 
    Action() : ActionBase(N, this) {} 
}; 

template<> 
class Action<1> : public ActionBase 
{ 
public: 
    Action() : ActionBase(1, this) {} 
    void perform(SomeObject* object) 
    { 
     // Do something 
    } 
}; 

我現在可以創建行動的源文件中的一些操作對象,是這樣的:

// action.cpp 
// #include "action.h" 
static Action<1> action1; 

重組項目之後,我要在我的子項目某處創建動作1變量明確地可以使用它,例如在main.cpp中。

更新:似乎Angew幫助我部分解決了第二個問題。我已經刪除了一個免費的空函數,並在action.cpp中定義了它。在應用程序中的某處調用強制執行操作對象的初始化。

+0

_「上述任何類都不起作用,除非您需要更多地解釋這一點並嘗試包含[MCVE] –

+0

@RichardCritten,這很可能是鏈接器刪除包含註冊實例的目標文件,因爲沒有人引用它。如果你問我,破壞行爲,但我們在這裏。 – Quentin

+0

@Quentin不一定。不要忘記,在C++中,文件範圍變量只能保證在執行該文件的任何代碼之前被初始化,但是它們可以在'main'啓動後被初始化。 – Angew

回答

2

使用自注冊技術在C++中設計應用程序是一個非常不好的內涵嗎?

恐怕我必須回答「是」這個。在main已經啓動後,C++顯式允許非本地變量被初始化;唯一的限制是它們必須在定義它們的文件的任何代碼被執行之前被初始化。引用C++ 14(N4140)[basic.start.init] 3.6.3/4:

它是實現定義是否非本地變量具有靜態存儲的動態初始化 持續時間之前完成第一個陳述main。如果初始化延遲到main的第一個語句之後的某個時間點 ,則它應在與初始化變量相同的翻譯單元中定義的任何函數或變量 的第一個odr-use(3.2)之前出現。

換句話說,在初始化做一些註冊的文件中定義的全局變量可能不會被初始化(並因此被註冊),直到調用該文件的其他代碼爲止。