在 C++ 中可能吗?循环抽象类的所有子类?

发布于 2024-10-27 05:15:02 字数 165 浏览 1 评论 0原文

我有一个带有几个子类的 C++ 抽象类。

是否可以通过宏或模板元编程以某种方式执行类似的操作:

foreach subclass of Base:
  mymap[subclass::SOME_CONSTANT] = new subclass();

I have an abstract class in C++ with several subclasses.

Is it somehow by Macros or template metaprogramming possible to do something like that:

foreach subclass of Base:
  mymap[subclass::SOME_CONSTANT] = new subclass();

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

萌化 2024-11-03 05:15:02

不,你不能。

显然,您想要的是一个工厂(或者可能是抽象工厂)。

在 C++ 中,您设置一个工厂类并注册构建器。

class FooFactory
{
public:
  typedef std::function<Foo*()> Builder;

  /// returns true if the registration succeeded, false otherwise
  bool Register(std::string const& key, Builder const& builder) {
    return map.insert(std::make_pair(key, builder)).second;
  }

  /// returns a pointer to a new instance of Foo (or a derived class)
  /// if the key was found, 0 otherwise
  Foo* Build(std::string const& key) const {
    auto it = _map.find(key);
    if (it == _map.end()) { return 0; } // no such key
    return (it->second)();
  }

private:
  std::map<std::string, Builder> _map;
};

您可以创建该工厂的单例,以在库加载期间注册派生类,这对于类似插件的架构非常方便:

FooFactory& GetFooFactory() { static FooFactory F; return F; }

并且您可以准备一个方便的构建器:

template <typename Derived>
Foo* fooBuilder() { return new Derived(); }

然后人们应该在工厂中注册其派生类:

static const bool registeredBar =
    GetFooFactory().Register("Bar", fooBuilder<Bar>);

注意:工厂应该是单例远非强制性的,尽管它在这里并不那么邪恶,因为一旦库的加载结束它就会保持不变。

注意:对于正确的插件架构,您需要使用 RAII(而不是 bool)来处理库卸载时的取消注册。不过这种情况要少见得多。

No, you cannot.

What you want, apparently, is a Factory (or perhaps Abstract Factory).

In C++, you setup a Factory class and register builders.

class FooFactory
{
public:
  typedef std::function<Foo*()> Builder;

  /// returns true if the registration succeeded, false otherwise
  bool Register(std::string const& key, Builder const& builder) {
    return map.insert(std::make_pair(key, builder)).second;
  }

  /// returns a pointer to a new instance of Foo (or a derived class)
  /// if the key was found, 0 otherwise
  Foo* Build(std::string const& key) const {
    auto it = _map.find(key);
    if (it == _map.end()) { return 0; } // no such key
    return (it->second)();
  }

private:
  std::map<std::string, Builder> _map;
};

You can create a singleton of this factory, to register the derived classes during library load, which is handy for plugins-like architecture:

FooFactory& GetFooFactory() { static FooFactory F; return F; }

And you can prepare a handy builder:

template <typename Derived>
Foo* fooBuilder() { return new Derived(); }

Then people are expected to register their derived classes in the factory:

static const bool registeredBar =
    GetFooFactory().Register("Bar", fooBuilder<Bar>);

Note: it is far from being mandatory that the factory should be a singleton, though it's not as evil here because it's constant once the load of the libraries ends.

Note: for a proper plugin architecture, you'd need to use RAII (instead of a bool), to handle the unregistration at library unload. It's much rarer though.

黑寡妇 2024-11-03 05:15:02

C++ 不允许迭代类型。枚举成员的枚举也是不可能的。请参阅:

enum Color
{
    red,
    green,
    blue=5,
    yellow
};

此外,C++ 编译器独立编译编译单元。您可以想象,在编译基类实现时,有时无法知道该类是否会被继承。

C++ does not allow to iterate over types. Also enumeration of enum members are not possible. See this:

enum Color
{
    red,
    green,
    blue=5,
    yellow
};

Further the C++ compiler compiles compilation units independent. You can imaging that it cannot known when compiling the base class implementation that the class will be inherited sometimes.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文