如何迭代另一个类中的容器?

发布于 2024-10-02 02:05:38 字数 452 浏览 1 评论 0原文

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

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

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

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

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

I've come across this issue a few times and would like find out if there is a simple method or pattern I can use to solve it.

Imagine a tree structure where each node contains a STL container (vector) of pointers to children. I want client code to be able to traverse this tree, and iterate through the child containers to access other parts.

My problem is that I want to maintain encapsulation for my nodes while at the same time letting clients easily see all of the children for that node. I also want to make sure that if a client gets a const reference to the root node in the tree, then all access to subsequent parts of the tree are also const.

Should I try to make an iterator class for my node type, have a node method return vector iterators , or is there a more elegant pattern I'm missing?

Edit: I want to stress again that while I see some good ideas presented, I have containers of pointers to other nodes. Returning a vector<node *>::const_iterator will not prevent clients from calling non-const methods on the node. It only protects the pointers themselves from pointing at different objects.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

眼前雾蒙蒙 2024-10-09 02:05:38

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

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::const_iterator 的代码知道它是一个随机访问迭代器(因为 std::vector:: const_iterator > 是一个随机访问迭代器),因此您可能很难切换到不支持随机访问的容器。

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

Something like this is usually sufficient:

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_;
}

This allows you to change the underlying container type without changing code that iterates over a node's children.

This does have the disadvantage that it leaks an implementation detail because code that uses your node::const_iterator know that it is a random access iterator (because std::vector:: const_iterator is a random access iterator), so you might have a hard time switching to a container that didn't support random access.

If you want to be able to control the iterator category yourself, you'll probably want to create your own iterator class that provides the exact behavior you want to provide.

等待圉鍢 2024-10-09 02:05:38

这不是对您问题的直接答案,而是一种替代方法。您可以通过注册回调函子来控制反转,而不是让客户端代码运行该节目。例如:

// 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);
}

完成封装!

This isn't a direct answer to your question, but rather, an alternative approach. Rather than have the client code run the show, you could go for control inversion by registering a callback functor. For instance:

// 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);
}

Complete encaspulation achieved!

强辩 2024-10-09 02:05:38

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

For traversing the entire tree, you would have to create your own iterator class, for just traversing the children, you can safely return the vector iterators.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文