我已经多次遇到过这个问题,想知道是否有一个简单的方法或模式可以解决它。
想象一下一个树结构,其中每个节点都包含一个指向子节点的STL容器(向量)。我希望客户端代码能够遍历这个树,并遍历子容器以访问其他部分。
我的问题是我想维护我的节点的封装,同时让客户轻松查看该节点的所有子节点。我还想确保如果客户端获取树中根节点的const引用,那么对树的后续部分的所有访问也都是const。
我应该尝试为我的节点类型创建一个迭代器类,有一个节点方法返回向量迭代器,还是有一个我丢失的更优雅的模式?
编辑:我想再次强调,虽然我看到了一些好主意,但我有 指针 的容器到其他节点。返回vector<node *>::const_iterator
不会阻止客户端在节点上调用非const方法。它只保护指针本身不会指向不同的对象。
答案 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)
对于遍历整个树,您必须创建自己的迭代器类,只需遍历子项,就可以安全地返回向量迭代器。