mass communicating

A Generic Factory in C++

Summary

Factories are classes that make other classes. They are useful together with interfaces – abstract classes which specify functionality that is implemented somewhere else.

As opposed to including a header file for each implementation (which can take quite a while to compile), factories can be used to separate implementations into different object files, and add/remove functionality simply by adding/removing objects at link time.

Here is what I want:

The full code is here: https://gist.github.com/pkrusche/5501253.

How to do it

Make an interface:

class interface {
    public:
    virtual ~interface() {}
    virtual void do_something(...) = 0;
};

typedef boost::shared_ptr<interface> Pinterface;

Make a factory and a generic factory:

/** factory interface */
class factory {
    public:
        virtual Pinterface make_me() = 0;
};
typedef boost::shared_ptr<factory> Pfactory;

/** generic factory */
template <class _s>
class generic_factory : public factory {
public:
    virtual Pinterface make_me() {
        Pinterface p(new _s());
        return p;
    }
};

Make a factory interface (static functions or separate class):

/** make one. */
static Pinterface create(const char * name);

/** register a factory with a given name */
static void register_me(const char * name, Pfactory fac);

…and a class to create this factory statically:

template <class _s>
class register_factory {
public:
    register_factory(const char * name) {
        Pfactory pf (new generic_factory<_s>);
        register_me(name, pf);
    }
#define REGISTER_INTERFACE(name, type) \
    namespace {     \
        static register_factory<type> fac(name); \
    };
};

When implementing, include interface.h in a separate cpp file. Subclass and call REGISTER_INTERFACE.

#include "interface.h"
#include <iostream>

class interface_impl_1 : public interface {
public:
    interface_impl_1() {}
    virtual ~interface_impl_1() {}

    virtual void do_something() {
        std::cout << "Hi there, I am implementation number 1." << std::endl;
    }

};

REGISTER_INTERFACE("impl1", interface_impl_1);

We could also use the class name directly in the macro using stringification.

#define REGISTER_INTERFACE(type) \
    namespace {     \
        static register_factory<type> fac(#type); \
    };

So, what have we achieved?

UPDATE: Added this: (02/05/2013).

There is one small issue remaining:

The above code runs into trouble when the implementations go into a static library (rather than just linking object files). Then, a smart linker will optimise away the static registration objects. One way to address this is shown here:

http://stackoverflow.com/questions/599035/force-visual-studio-to-link-all-symbols-in-a-lib-file

In there, two macros are defined to create references which force the linker to include stuff:

#define FORCE_LINK_THIS(x) int force_link_##x = 0;
#define FORCE_LINK_THAT(x) { extern int force_link_##x; force_link_##x = 1; }

This way, linking can be made to work by means of making an initialisation function (called at program startup) which calls all the FORCE_LINK_THAT’s, and inserting FORCE_LINK_THIS into REGISTER_INTERFACE.

This is not ideal, but still much faster than including full headers for each class which implements the interface (one more function and one more object).

Category: code Tags: c++ generic programming