C++ 正确的设计模式来处理对象的多态集合

C++ 正确的设计模式来处理对象的多态集合,c++,polymorphism,C++,Polymorphism,假设我有以下几个类: class BaseObject { public: virtual int getSomeCommonProperty(); }; class Object1: public BaseObject { public: virtual int getSomeCommonProperty(); // optional int getSomeSpecificProperty(); }; class BaseC

假设我有以下几个类:

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

class Object1: public BaseObject {
    public:
        virtual int getSomeCommonProperty();  // optional
        int getSomeSpecificProperty();
};

class BaseCollection {
    public:
        virtual void someCommonTask();
};

class Collection1: public BaseCollection {
    public:
        virtual void someCommonTask();  // optional
        void someSpecificTask();
};
从BaseCollection派生的每个集合都处理特定的对象类型(并且只有一种类型)。但是BaseCollection应该能够执行一些对所有对象通用的任务,只使用BaseObject中的通用对象属性

目前,我考虑的可能有三种解决方案:

1) 将对象列表存储在BaseCollection中,例如:

class BaseCollection {
    vector<BaseObject*> objects;
};
class Collection1: public BaseCollection {
    vector<Object1*> objects;
}
类基集合{
矢量对象;
};

这个解决方案的问题是,当我需要在Collection1中执行特定于对象的任务时,我需要一个动态的\u转换,因为我不想对特定的属性使用虚拟固有,只应用于一种类型的对象。考虑到dynamic_cast可能每秒被调用数百万次,这似乎是性能关键型应用程序的一个问题

2) 将对象列表存储在Collection1中,例如:

class BaseCollection {
    vector<BaseObject*> objects;
};
class Collection1: public BaseCollection {
    vector<Object1*> objects;
}
class Collection1:公共BaseCollection{
矢量对象;
}
但是我需要一些方法来访问BaseCollection中的这个对象列表,以便能够对它们执行一些常见的任务,最好是通过迭代器。我需要创建一个函数,为BaseCollection返回一个向量,但这似乎不是很有效,因为唯一的方法是创建一个新向量(可能包含数千个对象)

3) 将对象列表存储在BaseCollection和Collection1中:

class BaseCollection {
    public:
        void someCommonTask();  // Use baseObjects
        virtual void addObject() = 0;

    protected:
        vector<BaseObject*> baseObjects;
};

class Collection1: public BaseCollection {
    vector<Object1*> objects;

    public:
        virtual void addObject() {
            Object1* obj = new Object1;
            objects.push_back(obj);
            baseObjects.push_back(obj);
        }

        void someSpecificTask(); // Use objects, no need of dynamic_cast<>
}
类基集合{
公众:
void someCommonTask();//使用baseObjects
虚拟void addObject()=0;
受保护的:
矢量基对象;
};
类集合1:公共BaseCollection{
矢量对象;
公众:
虚拟void addObject(){
Object1*obj=newobject1;
物体。推回(obj);
基本对象。推回(obj);
}
void someSpecificTask();//使用对象,无需动态强制转换
}
这两个列表实际上包含相同的对象。这是不是听起来那么难看

我正在为这类问题寻找正确/正确/最佳的设计模式,上面提到的3种解决方案都不能让我满意

也许可以用模板解决这个问题,但我看不到一种存储多态集合列表的方法,如下所示:

vector<BaseCollection*> collections;
向量集合;

我认为您应该选择选项1,但应使用静态强制转换。毕竟派生集合确实知道成员变量的类型


解释得很好。

我认为解决方案应该是和的混合。看一看这些,以完善您的设计

编辑:下面是一个示例代码
GenericProduct
BaseObject
,它提供了两个方法,一个是通用的(尽管可以重写),另一个是不做任何事情的特定方法,它不是纯虚拟的,因此可以实例化这个类
SpecificProduct
是一个子类,它以某种方式实现了特定的方法

现在,
Factory
类是一个抽象类,它定义了一个由特定工厂创建特定产品的接口,它定义了一个创建产品的纯虚拟方法
createProduct
。创建了两个具体的工厂
GenericFactory
SpecificFactory
,它们创建特定的产品

最后,
Consumer
抽象类(对应于代码中的
BaseCollection
),它定义了一个纯虚拟方法来创建工厂
createFactory
,以强制子类创建自己的具体工厂(从而创建正确的产品)。该类还定义了一个方法
fillArray
(原型模式),用工厂创建的产品填充数组

#include <iostream>
#include <vector>

using namespace std;

class GenericProduct{
    public:
        virtual void getSomeCommonProperty()
        {
            cout<<"Common Property\n";
        }
        virtual void getSomeSpecificProperty()
        {
            cout<<"Generic Has Nothing Specific\n";
        }
};

class SpecificProduct : public GenericProduct{
    public:
        virtual void getSomeSpecificProperty()
        {
            cout<<"Specific Product Has a Specific Property\n";
        }
};

class Factory
{
    public:
        virtual GenericProduct* createProduct() = 0;
};

class GenericFactory : public Factory
{
    public:
        virtual GenericProduct* createProduct()
        {
            return new GenericProduct();
        }
};

class SpecificFactory : public Factory
{
    public:
        virtual GenericProduct* createProduct()
        {
            return new SpecificProduct();
        }
};

class Consumer
{
    protected:
        vector<GenericProduct*> gp;
        Factory* factory;

    protected:
        virtual void createFactory() = 0;

    public: 
        void fillArray()
        {
            createFactory();
            for(int i=0; i<10; i++)
            {
                gp.push_back(factory->createProduct());
            }
        }

        virtual void someCommonTask()
        {
            cout<<"Performaing a Common Task ...\n";
            for(int i=0; i<10; i++)
            {
                gp[i]->getSomeCommonProperty();
            }
        }
        virtual void someSpecificTask()
        {
            cout<<"Performaing a Specific Task ...\n";
            for(int i=0; i<10; i++)
            {
                gp[i]->getSomeSpecificProperty();
            }
        }
};

class GenericConsumer : public Consumer
{
    virtual void createFactory()
    {
        factory = new GenericFactory();
    }
};

class SpecificConsumer : public Consumer
{
    virtual void createFactory()
    {
        factory = new SpecificFactory();
    }
};


int main()
{
    Consumer* c = new GenericConsumer();
    c->fillArray();
    c->someCommonTask();
    return 0;
}
#包括
#包括
使用名称空间std;
类泛型产品{
公众:
虚拟void getSomeCommonProperty()
{

难道这就够了吗

class CollectionManipulator {
public:
    void someCommonTask(BaseCollection& coll) {
         for(unsigned int i = 0; i < coll.size(); i++)
              someCommonTask(coll.getObj(i));
    }
private:
    void someCommonTask(BaseObject*);  // Use baseObjects

};

class BaseCollection {
     friend class CollectionManipulator;
private:
     virtual BaseObject* getObj(unsigned int) = 0;
     virtual unsigned int size() const = 0;
};

class Collection1 : public BaseCollection {
    vector<Object1*> objects;

public:
    virtual void addObject() {
        Object1* obj = new Object1;
        objects.push_back(obj);
        baseObjects.push_back(obj);
    }

    void someSpecificTask(); // Use objects, no need of dynamic_cast<>

private:
    BaseObject* getObj(unsigned int value) {
        return object[value];
    }

    unsigned int size() const {
        return objects.size();
    }
}
类集合操纵器{
公众:
void someCommonTask(BaseCollection和coll){
for(无符号整数i=0;i

如果您想在Collection1中抽象您的容器(比如使用list而不是vector),要在操纵器中使用它,请创建一个抽象迭代器…

Id使用嵌套适配器,如下面的示例所示。您必须为每个要进行奇特更新的类专门化它 !该示例存在内存泄漏-分配的A、B、Q对象不会被删除

#include <iostream>
#include <vector>
#include <algorithm>
class Q
{
public:
    virtual void Foo()
    {
        std::cout << "Q::Foo()" << std::endl;
    }
};
class A
{

public:
    virtual void Foo()
    {
        std::cout << "A::Foo()" << std::endl;
    }
};

class B : public A
{
public:
    virtual void Foo()
    {
    std::cout << "B::Foo()" << std::endl;
    }
    virtual void BFoo()
    {
        std::cout << "B::BFoo()" << std::endl;
    }
};

template <typename ElementType>
class C
{
public:
    template <typename T>
    void add(T* ptr){m_Collection.push_back(std::unique_ptr<Adapter>(new ConcreteAdapter<T>(ptr)));}
    void updateAll()
    {
        std::for_each(m_Collection.begin(), m_Collection.end(), [&](std::unique_ptr<Adapter> &adapter)->void{adapter->update();});
    }
private:
    class Adapter
    {
    public:
        virtual ElementType* get() = 0;
        virtual void update(){get()->Foo();}

    };
    template <typename T>
    class ConcreteAdapter : public Adapter
    {
    public:
        ConcreteAdapter(T* ptr) : m_Ptr(ptr){}
        virtual T* get(){return m_Ptr;}
    protected:
        T* m_Ptr;
    };

    template <>
    class ConcreteAdapter<B> : public Adapter
    {
    public:
        ConcreteAdapter(B* ptr) : m_Ptr(ptr){}
        virtual B* get(){return m_Ptr;}
        virtual void update()
        {
        get()->Foo();
        get()->BFoo();
        }
    private:
        B* m_Ptr;

    };
    std::vector<std::unique_ptr<Adapter>> m_Collection;
};
int main()
{
    C<A> c;
    c.add(new A());
    c.add(new B());
    //c.add(new Q()); //error - correct
    c.updateAll();
    return 0;
}
#包括
#包括
#包括
Q类
{
公众:
虚拟void Foo()
{

std::cout您可以通过基类(智能)指针将基类和派生类的所有对象存储在一个集合中。使用and机制,您可以仅对特定类型的对象调用函数,而无需在基类接口中公开该函数。例如:

#include <boost/intrusive_ptr.hpp>
#include <boost/bind.hpp>
#include <vector>
#include <algorithm>
#include <stdio.h>

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<class T, class Functor>
struct FunctorVisitor : Visitor {
    Functor f_;
    FunctorVisitor(Functor f) : f_(f) {}
    void visit(T& t) { f_(t); } // apply to T objects only
    template<class P> void operator()(P const& p) { p->accept(*this); }
};

template<class T, class Functor>
FunctorVisitor<T, Functor> apply_to(Functor f)
{
    return FunctorVisitor<T, Functor>(f);
}

int main()
{
    typedef boost::intrusive_ptr<BaseObject> BaseObjectPtr;
    typedef std::vector<BaseObjectPtr> 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<BaseObject>(boost::bind(&BaseObject::getSomeCommonProperty, _1))
        );

    for_each(
          objects.begin()
        , objects.end()
        , apply_to<Object1>(boost::bind(&Object1::getSomeSpecificProperty, _1))
        );
}

“因为我不想对特定属性使用虚拟内在性”这意味着每次我用特定属性创建一个新类型的对象(只能由其相应的集合使用),我都必须在BaseObject中添加一个虚拟函数,它是compl