Поддержка my_2D_Array [x] [y] (двойной оператор []) для константного 2D-массива;Не могу заставить вещи работать - PullRequest
0 голосов
/ 18 января 2012

Я создаю класс двумерного массива в C ++.Все работает отлично для недорогого массива.Мне еще предстоит найти хорошее объяснение константных функций, и мне кажется, что они все время возятся, пока они не работают.Однако теперь я нахожусь в тупике.

Я не понимаю, как поддерживать 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 << "\n\n[ PAUSE: Press ENTER to exit the program. ]";
    std::cin.get();
    return 0;
}

Когда я пытаюсь получить доступ к carr [x] [y], он выдает ошибку, что и следовало ожидать.Поэтому я включил const и неконстантную перегрузку operator [] в Array2D

Array2D.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 состоит в том, чтобы передать обратночто-то для обработки второго оператора [] без необходимости передавать обратно массив.

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];
}

1 Ответ

0 голосов
/ 18 января 2012

К сожалению, я думаю, вам понадобятся две версии Row: одна для const Array и одна для неконстантных.Так же, как стандартные контейнеры имеют iterator с и const_iterator с.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...