简体   繁体   English

继承抽象迭代器接口

[英]Inheriting a abstract iterator interface

I want to inherit a iterator for an container class. 我想为容器类继承一个迭代器。 It should always have the same signature independent of the actual implementation. 它应始终具有与实际实现无关的相同签名。

But I have the problem that in ContainerImpl the returned Container::Iterator from ContainerImpl::begin() slices the overridden methods from ContainerImpl::Iterator back to the ones of Container::Iterator . 但我在这个问题ContainerImpl返回的Container::IteratorContainerImpl::begin()切片从覆盖的方法ContainerImpl::Iterator返回的那些Container::Iterator

How can I force the more specific method to be used? 如何强制使用更具体的方法? Or can I rewrite my classes so that it behaves like that? 还是可以重写我的类,使其表现得像那样?

Below is a working example. 下面是一个工作示例。 It compiles at least against C++17. 它至少针对C ++ 17进行编译。

#include <tuple>

using std::tuple;

class Container {
    // some code

public:

    class Iterator {
    public:
        virtual tuple<int, int> &operator*() {};

        virtual Iterator &operator++() {};

        virtual bool operator!=(const Iterator &rhs) const {};
    };

    virtual Iterator begin() = 0;

    virtual Iterator end() = 0;
};

class ContainerImpl : public Container {
    // some code

public:

    class Iterator : public Container::Iterator {
    public:
        Iterator(ContainerImpl &containerImpl) {
            // init
        }

        Iterator() {
            // end_iterator
        }

        virtual tuple<int, int> &operator*() override {
            // impl
        };

        virtual Container::Iterator &operator++() override {
            // impl
        };

        virtual bool operator!=(const Container::Iterator &rhs) const override {
            // impl
        };
    };

    virtual Container::Iterator begin() override {
        return Iterator{*this};
    };

    virtual Container::Iterator end() override {
        return Iterator{};
    };
};


int main() {
    ContainerImpl cont{};
    for (auto &entry : cont) {
        // here Container::Iterator::operator++() is called
        // instead of ContainerImpl::Iterator::operator++()
    }
}

edit: 编辑:

Thanks! 谢谢! I read through your comments and figured out that I should try an static approach using templates. 我通读了您的评论,并发现我应该尝试使用模板的静态方法。 Performance is quite important for those iterators. 对于那些迭代器,性能非常重要。 This will need refactoring of other code where I use this code. 这将需要在我使用此代码的地方重构其他代码。 But it should be moderate. 但这应该适中。

Here is what I came up with: 这是我想出的:

#include <tuple>
#include <type_traits>

using std::tuple;

template<class SubContainer>
class Container;


template<class ContImpl>
class Iterator {
    static_assert(std::is_base_of<Container<ContImpl>, ContImpl>::value, "ContImpl not derived from Container");
public:

    tuple<int, int> &operator*();

    Iterator<ContImpl> &operator++();

    bool operator!=(const Iterator<ContImpl> &rhs) const;
};



template<class SubContainer>
class Container {
public:
    Iterator<SubContainer> begin();

    Iterator<SubContainer> end();

};

class ContImpl;

template<>
class Iterator<ContImpl> {
public:
    ContImpl &container;

    Iterator(ContImpl &container, bool is_end = false) : container(container) { init(); }

    void init() {
    }

    tuple<int, int> &operator*() {
    }

    Iterator<ContImpl> &operator++() {
    }

    bool operator!=(const Iterator<ContImpl> &rhs) const {
    }
};

class ContImpl : public Container<ContImpl> {
public:
    Iterator<ContImpl> begin() {
        return Iterator<ContImpl>(*this, false);
    }

    Iterator<ContImpl> end() {
        return Iterator<ContImpl>(*this, true);
    }
};


int main() {
    ContImpl cont{};
    for (auto &entry : cont) {
        // Iterator<ContImpl>::operator++() is called.
    }
}

If you want to dynamically abstract away the differences between, say, std::list<int> and std::vector<int> , then what you want is type erasure . 如果您想动态地抽象出例如std::list<int>std::vector<int>之间的差异,那么您想要的就是类型Erase But do note that, using things like template template parameters, it is also possible to statically abstract over containers with similar interfaces (with the same or different element types), which (if it meets your requirements) should be significantly faster. 但是请注意,使用模板模板参数之类的东西,还可以对具有相似接口(具有相同或不同元素类型)的容器进行静态抽象,这(如果满足您的要求)应该更快。

Regarding your template-based approach: while it might have value as documentation, the methods in Container are unnecessary: static polymorphism does not need any “base functions” to override. 关于基于模板的方法:虽然它可能具有文档价值,但Container中的方法是不必要的:静态多态不需要任何“基本函数”来覆盖。 If you remove them, you can do without that CRTP class entirely. 如果删除它们,则可以完全不用该CRTP类。 Then, similarly, you can replace the Iterator class template with a simple class ContImpl::iterator . 然后,类似地,您可以用简单的类ContImpl::iterator替换Iterator类模板。

Of course, at that point all that's left is the same interface compatibility as between the standard containers (which allows code like 当然,到那时,剩下的就是与标准容器之间相同的接口兼容性(它允许类似

template<template<class> class C>
C<int> makeInts(/*...*/);

void f() {
  auto d=makeInts<std::deque>(/*...*/);
  // ...
}

that I suggest above). 我在上面建议)。 The interesting exercise is to hide a different container interface behind wrapper classes or with a traits interface. 有趣的练习是在包装器类后面或使用traits接口隐藏另一个容器接口。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM