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

Abstract class as a type, derived class as instance in C++

本文关键字:派生 实例 类型 c++ 抽象类      更新时间:2023-10-16

我试图为二叉树(每次遍历一个)创建3个迭代器(3个类),我希望它们共享相同的基类。

class BinaryTree
{
    class Iterator
    {
        virtual Iterator operator++() = 0;
    }
    class Iterator1 : public Iterator
    {
    }
    class Iterator2 : public Iterator
    {
    }
    class Iterator3 : public Iterator
    {
    }
}

我已经实现了它们在Iterator类中共享的方法。唯一不同的方法是构造函数和前缀++的重载。

我的想法是使重载的操作符++成为虚函数,这样它就可以被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方法使用工厂模式:它返回一个迭代器1、2或3类型的对象。

是否有任何方法来保持与for相同的语法?

请记住,在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++)

可以正常工作。那么就不需要基类或虚成员函数了。

你需要对多态类型使用指针或引用:

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,或句柄体习惯用法)后面,可以使这些东西更像常规迭代器那样工作:

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