Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Register a C++ class so that later a function can iterate over all registered classes

I am trying to write an application that is loading its extensions dynamically during runtime. I used Boost Preprocessor library to write a preprocessor function that, given a list of names, declares a class for each name (and make all of them subclasses of some AbstractPlugin class) and then declares a Boost MPL sequence containing that classes. Then I wrote a class that tries a pointer to AbstractPlugin if it could be cast to any of the types in that MPL sequence. The problem here is that my preprocessor function needs a full list of all extensions I want to create and load. Is there some technique that lets me register each extension in a separate file?

Update:

I believe, my explanation of situation was too vague, so I decided to make it more specific.

I would like to define a collection of extension types. For each extension type there could be any number of extensions. During runtime the program loads external library, resolve the entry point function, call it and, as a result, get a pointer. Then it tries to cast that pointer to all registered extension types (using dynamic_cast, so classes for extension types all inherit from some polymorphic base class). If a cast to some extension type succeeds, the casted pointer is used in a call to special handler for that extension type.

The number of extension types is known at compile time (while, obviously, the number of extensions is infinite). Using my aproach the loader class uses this knowledge to check whether there exists a handler for each extension type (if not, the program doesn't compile). Also, my aproach doesn't force classes for extension types know anything about the loader (so it is easy to modify the loader). But it would be more convenient if each extension type registered itself.

like image 867
grisumbras Avatar asked Jun 24 '12 06:06

grisumbras


People also ask

What does it mean to register a class in Python?

Class registration is a helpful pattern for building modular Python programs. Metaclasses let you run registration code automatically each time your base class is subclassed in a program. Using metaclasses for class registration avoids errors by ensuring that you never miss a registration call.

What is a subclass C++?

Sub Class: The class that inherits properties from another class is called Subclass or Derived Class. Super Class: The class whose properties are inherited by a subclass is called Base Class or Superclass.

Are there classes in C?

No, C doesn't have classes. That said, there are ways of simulating object-oriented programming in C - a quick Google search should yield some useful results.


2 Answers

You can make all your classes self-registering in some sort of collection. Here's a skeleton approach:

Base.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();
};

Base.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;
}

Now to use this in a client:

Derived.hpp:

#include "Base.hpp"

struct Derived : Base
{
    static std::unique_ptr<Base> create() { return std::make_unique<Derived>(); }
    // ...
};

Derived.cpp:

#include "Derived.hpp"

namespace
{
    Base::Registrar<Derived> registrar("MyClass");
}

The constructor of the Base::Registrar<Derived> takes care of registering the class Derived under the name "MyClass". You can create instances of Derived dynamically via:

std::unique_ptr<Base> p = Base::instantiate("MyClass");

The code could/should be improved by detecting repeat registrations, printing a list of available classes, etc. Note how we avoid any static initialization ordering problems my making the actual registry map object a block-static object, which is guaranteed to be initialized before its first use, and thus destroyed only after its last use.

like image 172
Kerrek SB Avatar answered Sep 20 '22 21:09

Kerrek SB


It is not difficult to implement such an extension framework using the abstract factory pattern.

http://en.wikipedia.org/wiki/Abstract_factory_pattern

You can register those abstract factory functions/objects in a global list, and do whatever you want to do base on it.

like image 24
lenx.wei Avatar answered Sep 19 '22 21:09

lenx.wei