Right design pattern to deal with polymorphic collections of objects

后端 未结 5 1045
爱一瞬间的悲伤
爱一瞬间的悲伤 2021-01-22 04:59

Suppose I have the following classes:

class BaseObject {
    public:
        virtual int getSomeCommonProperty();
};

class Object1: public BaseObject {
    publ         


        
5条回答
  •  鱼传尺愫
    2021-01-22 05:30

    You can store all your objects of base and derived classes in one collection through the base class (smart) pointer. Using visitor design pattern and double dispatch mechanism you can call a function only on objects of a specific type without having to expose that function in the base class interface. For example:

    #include 
    #include 
    #include 
    #include 
    #include 
    
    struct Visitor { // Visitor design patter
        virtual void visit(struct BaseObject&) {}
        virtual void visit(struct Object1&) {}
    };
    
    struct BaseObject {
        unsigned ref_count_; // intrusive_ptr support
        BaseObject() : ref_count_() {}
        virtual ~BaseObject() {}
        virtual void accept(Visitor& v) { v.visit(*this); } // Visitor's double dispatch
        virtual void getSomeCommonProperty() { printf("%s\n", __PRETTY_FUNCTION__); }
    };
    
    void intrusive_ptr_add_ref(BaseObject* p) { // intrusive_ptr support
        ++p->ref_count_;
    }
    
    void intrusive_ptr_release(BaseObject* p) { // intrusive_ptr support
        if(!--p->ref_count_)
            delete p;
    }
    
    struct Object1 : BaseObject {
        virtual void accept(Visitor& v) { v.visit(*this); } // Visitor's double dispatch
        virtual void getSomeCommonProperty() { printf("%s\n", __PRETTY_FUNCTION__); }
        void getSomeSpecificProperty() { printf("%s\n", __PRETTY_FUNCTION__); }
    };
    
    template
    struct FunctorVisitor : Visitor {
        Functor f_;
        FunctorVisitor(Functor f) : f_(f) {}
        void visit(T& t) { f_(t); } // apply to T objects only
        template void operator()(P const& p) { p->accept(*this); }
    };
    
    template
    FunctorVisitor apply_to(Functor f)
    {
        return FunctorVisitor(f);
    }
    
    int main()
    {
        typedef boost::intrusive_ptr BaseObjectPtr;
        typedef std::vector Objects;
    
        Objects objects;
        objects.push_back(BaseObjectPtr(new BaseObject));
        objects.push_back(BaseObjectPtr(new Object1));
    
        for_each(
              objects.begin()
            , objects.end()
            , boost::bind(&BaseObject::getSomeCommonProperty, _1)
            );
    
        for_each(
              objects.begin()
            , objects.end()
            , apply_to(boost::bind(&BaseObject::getSomeCommonProperty, _1))
            );
    
        for_each(
              objects.begin()
            , objects.end()
            , apply_to(boost::bind(&Object1::getSomeSpecificProperty, _1))
            );
    }
    

    Output:

    $ ./test
    virtual void BaseObject::getSomeCommonProperty()
    virtual void Object1::getSomeCommonProperty()
    virtual void BaseObject::getSomeCommonProperty()
    void Object1::getSomeSpecificProperty()
    

提交回复
热议问题