Я создаю класс двумерного массива в 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 ©);
//===============
//OPERATORS
//
inline Array& operator=(Array const ©);
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 ©)
{ (*this) = copy; }
//OPERATORS
template <typename T>
Array<T>& Array<T>::operator=(Array const ©)
{
_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];
}