2011-05-28 53 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