我正在尝试为二叉树制作3个迭代器(3个类)(每个遍历一个),我希望它们共享相同的基类。
class BinaryTree
{
class Iterator
{
virtual Iterator operator++() = 0;
}
class Iterator1 : public Iterator
{
}
class Iterator2 : public Iterator
{
}
class Iterator3 : public Iterator
{
}
}
我已经实现了他们在Iterator类中共享的方法。唯一不同的方法是构造函数和前缀++的重载。
我的想法是让重载的operator ++成为一个虚函数,以便它可以被Iterator1,2和3覆盖,因为我想使用这样的迭代器:
for(BinaryTree::Iterator it = t.begin(Preorder); it != t.end(); it++)
{
// do stuff
}
我习惯了Java,在那里你可以创建一个抽象类型的对象,但是将它实例化为另一种类型。
问题是在C ++中cannot allocate an object of abstract type
。
begin
方法是使用工厂模式生成的:它返回Iterator 1,2或3类型的对象。
有没有办法解决这个问题,以保持与for
相同的语法?
答案 0 :(得分:3)
请记住,在Java中,您不直接处理对象,而是指向对象。在C ++中,当您声明类型为x
的变量时,您有x
,而不是x
派生的变量。如果要使用多态,则需要引用(x&
)或指针(x*
,shared_ptr<x>
,unique_ptr<x>
,...)。
所以,你的for循环应该是
for(BinaryTree::Iterator& it = t.begin_preorder(); it != t.end; it++)
BinaryTree::begin_preorder()
应返回BinaryTree::Iterator#
,其中#
是与正确迭代器对应的数字。它不能返回BinaryTree::Iterator
,因为你不能拥有那种类型的对象(它是抽象的)。 如果返回BinaryTree::Iterator&
,则您将无法返回在函数中创建的(本地)对象,因为该函数退出后该对象将不再存在。如果返回引用,则引用所指向的实际对象必须缓存在t
对象中。
我假设你想使用多态,因为在编译时你不一定知道你要使用哪个迭代器(因为如果你在编译时知道,那么多态是不必要的)。
如果您只想在for循环中保存一些输入并且不需要多态:
for(auto it = t.begin_preorder(); it != t.end; it++)
会正常工作。那么您不需要基类或虚拟成员函数。
答案 1 :(得分:2)
您需要使用具有多态类型的指针或引用:
struct Test {
struct Iterator {
virtual Iterator &operator++() = 0;
virtual ~Iterator() = 0;
};
struct Forward : public Iterator {
int i;
virtual Iterator &operator++()
{
i++;
return *this;
}
};
Iterator *forward()
{
return new Forward();
}
};
int main()
{
Test t;
Test::Iterator &it = *t.forward();
++it;
delete ⁢
}
通过将多态隐藏在非多态包装类(pimpl或handle-body惯用法)后面,可以使这些事情更像常规迭代器:
class IteratorImpl {
virtual IteratorImpl *clone() = 0;
virtual void increment() = 0;
virtual ~IteratorImpl() = 0;
};
// concrete subclasses
class iterator {
std::unique_ptr<IteratorImpl> impl;
public:
// operator++() based on IteratorImpl::increment
// copy constructor based on IteratorImpl::clone
};