I am looking for an intuitive and extensible way to implement factories for subclasses of a given base class in c++. I want to provide such a factory function in a library.T
The best solution I can currently think of is by using a Factory class which stores pointers to producing functions for each derived class. When a new derived class is made, a function pointer to a producing method can be stored in the factory.
Here is some code to illustrate my approach:
#include
#include
class Base{};
// Factory class to produce Base* objects from an int (for simplicity).
// The class uses a list of registered function pointers, which attempt
// to produce a derived class based on the given int.
class Factory{
public:
typedef Base*(*ReadFunPtr)(int);
private:
static vector registeredFuns;
public:
static void registerPtr(ReadFunPtr ptr){ registeredFuns.push_back(ptr); }
static Base* Produce(int value){
Base *ptr=NULL;
for(vector::const_iterator I=registeredFuns.begin(),E=registeredFuns.end();I!=E;++I){
ptr=(*I)(value);
if(ptr!=NULL){
return ptr;
}
}
return NULL;
}
};
// initialize vector of funptrs
std::vector Factory::registeredFuns=std::vector();
// An example Derived class, which can be produced from an int=0.
// The producing method is static to avoid the need for prototype objects.
class Derived : public Base{
private:
static Base* ProduceDerivedFromInt(int value){
if(value==0) return new Derived();
return NULL;
}
public:
Derived(){};
// registrar is a friend because we made the producing function private
// this is not necessary, may be desirable (e.g. encapsulation)
friend class DerivedRegistrar;
};
// Register Derived in the Factory so it will attempt to construct objects.
// This is done by adding the function pointer Derived::ProduceDerivedFromInt
// in the Factory's list of registered functions.
struct DerivedRegistrar{
DerivedRegistrar(){
Factory::registerPtr(&(Derived::ProduceDerivedFromInt));
}
} derivedregistrar;
int main(){
// attempt to produce a Derived object from 1: should fail
Base* test=Factory::Produce(1);
std::cout << test << std::endl; // outputs 0
// attempt to produce a Derived object from 0: works
test=Factory::Produce(0);
std::cout << test << std::endl; // outputs an address
}
TL;DR: in this approach, downstream developers need to implement the producing function of a derived class as a static member function (or a non-member function) and register it in the factory using a simple struct.
This seems simple enough and does not require any prototype objects.