How to randomly select a class to instantiate without using switch?

前端 未结 2 1058
既然无缘
既然无缘 2020-12-10 14:44

I\'m refactoring a single 3000+-line class with a tangled web of conditionals and switches into a set of worker classes. Previously part of the constructor would select whic

相关标签:
2条回答
  • 2020-12-10 15:38

    I would suggest creating a common base class (if you've not already got one) and then using a factory class to encapsulate the creation process. The factory would just return a pointer to your base class which has the prototype run method.

    Something along these lines:

    class Type
    {
        virtual void Run() = 0;
    };
    
    class TypeFoo : public Type
    {
    public:
        TypeFoo() {};
        virtual void Run() {};
        static Type* Create() { return new TypeFoo(); };
    };
    
    class TypeBar : public Type
    {
    public:
        TypeBar() {};
        virtual void Run() {};
        static Type* Create() { return new TypeBar(); };
    };
    
    class TypeBaz : public Type
    {
    public:
        TypeBaz() {};
        virtual void Run() {};
        static Type* Create() { return new TypeBaz(); };
    };
    
    class TypeFactory
    {
        typedef Type* (*CreateFn)();
    
    public:
        static Type* RandomTypeFooWeighted()
        {
            CreateFn create[] = 
            {
                TypeFoo::Create, 
                TypeFoo::Create,   // weighted towards FOO
                TypeBar::Create, 
                TypeBaz::Create
            };   
            const int fncount = sizeof(create)/sizeof(*create);
            return create[ rand()%fncount ]();
        }
    };
    

    So to use it you can just call:

    Type *t = TypeFactory::RandomTypeFooWeighted();
    

    Credit to Nawaz for the function pointer bits and bobs.

    0 讨论(0)
  • 2020-12-10 15:41

    The answer is : a base class and an array of function pointers can help you do that.

    struct Base { virtual ~Base() {} }; //make ~Base() virtual
    struct Foo : Base {};
    struct Bar : Base {};
    struct Baz : Base {};
    
    template<typename T>
    Base *Create() { return new T(); }
    
    typedef Base* (*CreateFn)();
    
    CreateFn create[] = 
             {
                  &Create<Foo>, 
                  &Create<Foo>,   // weighted towards FOO
                  &Create<Bar>, 
                  &Create<Baz>
             }; 
    const size_t fncount = sizeof(create)/sizeof(*create);
    
    Base *Create()
    {
       return create[rand() % fncount](); //forward the call
    }
    

    Then use it as (ideone demo):

    int main() {
            Base *obj = Create();
            //work with obj using the common interface in Base
    
            delete obj; //ok, 
                        //the virtual ~Base() lets you do it 
                        //in a well-defined way
            return 0;
    }   
    
    0 讨论(0)
提交回复
热议问题