您可以让您的所有课程在某种集合中自行注册。这是一个骨架方法:
基础.hpp:
#include <memory>
#include <unordered_map>
#include <string>
struct Base
{
virtual ~Base() = default;
using create_f = std::unique_ptr<Base>();
static void registrate(std::string const & name, create_f * fp)
{
registry()[name] = fp;
}
static std::unique_ptr<Base> instantiate(std::string const & name)
{
auto it = registry().find(name);
return it == registry().end() ? nullptr : (it->second)();
}
template <typename D>
struct Registrar
{
explicit Registrar(std::string const & name)
{
Base::registrate(name, &D::create);
}
// make non-copyable, etc.
};
private:
static std::unordered_map<std::string, create_f *> & registry();
};
基础.cpp:
#include "Base.hpp"
std::unordered_map<std::string, Base::create_f *> & Base::registry()
{
static std::unordered_map<std::string, Base::create_f *> impl;
return impl;
}
现在在客户端中使用它:
派生的.hpp:
#include "Base.hpp"
struct Derived : Base
{
static std::unique_ptr<Base> create() { return std::make_unique<Derived>(); }
// ...
};
派生的.cpp:
#include "Derived.hpp"
namespace
{
Base::Registrar<Derived> registrar("MyClass");
}
的构造函数负责在 name 下Base::Registrar<Derived>
注册类。您可以通过以下方式动态创建实例:Derived
"MyClass"
Derived
std::unique_ptr<Base> p = Base::instantiate("MyClass");
可以/应该通过检测重复注册、打印可用类列表等来改进代码。注意我们如何避免任何静态初始化排序问题,我将实际的注册表映射对象设为块静态对象,保证在之前初始化它的第一次使用,因此只有在最后一次使用后才被销毁。