代码之家  ›  专栏  ›  技术社区  ›  Thomas Matthews

智能指针的迭代和容器

  •  0
  • Thomas Matthews  · 技术社区  · 15 年前

    我有一个指向可变对象的智能指针容器。我得写两封 每一个 循环,一个用于以只读数据的形式访问对象,另一个用于可变数据。编译器告诉我 std::vector< boost::shared_ptr<Object> > 与…不同 std::vector< boost::shared_ptr<const Object> > 请注意 const .

    下面是我的示例代码:

    #include <vector>
    #include "boost/shared_ptr.hpp"
    #include <iterator>
    
    class Field_Interface
    { ; };
    typedef boost::shared_ptr<Field_Interface> Ptr_Field_Interface;
    typedef boost::shared_ptr<const Field_Interface> Ptr_Const_Field_Interface;
    
    struct Field_Iterator
      : std::input_iterator<std::forward_iterator_tag, Ptr_Field_Interface>
    {
      // forward iterator methods & operators...
    };
    
    struct Const_Field_Iterator
      : std::input_iterator<std::forward_iterator_tag, Ptr_Const_Field_Interface>
    {
      // forward iterator methods & operators...
    };
    
    struct Field_Functor
    {
      virtual void operator()(const Ptr_Field_Interface&) = 0;
      virtual void operator()(const Ptr_Const_Field_Interface&) = 0;
    };
    
    class Record;
    typedef boost::shared_ptr<Record> Ptr_Record;
    typedef boost::shared_ptr<const Record> Ptr_Const_Record;
    
    class Record_Base
    {
      protected:
        virtual Field_Iterator beginning_field(void) = 0;
        virtual Field_Iterator ending_field(void) = 0;
        virtual Const_Field_Iterator const_beginning_field(void) = 0;
        virtual Const_Field_Iterator const_ending_field(void) = 0;
    
        void for_each(Field_Functor * p_functor)
        {
           Field_Iterator iter_begin(beginning_field());
           Field_Iterator iter_end(ending_field());
           for (; iter_begin != iter_end; ++ iter_begin)
           {
             (*p_functor)(*iter_begin);
           }
         }
    };
    
    class Record_Derived
    {
    public:
       typedef std::vector<Ptr_Field_Interface> Field_Container;
       typedef std::vector<Ptr_Record>          Record_Container;
    private:
       Field_Container m_fields;
       Record_Container m_subrecords;
    };
    

    鉴于以上所有细节,我如何实现 Record_Base 在里面 Record_Derived ?

    我试过了:

    • 返回 m_fields.begin() 哪一个
      返回转换错误(不能 转换 std::vector<...> to Field_Iterator )
    • 返回 &m_fields[0] ,这就是 很危险,因为它假设 关于 std::vector .

    顺便说一句,我没有用 std::for_each 因为我必须遍历一个字段容器 子记录的容器。

    3 回复  |  直到 15 年前
        1
  •  1
  •   Emile Cormier    15 年前

    你所做的与 Composite Visitor 模式。这两种图案很好地结合在一起,所以你似乎走对了。

    要实现复合模式,请分配以下角色(请参阅复合模式UML图):

    • 叶&叶; Field
    • 复合材料-GT; Record
    • 组件-的抽象基类 记录 (想不出一个好名字)

    对复合类型调用的组件操作以递归方式传递给所有子级(叶和其他嵌套复合类型)。

    要实现访问者模式,请重载 operator() 在每个组件子类型(字段和记录)的函数类中。

    我建议你拿一份 Design Patterns 这本书由“四人帮”所著,它更好地解释了这些概念,并且比我所能理解的要详细得多。

    以下是一些激发食欲的示例代码:

    #include <iostream>
    #include <vector>
    #include "boost/shared_ptr.hpp"
    #include "boost/foreach.hpp"
    
    class Field;
    class Record;
    
    struct Visitor
    {
        virtual void operator()(Field& field) = 0;
        virtual void operator()(Record& field) = 0;
    };
    
    class Component
    {
    public:
        virtual bool isLeaf() const {return true;}
        virtual void accept(Visitor& visitor) = 0;
    };
    typedef boost::shared_ptr<Component> ComponentPtr;
    
    class Field : public Component
    {
    public:
        explicit Field(int value) : value_(value) {}
        void accept(Visitor& visitor) {visitor(*this);}
        int value() const {return value_;}
    
    private:
        int value_;
    };
    
    class Record : public Component
    {
    public:
        typedef std::vector<ComponentPtr> Children;
        Record(int id) : id_(id) {}
        int id() const {return id_;}
        Children& children() {return children_;}
        const Children& children() const {return children_;}
        bool isLeaf() const {return false;}
        void accept(Visitor& visitor)
        {
            visitor(*this);
            BOOST_FOREACH(ComponentPtr& child, children_)
            {
                child->accept(visitor);
            }
        }
    
    private:
        int id_;
        Children children_;
    };
    typedef boost::shared_ptr<Record> RecordPtr;
    
    struct OStreamVisitor : public Visitor
    {
        OStreamVisitor(std::ostream& out) : out_(out) {}
        void operator()(Field& field) {out_ << "field(" << field.value() << ") ";}
        void operator()(Record& rec) {out_ << "rec(" << rec.id() << ") ";}
        std::ostream& out_;
    };
    
    int main()
    {
        RecordPtr rec(new Record(2));
            rec->children().push_back(ComponentPtr(new Field(201)));
            rec->children().push_back(ComponentPtr(new Field(202)));
        RecordPtr root(new Record(1));
            root->children().push_back(ComponentPtr(new Field(101)));
            root->children().push_back(rec);
    
        OStreamVisitor visitor(std::cout);
        root->accept(visitor);
    }
    

    在记录中,您可能希望提供用于操作/访问子级的方法,而不是返回对基础子级向量的引用。

        2
  •  0
  •   Mathias Soeken    15 年前

    我建议在使用公共容器类型时不要编写自己的迭代器。编写自己的迭代器在编写自己的容器时是有意义的。但是,当您计划编写自定义迭代器时,可以查看 Boost.Iterator 包裹。

        3
  •  0
  •   Emile Cormier    15 年前

    如果你想隐藏 std::vector 以及它来自用户的迭代器,然后您需要提供多态迭代器来支持您的多态性 RecordBase 容器。退房 any_iterator 来自Adobe ASL库。 These links 也可能有帮助。

    但是,您应该考虑在设计中使用复合模式和访问者模式,而不是去解决所有这些问题。看看我的另一个答案。