Skip to content

Instantly share code, notes, and snippets.

@sacko87
Last active June 26, 2024 23:37
Show Gist options
  • Save sacko87/3359911 to your computer and use it in GitHub Desktop.
Save sacko87/3359911 to your computer and use it in GitHub Desktop.
Factory Pattern in C++ with templates (using the confusingly recurring template and registry patterns)
#include "Base.h"
Base::Base() :
IsRegistered_(false)
{ }
Base::Base(bool isRegistered) :
IsRegistered_(isRegistered)
{ }
bool
Base::IsRegistered() const {
return this->IsRegistered_;
}
#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