【问题标题】:Iterators and Const iterators in C++?C++ 中的迭代器和常量迭代器?
【发布时间】:2020-06-14 15:32:15
【问题描述】:

假设我有两个类,第一个:

class IntMatrix::iterator {
private:
    const IntMatrix *int_matrix;
    int index;

    iterator(const IntMatrix *int_matrix, int index);

    friend class IntMatrix;

public:
    int &operator*() const;

    iterator &operator++();

    iterator operator++(int);

    bool operator==(const iterator &it) const;

    bool operator!=(const iterator &it) const;

    iterator(const iterator &) = default;

    iterator &operator=(const iterator &) = default;

    ~iterator() = default;
};

第二个是:

class IntMatrix::const_iterator {
private:
    const IntMatrix *int_matrix;
    int index;

    const_iterator(const IntMatrix *int_matrix, int index);

    friend class IntMatrix;

public:
    const int &operator*() const;

    const_iterator &operator++();

    const_iterator operator++(int);

    bool operator==(const const_iterator &it) const;

    bool operator!=(const const_iterator &it) const;

    const_iterator(const const_iterator &) = default;

    const_iterator &operator=(const const_iterator &) = default;

    ~const_iterator() = default;
};

由于 99% 的实现是相同的,如何防止代码重复? 泛型在这里或继承有帮助吗?

如何实现的示例:

int &IntMatrix::iterator::operator*() const {
    return int_matrix->data[index];
}

const int &IntMatrix::const_iterator::operator*() const {
    return int_matrix->data[index];
}

另外,我希望在 main 中允许类似:

IntMatrix::iterator it;

更新: 我正在尝试通过以下方式在一个名为 Matrix 的通用类上实现给定的解决方案:(注意显示的代码在我的类中都是公开的)

template<typename T>
class iterator_impl;

template<typename T>
iterator_impl<T> begin(){
    return iterator(this, 0);
}

template<typename T>
iterator_impl<T> end(){
    return iterator(this, size());
}

template<typename T>
iterator_impl<const T> begin() const
{
    return const_iterator(this, 0);
}

template<typename T>
iterator_impl<const T> end() const
{
    return const_iterator(this, size());
}

template<typename T>
class iterator_impl{
private:
    const Matrix<T> *matrix;
    int index;
    friend class Matrix<T>;

public:
    iterator_impl(const iterator_impl &) = default;

    iterator_impl &operator=(const iterator_impl &) = default;

    ~iterator_impl() = default;

    iterator_impl(const Matrix<T> *int_matrix, int index)
            : matrix(int_matrix), index(index) {}

    iterator_impl &operator++()
    {
        ++index;
        return *this;
    }

    iterator_impl operator++(int)
    {
        iterator_impl result = *this;
        ++*this;
        return result;
    }

    bool operator==(const iterator_impl &it) const
    {
        return index == it.index;
    }

    bool operator!=(const iterator_impl &it) const
    {
        return !(*this == it);
    }

    T &operator*() const {
        if (index < 0 || index > matrix->size() - 1) {
            throw Matrix<T>::AccessIllegalElement();
        }
        return matrix->data[index];
    }
};
template<typename T>
using iterator = iterator_impl<T>;

template<typename T>
using const_iterator = iterator_impl<const T>;

我收到一些错误,例如:

在非静态成员函数之外无效使用“this” 返回迭代器(this, 0);

【问题讨论】:

  • @TedLyngmo 你能把它改成删除 IMT,这让我的事情变得非常复杂
  • 我的 Matrix 类中的迭代器代码完全损坏,我没有备份
  • 我不确定是否可以删除 IMT,因为您的迭代器要么指向 const IntMatrix,要么指向非 const IntMatrix。我现在改变了它,所以 IMT 被自动推导出来。
  • 按原样编写代码给了我:非成员函数在编写时不能有'const'限定符:const_iterator begin() const;
  • 您的代码适用于 intMatrix 而不是 Matrix

标签: c++ class generics methods iterator


【解决方案1】:

一种方法是将实现变成类模板,然后为const 和非const 实例创建别名。

另外,我希望 In main 允许以下内容: IntMatrix::iterator it;

然后你需要添加一个默认构造函数。

例子:

#include <cstddef>
#include <type_traits>

// in the .hpp file:
class IntMatrix {
private:
    int data[10];     // just an example
    size_t size = 10; // just an example

    template<typename T>
    class iterator_impl;

public:
    // two typedefs using the template:
    using iterator = iterator_impl<int>;
    using const_iterator = iterator_impl<const int>;

    const_iterator cbegin() const;
    const_iterator cend() const;
    const_iterator begin() const;
    const_iterator end() const;
    iterator begin();
    iterator end();
};

// still in the .hpp file:
template<typename T>
class IntMatrix::iterator_impl {
public:
    using matrix_type =
        std::conditional_t<
            std::is_const_v<T>,
            const IntMatrix,
            IntMatrix
        >;

private:
    matrix_type* int_matrix;
    size_t index;

    friend IntMatrix;

    iterator_impl(matrix_type* im, size_t idx) :
        int_matrix(im), index(idx)
    {}

public:
    iterator_impl() = default;                          // default constructor
    //iterator_impl(const iterator_impl&) = default;             // not needed
    //iterator_impl &operator=(const iterator_impl &) = default; // not needed
    //~iterator_impl() = default;                                // not needed

    iterator_impl &operator++() {
        ++index;
        return *this;
    }
    iterator_impl operator++(int) {
        iterator_impl old(*this);
        ++index;
        return old;
    }
    bool operator!=(const iterator_impl &it) const {
        return index != it.index || int_matrix != it.int_matrix;
    }
    bool operator==(const iterator_impl &it) const {
        return !(*this != it);
    }

    T& operator*() const {
        return int_matrix->data[index];
    }
};

// in the .cpp file:
IntMatrix::const_iterator IntMatrix::cbegin() const { return {this, 0}; }
IntMatrix::const_iterator IntMatrix::cend() const { return {this, size}; }
IntMatrix::const_iterator IntMatrix::begin() const { return cbegin(); }
IntMatrix::const_iterator IntMatrix::end() const { return cend(); }
IntMatrix::iterator IntMatrix::begin() { return {this, 0}; }
IntMatrix::iterator IntMatrix::end() { return {this, size}; }

Demo


编辑:如果Matrix本身就是一个类模板,你需要稍微改变一下迭代器。

#include <cstddef>
#include <type_traits>

// in the .hpp file:
template<typename T>
class Matrix {
private:
    T data[10];       // just an example
    size_t size = 10; // just an example

    template<typename I>
    class iterator_impl;

public:
    // two typedefs using the template:
    using iterator = iterator_impl<T>;
    using const_iterator = iterator_impl<const T>;

    auto cbegin() const;
    auto cend() const;
    auto begin() const;
    auto end() const;
    auto begin();
    auto end();
};

// still in the .hpp file:
template<typename T>
template<typename I>
class Matrix<T>::iterator_impl {
public:
    using value_type = std::remove_const_t<I>;

    using matrix_type =
        std::conditional_t<
            std::is_const_v<I>,
            const Matrix<value_type>,
            Matrix<value_type>
        >;

private:
    matrix_type* matrix;
    size_t index;

    friend Matrix;

    iterator_impl(matrix_type* im, size_t idx) :
        matrix(im), index(idx)
    {}

public:
    iterator_impl() = default;                          // default constructor

    iterator_impl& operator++() {
        ++index;
        return *this;
    }
    iterator_impl operator++(int) {
        iterator_impl old(*this);
        ++index;
        return old;
    }
    bool operator!=(const iterator_impl &it) const {
        return index != it.index || matrix != it.matrix;
    }
    bool operator==(const iterator_impl &it) const {
        return !(*this != it);
    }

    I& operator*() const {
        return matrix->data[index];
    }
};

// still in the .hpp file
template<typename T> auto Matrix<T>::cbegin() const { return const_iterator{this, 0}; }
template<typename T> auto Matrix<T>::cend() const { return const_iterator{this, size}; }
template<typename T> auto Matrix<T>::begin() const { return cbegin(); }
template<typename T> auto Matrix<T>::end() const { return cend(); }
template<typename T> auto Matrix<T>::begin() { return iterator{this, 0}; }
template<typename T> auto Matrix<T>::end() { return iterator{this, size}; }

Demo

【讨论】:

  • 在这里继承不是最好的选择吗?
  • @smith 有些人更喜欢继承和铸造这种东西,但我个人不喜欢。我不能说一个比另一个更好。
  • 我有点困惑,我应该更改 .h 文件中的任何内容还是 .cpp 文件中的所有更改?
  • 如果您愿意,您可以在 cpp 文件中执行类模板函数的实现,但是您必须显式地实例化两个版本 - 当您将它用于 int 和仅限const int。但是,如果您也将 Matrix 类变成模板,这将更加困难。我会坚持在头文件中包含完整的iterator_impl 实现。
  • 当我尝试访问数据时,我收到错误说它是私有的,而且我的教授说永远不要在 .h 文件中使用 using,他会减少分数,如何防止这种情况发生?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-07
  • 1970-01-01
  • 1970-01-01
  • 2013-12-16
相关资源
最近更新 更多