抽象类作为类型,派生类作为C ++中的实例

时间:2014-06-18 13:16:17

标签: c++ inheritance tree iterator virtual

我正在尝试为二叉树制作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 typebegin方法是使用工厂模式生成的:它返回Iterator 1,2或3类型的对象。

有没有办法解决这个问题,以保持与for相同的语法?

2 个答案:

答案 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 &it;
}

通过将多态隐藏在非多态包装类(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
};