Как перегрузить оператор индекса массива для класса-оболочки двумерного массива?

#define ROW 3
#define COL 4

class Matrix
{
   private:
      int mat[ROW][COL];  
    //.....
    //.....

};

int main()
{
  Matrix m;
  int a = m[0][1]; //  reading
  m[0][2] = m[1][1]; // writing
} 

Я думаю, что напрямую перегрузить нельзя [][] .

Я думаю, что мне нужно сделать это косвенно, но как это реализовать?


person Ashish    schedule 28.12.2009    source источник


Ответы (2)


Более простое решение — использовать оператор(), так как он позволяет использовать несколько параметров.

class M
{
    public:
       int& operator()(int x,int y)  {return at(x,y);}
    // .. Stuff to hold data and implement at()
};


M   a;
a(1,2) = 4;

Простой способ заключается в том, что первый оператор [] возвращает промежуточный объект, а второй оператор [] возвращает значение из массива.

class M
{
    public:
    class R
    {
         private:
             friend class M; // Only M can create these objects.
             R(M& parent,int row): m_parent(parent),m_row(row) {}
         public:
              int& operator[](int col) {return m_parent.at(m_row,col);}
         private:
              M&  m_parent;
              int m_row;
    };

    R operator[](int row) {return R(*this,row);}

    // .. Stuff to hold data and implement at()
};

M   b;
b[1][2] = 3;   // This is shorthand for:

R    row = b[1];
int& val = row[2];
val      = 3;
person Martin York    schedule 28.12.2009
comment
Сможет ли хороший оптимизатор изменить прокси-версию таким же эффективным кодом, как operator()? - person GManNickG; 28.12.2009
comment
Это зависит от компилятора. Но мне нравится делать использование моих объектов максимально интуитивным. Чем более естественным кажется использование объекта, тем меньше вероятность ошибок. Я лично предпочитаю прокси, но для этой ситуации их шесть из одного полдюжины другого, и я не могу однозначно сказать, что один лучше другого. - person Martin York; 28.12.2009
comment
Да, я всегда использовал operator(), но думаю, что на этот раз я буду использовать прокси (я пишу игровые движки) и посмотрю, не вызовет ли это каких-либо проблем. Я не могу себе представить, что компилятору будет слишком сложно сделать это так же быстро, поскольку он будет иметь полное определение всех операторов. - person GManNickG; 28.12.2009
comment
должно быть: int& оператор () (int x, int y) - person dvide; 28.12.2009
comment
Так впечатлен! Я только что получил это для работы с шаблонным классом (для операций с матрицами). У меня была одна небольшая синтаксическая ошибка, потому что я пытался вернуть R& из R::operator[] вместо самого R. Однажды я поймал, что это работает без проблем. Очень гладко! (теперь посмотрим, смогу ли я перегрузить адрес оператора, чтобы вернуть вектор в матрице. :P - person Troy Chard; 04.03.2011

Поскольку вы хотите хранить свои элементы в массивах фиксированного размера, это будет довольно просто:

#define ROWS 3
#define COLS 4

typedef int row_type[COLS];

class matrix {
   row_type elements[ROWS];
public:
   ...
   row_type const& operator[](int r) const {return elements[r];}
   row_type      & operator[](int r)       {return elements[r];}
   ...
};

Это должно сработать.

Кроме того, вы можете заменить #define соответствующими константами или использовать параметры шаблона для типа (int) и размера (3x4), чтобы сделать ваш матричный класс более универсальным. Если вы хотите поддерживать динамические размеры, ваш оператор[] должен возвращать прокси-объекты. Это возможно, но вам, вероятно, следует предпочесть оператор() с двумя параметрами индекса для доступа к элементам.

person sellibitze    schedule 28.12.2009