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

C++ 如何遍历另一个类中的容器?,c++,design-patterns,stl,tree,iterator,C++,Design Patterns,Stl,Tree,Iterator,我曾多次遇到这个问题,我想知道是否有一个简单的方法或模式可以用来解决它 设想一个树结构,其中每个节点包含指向子节点的指针的STL容器(向量)。我希望客户端代码能够遍历此树,并遍历子容器以访问其他部分 我的问题是,我希望维护节点的封装,同时让客户端轻松查看该节点的所有子节点。我还想确保,如果客户机获得对树中根节点的常量引用,那么对树的后续部分的所有访问也是常量 我应该尝试为我的节点类型创建一个迭代器类,使用一个节点方法返回向量迭代器,还是缺少一个更优雅的模式 编辑:我想再次强调,虽然我看到了一些好

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

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

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

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


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

像这样的东西通常就足够了:

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_;
}
类节点
{
公众:
typedef std::向量节点列表;
typedef node_list::const_迭代器const_迭代器;
const_迭代器begin()const{return children_uu.begin();}
const_迭代器end()const{return children_uu.end();}
私人:
节点\列出子节点\子节点;
}
这允许您更改基础容器类型,而无需更改迭代
节点
子节点的代码

这样做的缺点是它会泄漏实现细节,因为使用
节点::常量迭代器的代码知道它是一个随机访问迭代器(因为
std::vector::常量迭代器
是一个随机访问迭代器),因此,您可能很难切换到不支持随机访问的容器


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

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

这不是对您的问题的直接回答,而是另一种方法。您可以注册回调函数,而不是让客户机代码运行该节目。例如:

// 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);
}
//从此类派生以创建访问者
类抽象访问者
{
公众:
虚空运算符()(常数T&)=0;
};
//您的递归数据结构类
类MyClass
{
公众:
空走(抽象和虚拟)常数
{
//调用客户端回调
v(有效载荷);
对于(std::vector::const_迭代器it=children.begin();
it!=children.end();++it)
{
//重现
它->步行(v);
}
}
私人:
T payload;//与类关联的某种有效负载
性病媒儿童;
};
//您可以使用不同的访问者类来做不同的事情
类MyVisitor:公共抽象访问者
{
公众:
虚空运算符()(常量T&T)
{
//用t做点什么
}
}
int main()
{
MyClass m;
MyV;
...
m、 步行(五);
}

完成封装

访客模式!:-O(嗯,至少是有关它的)。个人来说,在C++中,我希望<代码> Wave>代码>是一个带有Frimor参数的函数模板。如果做不到这一点(因为有时您不希望在接口边界使用模板),我希望用户数据指针与我的函数指针一起使用,或者是一个带有虚拟函数的接口。否则,walk仅限于除了全局状态之外没有任何状态的操作,并且不返回任何值(因为它是空的)。也就是说,设计糟糕;-)@史提夫:是的,绝对是;理想情况下,您希望能够为它提供函子。但是对于上面的代码片段来说,这似乎有点复杂
std::function
会起作用,带有虚拟
运算符()的访问者基类也会起作用。@James:这是一个C++0x模板吗?如果node_list是指向节点的指针向量,并且我希望客户端只有指向常量节点的指针,这也会起作用吗?“code知道这是一个随机访问迭代器”有趣的点,但同样地,代码也知道它是一个向量::常量迭代器。但是,不用思考就使用
操作符+
要比不用思考就将迭代器分配给
向量::常量迭代器
要容易得多,而不用思考就将迭代器分配给
节点::常量迭代器
。我想知道是否有迭代器适配器除了“降级”迭代器包装到特定类别之外什么都不做的情况。然后您可以返回
make\u forward\u iterator(children\u.begin())
,或者类似的内容。@Steve:由于类别是迭代器类型的一部分,因此您必须在typedef中进行转换。我认为通过使用
模板类forward\u iterator\u wrapper:private realiterator{},您可以很容易地做到这一点。可能有问题,;我还没有深入考虑过这件事。