Last active
June 26, 2024 23:37
-
-
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)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "Base.h" | |
Base::Base() : | |
IsRegistered_(false) | |
{ } | |
Base::Base(bool isRegistered) : | |
IsRegistered_(isRegistered) | |
{ } | |
bool | |
Base::IsRegistered() const { | |
return this->IsRegistered_; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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 = { }; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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