使用多态集合

时间:2015-04-29 07:24:24

标签: c++ templates inheritance

我遇到如下情况:

    #include <set>
    #include <map>
    #include <vector>
    #include <string>

    class BaseCollection {
        // I don't know what to keep here
        // I want to have access to collection elements
        // seems I need to implmement begin(), end() for collections
    };

    class CollectionA : public BaseCollection {
        public: // in real code this will be private
            std::vector<double> coll_;
    };

    class CollectionB : public BaseCollection {
        public: // in real code this will be private
            std::set<double> coll_;
    };

    class CollectionC : public BaseCollection {
        public: // in real code this will be private
            std::map<std::string, double> coll_;
    };

    class Base {
        public:
            virtual BaseCollection* getColl() = 0;
    };

    class A : public Base {
        virtual BaseCollection* getColl() { return &coll_; }
        public: // in real code this will be private
            CollectionA coll_;
    };

    class B : public Base {
        virtual BaseCollection* getColl() { return &coll_; }
        public: // in real code this will be private
            CollectionB coll_;
    };

    class C : public Base {
        virtual BaseCollection* getColl() { return &coll_; }
        public: // in real code this will be private
            CollectionC coll_;
    };

    class Container {
        public:
        typedef std::map<std::string, Base*>::const_iterator const_iterator;
        Container::const_iterator begin() const { return objects_.begin(); }
        public: // in real code this will be private
            std::map<std::string, Base*> objects_;
    };


    int main() {
        // somewhere we're creating objects of different types and filling their collections
        A objA;
        // suppose we filled objA.coll_ somehow
        Base* ptrA = new A;
        ptrA = &objA;

        // somwhere we're iterationg over Container
        Container c;
        c.objects_["objA"] = ptrA;
        Container::const_iterator itBeg = c.begin();
        BaseCollection* coll = itBeg->second->getColl();
        // and here I want to itarate over collection
}

所以,我需要以某种方式为begin()定义至少end()BaseCollection并在派生类中实现它们。
或者我可能需要使用模板?但我无法理解这一点 我怎么能这样做?
或者也许这是不可能的,我需要为每种类型保留单独的容器(ABC)。

修改 所以,我所拥有的是Base类,以及从中派生的一些类(ABC),它们包含不同类型的集合。实际上我想要的是Base中的一个接口,用于迭代当前指向它的派生类的集合。

提前致谢。

2 个答案:

答案 0 :(得分:0)

修改 您可以实现迭代器的并行层次结构BaseCollection的Base iterator类和每个派生集合类的一个迭代器。 同样,当迭代器中的值类型不同时,您可以将公共值类型定义为某种变体或将所有内容都返回为字符串。

这不是微不足道的。你必须在每个特定的类开始/结束,并在每个派生的迭代器中实现值访问函数,像复制/比较等操作符。

制作基础类(不是集合)并存储指向标准容器中对象的指针是不是更容易?

<强>原始 使用模板进行代码重用

使用多态来提供相同的接口并隐藏实现

在您的情况下,您在派生类中使用具有不同类型的不同容器。它只是一个例子,还是应该是这样的?如果第二个,模板在这里没有帮助。

实施开始/结束不是问题,例如virtual void begin() =0; 派生类中的实现应该设置一些指向特定容器中位置的私有索引或迭代器。

问题还在于,您将返回哪种类型?一种变体可能是一种解决方案。

答案 1 :(得分:0)

如果您希望能够以基本类型或类型a,b或c访问元素。多态是要走的路。但是你不应该继承这个集合。所以您的基本类型如下所示:

class baseType{
    //define share parameters here like:
    int baseInt;
    //and pure virtual functions like:
    int elementType() = 0;
}

你的收藏品看起来像这样:

class BaseCollection {
    std::list<baseType> baseList;
 };

继承类型如下所示:

 class typeA:baseType{

 //a pure virtual has to be overridden so:
 int elementType() { return 1;}
 }

请注意,该集合将始终返回baseType类型的元素。如果您想知道继承类型是什么。有两种方法可以做到这一点。

  • 对baseType的指针进行静态强制转换,然后转换为所需的类型。如果类型不是所需类型,则返回null。
  • 创建一个(纯)虚函数,返回一个整数或其他类型的变量,指示类型。就像上面做的那样。

当继承类型有很多时,你可能想要做后者。因为它是很多static_casts