Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible in C++ to loop over all subclasses of an Abstract class?

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();
like image 977
Stefan Lendl Avatar asked Mar 27 '11 17:03

Stefan Lendl


1 Answers

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.

like image 103
Matthieu M. Avatar answered Nov 15 '22 09:11

Matthieu M.