如何遍历另一个类中的容器?

时间:2010-11-11 16:07:42

标签: c++ design-patterns stl tree iterator

我已经多次遇到过这个问题,想知道是否有一个简单的方法或模式可以解决它。

想象一下一个树结构,其中每个节点都包含一个指向子节点的STL容器(向量)。我希望客户端代码能够遍历这个树,并遍历子容器以访问其他部分。

我的问题是我想维护我的节点的封装,同时让客户轻松查看该节点的所有子节点。我还想确保如果客户端获取树中根节点的const引用,那么对树的后续部分的所有访问也都是const。

我应该尝试为我的节点类型创建一个迭代器类,有一个节点方法返回向量迭代器,还是有一个我丢失的更优雅的模式?

编辑:我想再次强调,虽然我看到了一些好主意,但我有 指针 的容器到其他节点。返回vector<node *>::const_iterator不会阻止客户端在节点上调用非const方法。它只保护指针本身不会指向不同的对象。

3 个答案:

答案 0 :(得分:4)

这样的事情通常就足够了:

class node 
{
public:
    typedef std::vector<node> node_list;
    typedef node_list::const_iterator const_iterator;

    const_iterator begin() const { return children_.begin(); }
    const_iterator end() const { return children_.end(); }

private:
    node_list children_;
}

这允许您更改基础容器类型,而无需更改迭代node个孩子的代码。

这样做的缺点是它泄漏了一个实现细节,因为使用你的node::const_iterator的代码知道它是一个随机访问迭代器(因为std::vector:: const_iterator是一个随机访问迭代器),所以你可能有很难切换到不支持随机访问的容器。

如果您希望自己能够控制迭代器类别,则可能需要创建自己的iterator类,以提供您想要提供的确切行为。

答案 1 :(得分:4)

这不是您问题的直接答案,而是另一种方法。您可以通过注册回调函数来获取control inversion,而不是让客户端代码运行该节目。例如:

// Derive from this class to create a visitor
class AbstractVisitor
{
public:
    virtual void operator() (const T &) = 0;
};


// Your recursive data-structure class
class MyClass
{
public:
    void walk(AbstractVisitor &v) const
    {
        // Call the client callback
        v(payload);
        for (std::vector<MyClass>::const_iterator it = children.begin();
             it != children.end(); ++it)
        {
            // Recurse
            it->walk(v);
        }
    }

private:
    T payload;   // Some sort of payload associated with the class
    std::vector<MyClass> children;
};


// You could have different visitor classes to do different things
class MyVisitor : public AbstractVisitor
{
public:
    virtual void operator() (const T &t)
    {
        // Do something with t
    }
}


int main()
{
    MyClass m;
    MyVisitor v;
    ...
    m.walk(v);
}

完成了完成任务!

答案 2 :(得分:0)

对于遍历整个树,您必须创建自己的迭代器类,只需遍历子项,就可以安全地返回向量迭代器。