Elegant way to implement extensible factories in C++

前端 未结 7 1036
刺人心
刺人心 2020-12-07 14:50

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

7条回答
  •  再見小時候
    2020-12-07 15:35

    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.

提交回复
热议问题