Factory Pattern in C++ with templates (using the confusingly recurring template and registry patterns)
#ifndef __BASE_H | |
#define __BASE_H | |
#include <string> | |
class Base { | |
public: | |
Base(); | |
Base(bool isRegistered); | |
virtual ~Base() {} | |
// to determine if this instance class is an instance | |
// of a derived class, registered to the factory. | |
bool IsRegistered() const; | |
// a way for derived classes to identify themselves | |
virtual std::string GetName() = 0; | |
private: | |
const bool IsRegistered_; | |
}; | |
#endif |
#include "BaseFactory.h" | |
#include <utility> | |
#include <cstdio> | |
bool | |
BaseFactory::Register(std::string name, factoryMethod createMethod) { | |
printf("Registering %s\n", name.c_str()); // debugging purposes | |
// add the pair to the map | |
std::pair<std::map<std::string, factoryMethod>::iterator, bool> registeredPair = | |
BaseFactory::RegisteredNames.insert(std::make_pair(name.c_str(), createMethod)); | |
// return whether it was added or updated | |
return registeredPair.second; | |
} | |
Base * | |
BaseFactory::Create(std::string name) { | |
// attempt to get the pair from the map | |
std::map<std::string, factoryMethod>::iterator registeredPair = | |
BaseFactory::RegisteredNames.find(name); | |
// did we find one? | |
if(registeredPair == BaseFactory::RegisteredNames.end()) | |
return NULL; // return NULL | |
// return a new instance of derived class | |
return registeredPair->second(); | |
} | |
// initialise the registered names map | |
std::map<std::string, factoryMethod> BaseFactory::RegisteredNames = { }; |
#ifndef __BASE_FACTORY_H | |
#define __BASE_FACTORY_H | |
#include "Base.h" | |
#include <string> | |
#include <map> | |
typedef Base* (*factoryMethod)(); | |
class BaseFactory { | |
public: | |
// register a class name with a particular create method | |
static bool Register(std::string name, factoryMethod createMethod); | |
// create a derived class, given a name | |
static Base *Create(std::string name); | |
protected: | |
// a map to hold a ... mapping between strings and create functions | |
static std::map<std::string, factoryMethod> RegisteredNames; | |
}; | |
#endif |
#ifndef __BASE_IMPL_H | |
#define __BASE_IMPL_H | |
#include "Base.h" | |
#include "BaseFactory.h" | |
#include <string> | |
template<typename T> | |
class BaseImpl : public Base { | |
public: | |
// give derived classes the ability to create themselves | |
static Base *Create() { return new T(); } | |
// get the identifier of the derived class | |
std::string GetName() { | |
return T::Name; | |
} | |
protected: | |
// to determine if the class definition is registered | |
static const bool IsRegistered_; | |
BaseImpl() : | |
Base(IsRegistered_) { } | |
}; | |
template<typename T> | |
// attempt to initialise the IsRegistered variable of derived classes | |
// whilst registering them to the factory | |
const bool BaseImpl<T>::IsRegistered_ = | |
BaseFactory::Register(T::Name, &BaseImpl<T>::Create); | |
#endif |
#include "BaseImpl.h" | |
#include "BaseFactory.h" | |
#include <string> | |
#define X(x) \ | |
class x : public BaseImpl<x> {\ | |
public:\ | |
x() : BaseImpl<x>() {}\ | |
static const std::string Name;\ | |
};\ | |
const std::string x::Name = #x; | |
X(A) | |
X(B) | |
X(C) | |
#undef X | |
int | |
main(void) | |
{ | |
Base *l = BaseFactory::Create("B"); | |
if(l != NULL) { | |
B *b = dynamic_cast<B*>(l); | |
printf("%s %s registered.\n", b->GetName().c_str(), b->IsRegistered() ? "is" : "is not"); | |
delete l; | |
} else { | |
printf("B doesn't exist.\n"); | |
} | |
l = BaseFactory::Create("D"); | |
if(l != NULL) { | |
printf("%s %s registered.\n", l->GetName().c_str(), l->IsRegistered() ? "is" : "is not"); | |
delete l; | |
} else { | |
printf("D doesn't exist.\n"); | |
} | |
return 0; | |
} |
CC ?= g++ | |
CFLAGS ?= -O2 -g -std=c++0x -Wall -Weffc++ -pedantic \ | |
-pedantic-errors -Wextra -Wall -Wcast-align \ | |
-Wcast-qual -Wchar-subscripts -Wcomment -Wconversion \ | |
-Wdisabled-optimization \ | |
-Werror -Wfloat-equal -Wformat -Wformat=2 \ | |
-Wformat-nonliteral -Wformat-security \ | |
-Wformat-y2k \ | |
-Wimport -Winit-self -Winline \ | |
-Winvalid-pch \ | |
-Wunsafe-loop-optimizations -Wlong-long -Wmissing-braces \ | |
-Wmissing-field-initializers -Wmissing-format-attribute \ | |
-Wmissing-include-dirs -Wmissing-noreturn \ | |
-Wpacked -Wparentheses -Wpointer-arith \ | |
-Wredundant-decls -Wreturn-type \ | |
-Wsequence-point -Wshadow -Wsign-compare -Wstack-protector \ | |
-Wstrict-aliasing -Wstrict-aliasing=2 -Wswitch -Wswitch-default \ | |
-Wswitch-enum -Wtrigraphs -Wuninitialized \ | |
-Wunknown-pragmas -Wunreachable-code -Wunused \ | |
-Wunused-function -Wunused-label -Wunused-parameter \ | |
-Wunused-value -Wunused-variable -Wvariadic-macros \ | |
-Wvolatile-register-var -Wwrite-strings | |
EXEC = Main | |
CORE = Base.o BaseFactory.o | |
exec: ${CORE} Main.o | |
${CC} ${CFLAGS} -o ${EXEC} ${CORE} Main.o | |
clean: | |
rm -Rf *.dSYM *.o ${EXEC} | |
%.o: %.cpp | |
$(CC) $(CFLAGS) -c $< |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment