C++ 自定义迭代器和范围问题

标签 c++ for-loop iterator polymorphism

假设我有一个界面。接口(interface)具有开始和结束函数,因为派生类必须实现范围功能。用户只会使用接口(interface),不会知道派生类的实现。 我不能对所有派生类使用相同的迭代器(更具体地说,operator++() 是不同的)所以我必须创建一个抽象基迭代器类。

class BaseIterator
{
    //...
public:
    virtual Type operator*()
    {
        //Implementation
    }

    virtual bool operator!=(const BaseIterator&)
    {
        //Implementation
    }

    virtual BaseIterator& operator++() = 0; 
}

//Interface
struct Interface
{
    //other pure virtual functions

    virtual BaseIterator& begin() = 0;
    virtual BaseIterator& end() = 0;
}

在继承我正在使用的接口(interface)的具体类中,假设其中一个是 A 类,每个类都有自己的迭代器,它继承自 BaseIterator,并使用它来实现开始和结束函数。

class A : public Interface
{
//...

class AIterator : public BaseIterator
    {
        AIterator& operator++()
        {
            //...
        }
    }

    public:

    AIterator& begin() 
    {
        //...
    }

    AIterator& end() 
    {
        //...
    }


}

其他派生类也类似。当我尝试将 for range 循环与多态类型一起使用时,就会出现问题。例如 (*)

Interface* c = Interface::makeA(); //assume for simplicity that there is static function in "Interface"

for(auto el : *c)
{
    //do something with el
}

由于纯虚函数运算符++(),我得到一个无法实例化抽象类的错误。我认为发生这种情况的原因在于 for-range 循环的实现,它等效于以下内容:

auto && __range = range_expression ;
for (auto __begin = __range.begin(), __end = __range.end(); __begin != __end; ++__begin) {
   range_declaration = *__begin;
   loop_statement;
}

我认为问题在于“auto__begin == __range.begin()”。 begin 返回对 BaseIterator 的引用,由于自动类型推导,它被删除,最终使 __begin 成为 BaseIterator 类型,这是抽象类,无法实例化。 我知道这种行为可以用 Java 实现。 我在这里错过了什么吗?如果没有,您将如何实现它但保留 (*) 中的功能?

最佳答案

请张贴一个完整的例子来说明 future 的问题。我猜你面临的错误类似于 ( https://wandbox.org/permlink/PKop4WMbpuygHoes )

prog.cc:73:19: error: cannot allocate an object of abstract type 'BaseIterator'
   73 |     for(auto&& i: a) {
      |                   ^
prog.cc:3:7: note:   because the following virtual functions are pure within 'BaseIterator':
    3 | class BaseIterator
      |       ^~~~~~~~~~~~
prog.cc:19:27: note:     'virtual BaseIterator& BaseIterator::operator++()'
   19 |     virtual BaseIterator& operator++() = 0;
      |                           ^~~~~~~~
prog.cc:73:19: error: cannot declare variable '__for_begin ' to be of abstract type 'BaseIterator'
   73 |     for(auto&& i: a) {
      |                   ^
prog.cc:73:19: error: cannot allocate an object of abstract type 'BaseIterator'
prog.cc:73:19: error: cannot declare variable '__for_end ' to be of abstract type 'BaseIterator'

问题很明显,因为 for 循环试图将 begin() 的返回值分配给局部变量,但它不能。

C++ 不是 Java。基于范围的for循环要么调用begin/end成员函数,要么调用自由函数,因此不需要接口(interface)获取迭代器。您的类只需实现这些功能,基于范围的 for 就可以工作。除此之外,在基类中使用 operator!= 可以比较两个不同子类型的迭代器。要检查这一点,您需要使用 dynamic_cast 来检查类型。您还需要在实现中降低参数,这显然不是一个好的设计。

对于 C++ 中的这类问题,继承并不是那么突出,首选使用模板的通用代码,例如在STL中。由于迭代器类型是模板参数,所有算法都将使用兼容的迭代器而无需继承。

这是一个使用简单的 Range 类作为迭代器容器的示例: #包括

struct Range;

struct Iterator {
    Range const* r;
    int current;

    Iterator(Range const* x, int c) : r(x), current(c) {}

    Iterator& operator++() {
        ++current;
        return *this;
    }

    int const& operator*() const {
        return current;
    }
};

bool operator==(Iterator const& x, Iterator const& y) {
    return x.current == y.current;
}

bool operator!=(Iterator const& x, Iterator const& y) {
    return !(x == y);
}

struct Range {
    int min;
    int max;

    Iterator begin() const {
        return Iterator(this, min);
    }

    Iterator end() const {
        return Iterator(this, max+1);
    }
};


int main() {
    Range r{-5, 5};
    for(auto&& i: r) {
        std::cout << i << std::endl;
    }
}

这是一个简化且不完整的示例,仅用于展示如何使其与基于范围的 for 循环一起使用。如果要实现符合标准库中迭代器的迭代器,则需要添加一堆成员函数和类型定义。应该有很多关于如何编写这些迭代器的信息。

PS:如果您决定对接口(interface)使用类似 Java 的方法,请不要忘记为您的接口(interface)提供一个(公共(public)或 protected )虚拟析构函数并将复制构造函数声明为 delete 以防止对象切片.

关于C++ 自定义迭代器和范围问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58347228/

相关文章:

c++ - 哨兵和结束迭代器有什么区别?

c++ - 指向指针的 const 问题

c++ - template<> 用于成员枚举的显式特化

linux - for i in {00..03} 不适用于 nohup

java - 在 for 循环中使用数组长度不安全

c++ - 有什么方法可以检查迭代器是否有效?

c++ - 我如何找出软件输出的打印位置?

c++ - 函数调用在反汇编代码中似乎无法正常工作

c++ - "for (const auto &s : strs) {} "是什么意思?

arrays - 迭代 `setindex!`