2012-01-18 4 views
0

私はC++で2D配列クラスを作成しています。コストのかからない配列に対してはすべてうまく動作します。 私はまだconst関数の良い説明を見つけておらず、それがうまくいくまではいつもうんざりしているようです。しかし、今、私は邪魔しています。const 2D配列のmy_2D_Array [x] [y](double演算子[])をサポートしています。

constオブジェクトのサポート方法がわかりませんか? 2番目の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; 
} 

私はカーにアクセスしようとする[X] [Y]は予想されており、エラーをスローします。だから私はArray2Dにおけるオペレータ[]ののconstと非const過負荷

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の機能は、しかし、問題は、それが行を作成しようとしたときに発生する、ためにあるように見えますArray2D &を期待しているので、オブジェクト(次の段落で説明します)を使用しますが、const関数でconst Array2D &を渡しますが、当然動作しません。

Rowオブジェクトの考え方は、配列を渡すことなく2番目の[]演算子を処理するために何かを返すことです。 const Array用と非constのための1:

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

セットアップ作業を確実に行うことができますが、単にoperator []の代わりに 'operator()'をオーバーロードすることを考えましたか?あなたのコードは簡単で分かりやすくなります。それはどのように[Matlab](http://www.mathworks.com/help/techdoc/math/f1-85462.html)と[Blitz ++](http://www.oonumerics.org/blitz/manual/blitz02.html )は行列を索引付けするので、先例があります。 –

+0

私はあなたが何を得ているのかを見ていますが、その解決策はもっと回避策です。同様の問題が将来発生した場合、私が試みていることをどうやって行うのかを理解したいと思います。 – Rakosman

+0

@Rakosman:これは役に立ちましたか? http://ideone.com/oycrc –

答えて

0

のためですが、私はあなたがの2つのバージョンを必要とすると思います。標準コンテナと同様に、iteratorconst_iteratorがあります。

+0

これは、あなたがコメントに提供したリンクだけでなく、私が来た結論でもサポートされているようです。私のために十分な音です! – Rakosman

関連する問題