首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >C++自定义迭代器和for-range问题

C++自定义迭代器和for-range问题
EN

Stack Overflow用户
提问于 2019-10-12 03:12:18
回答 1查看 433关注 0票数 2

假设我有一个接口。接口具有begin和end函数,因为派生类必须实现for-range功能。用户将只使用接口,而不知道派生类的实现。我不能对所有的派生类使用相同的迭代器(更具体地说,operator++()是不同的),所以我必须创建一个抽象的基迭代器类。

代码语言:javascript
复制
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;
}

在继承我使用的接口的具体类中,假设其中一个是类A,每个类都有自己的迭代器,该迭代器继承自BaseIterator,并使用它来实现begin和end函数。

代码语言:javascript
复制
class A : public Interface
{
//...

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

    public:

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

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


}

其他派生类也是如此。当我尝试对多态类型使用for range循环时,就会出现这个问题。例如(*)

代码语言:javascript
复制
Interface* c = Interface::makeA(); //assume for simplicity that there is static function in "Interface"

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

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

代码语言:javascript
复制
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的引用,由于auto类型推导被移除,最终导致__begin类型为BaseIterator,这是抽象类,不能实例化。我知道这种行为可以在Java中实现。我是不是漏掉了什么?如果没有,您将如何实现此功能,但将功能保留在(*)中?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-10-12 05:26:26

请在将来发布一个完整的例子来说明这个问题。我猜您面临的错误类似于(https://wandbox.org/permlink/PKop4WMbpuygHoes)

代码语言:javascript
复制
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成员函数,要么调用自由函数,因此不需要接口来获取迭代器。您的类只需实现这些函数,基于范围的就可以工作。除此之外,在基类中使用operator!=可以比较不同子类型的两个迭代器。要检查这一点,您需要使用dynamic_cast来检查类型。您还需要在实现中向下转换参数,这显然不是一个好的设计。

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

下面是一个使用一个简单的Range类作为容器迭代遍历的示例:

代码语言:javascript
复制
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循环一起工作。如果您想实现符合标准库中迭代器的迭代器,则需要添加一组成员函数和typedefs。应该有大量关于如何编写这些迭代器的信息。

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

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/58347228

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档