在const 2D数组上支持my_2D_Array[x][y](双运算符[]);无法使事情正常工作

Supporting my_2D_Array[x][y] (double operator[]) on a const 2D array; Cannot get things working

本文关键字:2D 工作 常工作 运算符 数组 Array my 支持 const      更新时间:2023-10-16

我正在C++中创建一个2D数组类。对于非成本数组,一切都很好。我还没有找到一个很好的解释const函数,似乎总是在摸索,直到它起作用。然而,现在,我陷入了困境。

我是否不了解如何支持const对象?除了创建第二个Row类,我想不出解决方案,而且这个解决方案似乎没有必要。

main.cpp

#include "Array2D.h"
int main()
{
    int const x(1), y(1);
    Array2D<int> arr(3, 3);
    int value(0);
    for (int row(0); row < 3; ++row)
        for (int column(0); column < 3; ++column)
            arr[row][column] = ++value;
    std::cout << arr[x][y];
    Array2D<int> const carr(arr);
    //Everything's fine up to here

    std::cout << carr[x][y]; //Error
    std::cout << "nn[ PAUSE: Press ENTER to exit the program. ]";
    std::cin.get();
    return 0;
}

当我试图访问carr[x][y]时,它会抛出一个错误,这是意料之中的。所以我在Array2D 中包含了运算符[]的常量和非常量重载

阵列2D.h

    template <typename T>
    class Array2D
    {
    public:
       //===============
      //CONSTRUCTORS
     //
        inline Array2D();
        inline Array2D(int rows, int columns = 0);
        inline Array2D(Array2D const &array2D);
       //===============
      //OPERATORS
     //
        inline Array2D<T>& operator=(Array2D const &array2D);
        inline Row<T> operator[](int index);
        inline Row<T> const operator[](int index) const;
       //===============
      //GETTERS
     //
        inline int getRows() const { return _rows; }
        inline int getColumns() const { return _columns; }
       //===============
      //SETTERS
     //
        inline void setRows(int rows);      //May result in loss of data
        inline void setColumns(int columns); //May result in loss of data
    //OTHER
        inline T& select(int row, int column);
        inline T const & select(int row, int column) const;
       //===============
      //DESTRUCTOR
     //
        inline ~Array2D(){}
    private:
       //===============
      //DATA
     //
        Array<T>    _array;     //Two dimensional array in row-major order
        int         _rows;      //The number of rows in the array
        int         _columns;   //The number of data in each row
       //===============
      //PRIVATE FUNCTIONS
     //
        //Initializes the array with current data
        inline void initArray2D();
        //Throws exception if length is negative
        inline void checkLength(int length) const;
        //Throws exception if index is out of bounds
        inline void checkIndex(int rowIndex, int columnIndex) const;
    };
//CONSTRUCTORS
template <typename T>
Array2D<T>::Array2D() : _array(0), _rows(0), _columns(0)
{ initArray2D(); }
template <typename T>
Array2D<T>::Array2D(int rows, int columns) : _array(0), _rows(rows), _columns(columns)
{
    checkLength(rows);
    checkLength(columns);
    initArray2D();
}
template <typename T>
Array2D<T>::Array2D(Array2D const &array2D)
{ (*this) = array2D; }
//OPERATORS
template <typename T>
Array2D<T>& Array2D<T>::operator=(Array2D const &array2D)
{   
    _rows = array2D._rows;
    _columns = array2D._columns;
    initArray2D();
    _array = array2D._array;
    return *this;
}
template <typename T>
Row<T> Array2D<T>::operator[](int index)
{
    return Row<T>(*this, index);
}
template <typename T>
Row<T> const Array2D<T>::operator[](int index) const
{
    Row<T> const toReturn(*this, index);;
    return toReturn;
}
//SETTERS
template <typename T>
void Array2D<T>::setRows(int rows)
{
    _array.setLength(rows * _columns);
}
template <typename T>
void Array2D<T>::setColumns(int columns)
{
    Array newArray(_rows * columns);
    //This will prevent truncated columns from being copied over
    int lesserColumn(columns > _columns ? _columns : columns);
    for (int row(0); row < _rows; ++row)
        for (int column(0); column < lesserColumn; ++column)
            newArray[row][column] = _array[row][column];
    _array = newArray;
}
//OTHER
template <typename T>
T& Array2D<T>::select(int row, int column)
{
    checkIndex(row, column);
    return _array[(row * column) + column];
}
template <typename T>
T const & Array2D<T>::select(int row, int column) const
{
    checkIndex(row, column);
    return _array[(row * column) + column];
}

// PRIVATE \
template <typename T>
void Array2D<T>::initArray2D()
{
    _array = Array<T>(_rows * _columns);
}
template <typename T>
void Array2D<T>::checkLength(int length) const
{
    if (length < 0)
        throw Exception("LENGTH_LESS_THAN_ZERO");
}
template <typename T>
void Array2D<T>::checkIndex(int rowIndex, int columnIndex) const
{
    if (rowIndex >= _rows || columnIndex >= _columns)
        throw Exception("INDEX_LARGER_THAN_UPPER_BOUND");
    if (rowIndex < 0 || columnIndex < 0)
        throw Exception("INDEX_SMALLER_THAN_LOWER_BOUND");
}

const函数似乎是有序的,但是当它试图创建Row对象(在下一段中解释)时会出现问题,因为它期望Array2D&,但是在const函数中,它传递const Array2D&,这自然不起作用。

Row对象的思想是返回一些东西来处理第二个[]运算符,而不必返回数组。

第h行

template <typename T>
class Array2D;
template <typename T>
class Row
{
public:
   //==============
  //CONSTRUCTOR
 //
    inline Row(Array2D<T> &array2D, int row);
   //==============
  //OPERATORS
 //
    //The index will be validated by Array2D
    inline T& operator[](int column);
    inline T const & operator[](int column) const;
private:
   //==============
  //Data
 //
    Array2D<T>& _array2D;   //Source array
    int         _row;       //The row index
};
template <typename T>
Row<T>::Row(Array2D<T> &array2D, int row) : _array2D(array2D), _row(row)
{   }
template <typename T>
T& Row<T>::operator[](int column)
{
    return _array2D.select(_row, column);
}
template <typename T>
T const & Row<T>::operator[](int column) const
{
    return _array2D.select(_row, column);
}

这是Array.h供参考

#pragma once
#include "Exception.h"
template <typename T>
class Array
{
public:
   //===============
  //CONSTRUCTORS
 //
    inline Array();
    inline Array(int length, int startIndex = 0);
    inline Array(Array const &copy);
   //===============
  //OPERATORS
 //
    inline Array& operator=(Array const &copy);
    inline T& operator[](int index);
    inline T const & operator[](int index) const;
   //===============
  //GETTERS
 //
    inline int getStartIndex() const { return _startIndex; }
    inline int getLength() const { return _length; }
   //===============
  //SETTERS
 //
    inline void setStartIndex(int index);
    inline void setLength(int length);
   //===============
  //DECONSTRUCTOR <coolface.jpg>
 //
    inline ~Array();
private:
   //===============
  //DATA
 //
    T*  _array;         //Pointer to array of type T
    int _length;        //Length of the array
    int _startIndex;
   //===============
  //PRIVATE FUNCTIONS
 //
    //Initializes the array with current LENGTH
    inline void init();
    //Throws exception if length is less than zero
    inline void checkLength(int length) const;
    //Throws exception if index is out of bounds
    inline void checkIndex(int index) const;
    //Copies contents of SOURCE to DESTINATION
    inline void copyArray(T * destination, T * source, int lastIndex);
};
//CONSTRUCTORS
template <typename T>
Array<T>::Array() : _array(0), _length(0), _startIndex(0) 
{ init(); }
template <typename T>
Array<T>::Array(int length, int startIndex = 0) : _array(0), _length(length), _startIndex(startIndex)
{
    checkLength(length);
    init();
}
template <typename T>
Array<T>::Array(Array const &copy)
{ (*this) = copy; }
//OPERATORS
template <typename T>
Array<T>& Array<T>::operator=(Array const &copy)
{
    _length = copy._length;
    _startIndex = copy._startIndex;
    init();
    copyArray(_array, copy._array, _length);
    return *this;
}
template <typename T>
T& Array<T>::operator[](int index)
{
    checkIndex(index);
    return _array[index - _startIndex];
}
template <typename T>
T const & Array<T>::operator[](int index) const
{
    checkIndex(index);
    return _array[index - _startIndex];
}
//SETTERS
template <typename T>
void Array<T>::setStartIndex(int index)
{ _startIndex = index; }
    // ! WARNING: Setting length to a lower value than current will result in lost data
template <typename T>
void Array<T>::setLength(int length)
{
    checkLength(length);
    T* oldArray(_array);
    int oldLength(_length);
    _length = length;
    init();
    int lastIndex(oldLength < _length ? oldLength : _length);
    copyArray(_array, oldArray, lastIndex);
    delete [] oldArray;
}
//DECONSTRUCT <coolface.jpg>
template <typename T>
Array<T>::~Array()
{
    delete [] _array;
}
// PRIVATE \
template <typename T>
void Array<T>::init()
{
    _array = new T[_length];
}
template <typename T>
void Array<T>::checkLength(int length) const
{
    if (length < 0)
        throw Exception("LENGTH_LESS_THAN_ZERO");
}
template <typename T>
void Array<T>::checkIndex(int index) const
{
    if (index - _startIndex >= _length)
        throw Exception("INDEX_LARGER_THAN_UPPER_BOUND");
    if (index - _startIndex < 0)
        throw Exception("INDEX_SMALLER_THAN_LOWER_BOUND");
}
template <typename T>
void Array<T>::copyArray(T * destination, T * source, int lastIndex)
{
    while (lastIndex--)
        destination[lastIndex] = source[lastIndex];
}

遗憾的是,我认为您需要两个版本的Row:一个用于const Array,一个用于非常数。就像标准容器有iterator s和const_iterator s一样。