Проблемы перегрузки операторов Const в C ++ - PullRequest
3 голосов
/ 14 марта 2010

У меня проблемы с перегрузкой operator () с версией const:

#include <iostream>
#include <vector>
using namespace std;

class Matrix {
public:
    Matrix(int m, int n) { 
        vector<double> tmp(m, 0.0);
        data.resize(n, tmp);
    }
    ~Matrix() { }


    const double & operator()(int ii, int jj) const {
        cout << " - const-version was called - ";
        return data[ii][jj];
    }

    double & operator()(int ii, int jj) {
        cout << " - NONconst-version was called - ";
        if (ii!=1) {
            throw "Error: you may only alter the first row of the matrix.";
        }
        return data[ii][jj];
     }


protected:  
    vector< vector<double> > data;
};

int main() {
try {
    Matrix A(10,10);
    A(1,1) = 8.8;
    cout << "A(1,1)=" << A(1,1) << endl;
    cout << "A(2,2)=" << A(2,2) << endl;
    double tmp = A(3,3);
} catch (const char* c) { cout << c << endl; }
}

Это дает мне следующий вывод:

  • Была названа NONconst-версия - - Была названа NONconst-версия - A (1,1) = 8,8
  • Была вызвана NONconst-версия - Ошибка: вы можете изменять только первый ряд матрицы.

Как я могу добиться, чтобы C ++ вызывал const-версию operator ()? Я использую GCC 4.4.0.

Ответы [ 5 ]

3 голосов
/ 14 марта 2010

Перегрузка выглядит нормально, но вы никогда не вызываете ее для объекта const Вы можете попробовать это:

void foo(const Matrix& A) {
  cout << "A(1,1)=" << A(1,1) << endl;
}

Matrix A(10,10);
foo(A);

Это дает вам:

 - const-version was called - A(1,1)=0
2 голосов
/ 14 марта 2010

Объект, для которого вызывается метод, должен быть постоянным, например,

cout << "A(2,2)=" << (*static_cast<const Matrix*>(&A))(2,2) << endl;
1 голос
/ 14 марта 2010

Как правило, вы не можете вызвать постоянную или неконстантную версию функции в зависимости от того, что вы делаете с возвращаемым значением. Если вы хотите эмулировать аналогичную функциональность, вы можете попробовать вернуть прокси-сервер, который переключит поведение в зависимости от того, что вы с ним делаете:

class Proxy
{
  Matrix& m;
  int x, y;
public:
  ...
// mutating operations
  operator double&() { check(); return m.index(x,y); }
  double& operator=(double d) { check(); return m.index(x,y)=d; }
// ... other mutating operations (+=, ...) analogously

// nonmutating ops
  operator double() { return m.const_index(x, y); }
  operator const double&() // ... same
};

Proxy Matrix::operator(int x, int y)
{
  return Proxy(*this, x, y);
}

Предполагается, что check() - это ваша проверка на законную мутацию (может быть интегрирована в index()), а index() и const_index() - методы в Matrix, которые дают ссылку или постоянную ссылку на конкретное место.

0 голосов
/ 14 марта 2010

У вас есть разные методы с разной функциональностью, поэтому присвойте им разные имена. Тогда вам не нужно иметь const объект только для вызова того, что вы хотите.

Вы все еще можете заставить operator() const вызывать альтернативную функцию, если у вас случается объект const. Но альтернативная функциональность должна быть помещена в функцию с описательным именем.

Что касается получения дескриптора const для объекта, используйте static_cast< const Matrix & >( A ).

0 голосов
/ 14 марта 2010

Используйте const_cast <> () или сделайте ваш экземпляр постоянным.

Полагаю, может быть, вы хотите быть уверены, что оператор возвращает const double? Может быть, вы должны просто предоставить версию const, а не другую.

...