2011-05-28 82 views
0

我有一個稍微噁心的設置,我試圖找出檢修的好方法。保留子類的中心列表,但避免靜態實例

我有一個class Fractal與幾個純虛函數來做工作。每個實例也有一個人類可讀的名字。我想要構建一個所有這些子類的菜單,以便用戶可以在它們之間切換 - 但是,由於懶惰,我不想同時在源文件中定義每個實例,並在另一個實例中再次列出它們。換句話說,我想在運行時動態建立這個子類的列表。

我做了什麼(有工作)至今是:

  • 定義class FractalRegistry這是一個std::map<std::string,Fractal*>(其中鍵是實例名稱)的單封裝,
  • 有基地Fractal構造函數通過名稱向該註冊表註冊每個實例(並且爲了完整性,基地~Fractal註銷它們),
  • 靜態地實例化每個基類(使用其名稱,這是一個構造函數參數)。

所以對於每一個新的分形我寫這樣的事情(轉述):

class SomeFractal : public Fractal { 
    public: 
    SomeFractal(std::string name, std::string desc) : Fractal(name,desc) {} 
    virtual void work_function(...) { ... } 
} 
SomeFractal sf_instance("Some fractal", "This is some fractal or other"); 

和實例添加到由基類構造函數中央列表,所以我並不需要列出它自己。

但是,這會導致靜態實例處於負載狀態,如果將此代碼移動到庫中,這似乎會消失。 (是的,我可以添加一個可怕的空函數每個編譯單元,所以我可以強制將其列入,或訴諸到鏈接弄虛作假如-Wl,--whole-archive,但這些似乎並沒有像正確答案,無論是。)

有更好的方法?我想我正在尋找的是一種編寫這些Fractal實現的方法 - 所有這些實現都有相同的接口,所以我認爲基類的子類將是理想的 - 並且保留並填充它們的中央註冊表,但不會離開我自己是靜態實例的地雷。

我錯過了什麼? 我應該說我已經和C一起工作了很多年,但並沒有真正的C++禪,所以很可能會有這樣的工作能夠做到讓我面對我的工作......(如果我正在編寫這個在C中,我會考慮編寫一個二階宏組合,它既聲明瞭一些函數指針,又用它們和分形的名稱和描述填充了一個表格,但這是一個更重要的事情,它看起來並不像適合C++)

編輯: 我所希望實現的是這使得它容易增加新的分形類型,並自動重新安排我的代碼的一種優雅的方式填充他們的中心名單,但不迫使程序員創建每個分形的靜態實例。

+0

是那些子類應該是這樣的單身?例如,你不希望用戶能夠實例化一個或者你想要什麼?我無法弄清楚。 – Xeo 2011-05-28 23:54:48

+0

我通常會放棄 - 無論使用哪種makefile技巧來構建和鏈接所有單個分形,還能夠爲註冊每個分形的實例的函數生成源代碼。從'main'中調用該函數,或者在庫函數中調用該函數,或者從FractalRegistry的構造函數中調用該函數,或者從執行查找的函數調用該函數(當然,檢查它當前還沒有被調用)。 – 2011-05-28 23:58:19

+0

是否可以以「黑匣子」的形式將2-3行延伸到您的問題(即輸入和結果是什麼)。你的問題不清楚。 – iammilind 2011-05-29 06:02:03

回答

1

回想一下,靜態庫是C++之前的技術,因此它們的實現假設不需要引用的代碼是不合理的(當人們不玩這個特殊技巧時,實際上仍然是C++)。

因此,您需要爲需要它們的每個可執行文件明確指定對象文件,假設您不想探索涉及共享庫,插件等更復雜的方法。這不應該是繁重的:您必須已經有一個進入庫的對象列表,所以不是建立一個庫,而是將該列表添加到可執行文件的鏈接器命令行。

1

在應用程序啓動期間需要創建一些對象來處理分形的註冊。通常,當我需要這樣做時,我創建一個單獨的Registrar類,它處理向工廠註冊類型,並在工廠應該知道的每種類型的cpp文件中創建一個實例。

registrar.h

class Registrar 
{ 
    Registrar(const std::string& name, 
       const std::string& desc, 
       Fractal*(*creator)()) 
    { 
     FractalFactory::register(name, desc, creator); 
    } 
}; 

#define REGISTER_FRACTAL(name, desc, type)     \ 
    namespace {            \ 
     Fractal *create##type() {       \ 
      return new type();        \ 
     }             \ 
     Registrar register##type(name, desc, create##type); \ 
    } 

myfractal.cpp

class MyFractal : public Fractal 
{ 
    // fractal code 
}; 

REGISTER_FRACTAL("MyFractal", "Creates a cool pattern", MyFractal); 
+0

這似乎仍然存在與庫相同的鏈接器問題 - 也就是說,我沒有看到任何強制myfractal.cpp鏈接的東西。 – crazyscot 2011-05-29 12:16:04