Iterator继承和继承* this

时间:2016-09-20 21:32:40

标签: c++ inheritance iterator this crtp

如何编写基类和迭代器的几个派生类?

迭代器是否必须自行返回(* this)?

到目前为止,我使用typename Xstatic_cast<X&>(*this)来允许派生类继承从基类返回自身的函数。

This看起来很难看。还有更好的方法吗?

简化代码:

#include <iterator>
#include <iostream>
template <typename T, typename X>
class BaseIterator : public std::iterator<std::input_iterator_tag, T> {
    //Not intended to be used directly.
    private:
        T* p;
    protected:
        virtual void increment(void)=0;
        virtual T* stride_index(int index)=0;
    public:
        virtual ~BaseIterator(){} //virtual destructor.
        X operator++(int) { //takes a dummy int argument
            X tmp(static_cast<X&>(*this) );
            increment();
            return tmp;
        }
        bool operator==(const X & rhs) { return p==rhs.p; }
} ;
template <typename T>
class ContiguousIterator : public BaseIterator<T, ContiguousIterator<T> > {
    private:
        T* p;
    protected:
        inline void increment(void) {++p;}
        inline T* stride_index(int index){return p + index;}
    public:
        virtual ~ContiguousIterator(){} //destructor.
        ContiguousIterator(T* x) :p(x) {}
        ContiguousIterator(const ContiguousIterator<T> & mit) : p(mit.p) {}
} ;

int main(void){
    int i[]={0,1,2,3,4,5};
    ContiguousIterator<int> itbegin(i);
    ContiguousIterator<int> it(i);
    it++;
    std::cout << "result: " << (it == itbegin) << std::endl;
}

另一种方法是忘记使用继承来编写更少的代码。只需将返回*this的函数复制并粘贴到派生类中即可。

这种替代方案似乎越来越让我接受......

1 个答案:

答案 0 :(得分:1)

通常,virtual对于像迭代器这样应该是轻量级的东西来说是很多开销。通常的方法是CRTP。这有点棘手,但看起来像这样:

template <typename T, typename X>
class BaseIterator : public std::iterator<std::input_iterator_tag, T> {
    protected:
        T* p;
        X* self() {return static_cast<X*>(this);}
        const X* self() const {return static_cast<const X*>(this);}
        BaseIterator(T* x) :p(x) {}
    public:
        X operator++(int) { //takes a dummy int argument
            X tmp(*self());
            self()->increment();
            return tmp;
        }
        bool operator==(const X & rhs) const { return p==rhs.p; }
} ;

基础通常采用派生类型,以及函数签名作为模板参数所需的任何内容。然后添加两个self()函数,它们为您提供派生类型,这意味着您实际上并不需要virtual。编译器简单地概括了所有内容。 (注意我还给了它一个理智的构造函数,并operator== const

template <typename T>
class ContiguousIterator : public BaseIterator<T, ContiguousIterator<T> > {
    public:
        typedef BaseIterator<T, ContiguousIterator<T> > parent;
        void increment(void) {++(this->p);}
        T* stride_index(int index) const {return this->p + index;}
    public:
        virtual ~ContiguousIterator(){} //destructor.
        ContiguousIterator(T* x) :parent(x) {}
        ContiguousIterator(const ContiguousIterator<T> & mit) : parent(mit.p) {}
} ;

然后派生类型只是继承正常,除非您必须使用this->来访问该成员,因为父项是模板。看到它在这里工作:http://coliru.stacked-crooked.com/a/81182d994c7edea7

这会生成一个高效的迭代器,没有开销。我相信这种技术在Boost的迭代器库中使用得相当多:http://www.boost.org/doc/libs/1_59_0/libs/iterator/doc/#new-style-iterators