3

I'm having trouble with overloading operator() with a const version:

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

This gives me the following output:

  • NONconst-version was called - - NONconst-version was called - A(1,1)=8.8
  • NONconst-version was called - Error: you may only alter the first row of the matrix.

How can I achieve that C++ call the const-version of operator()? I am using GCC 4.4.0.

1
  • I'd like to be able and modify my matrix entries, but only some. Commented Mar 14, 2010 at 1:11

5 Answers 5

3

The overloading looks fine but you never call it on a const object. You can try this:

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

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

This gives you:

 - const-version was called - A(1,1)=0
Sign up to request clarification or add additional context in comments.

3 Comments

Thanks! It's unfortunate in my opinion that C++ doesn't call the const-methods "by default" even on non-const objects. I would put that on the wish list.
If that were the case, when would the non-const methods be called? You could always remove the non-const overload, and it would call the const one even on non-const objects.
The would be called when a non-const operation needs to be performed. Yes, I can remove the non-const overloaded method, but since I also sometimes want to assign something to a matrix element that reduces the functionality. Thanks for the advice.
2

The object you are calling the method on must be const, e.g.

cout << "A(2,2)=" << (*static_cast<const Matrix*>(&A))(2,2) << endl;

10 Comments

Hmm, that sort of contradicts the "use is simple"-paradigm which I wanted to have using that operator...
Well, this should almost never be necessary; your const and non-const versions should be very close in behavior, with the possible exception of a non-const version possibly resizing the container for you. If you are doing something so completely different in the two versions that you need to cast between them, consider making different methods instead.
I wanted to have this for banded matrices, where I can call the non-const operator() only when I'm near the diagonal of the matrix (otherwise the elements are not stored and implicitly zero, so the operator needs to throw an error). I will do different methods now.
That is what const_cast<> is for. Edit - and you shouldn't do anything with pointers.
@James - I disagree; const_cast's are more powerful than static_casts (or my more preferred one, currently-not-in-the-standard, implicit_cast), and should not be used a safe operation like adding constness. Seeing a const_cast in code means there is a large design flaw; using it to add constness severely waters down this meaning.
|
1

Generally, you can't call a const or non-const version of a function depending on what you do with the return value. If you want to emulate similar functionality, you can try returning some proxy that will switch the behaviour depending on what you do with it:

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

Assuming check() is your check for legal mutation (could be integrated in index()) and index() and const_index() are methods in Matrix that give a reference or const reference to a particular place.

2 Comments

OK, advanced... will think about it :-)
Actually, this doesn't compile : operator double() { return m.const_index(x, y); } operator const double&() Whereas this compile adding the const at the end of the second line: operator double() { return m.const_index(x, y); }; operator const double&() const;
0

Use const_cast<>() or make your instance const.

I'm guessing maybe you want to be sure the operator returns a const double? Maybe you should just provide the const version, not the other one.

Comments

0

You have different methods with different functionality, so give them different names. Then you don't need to have a const object just to call what you want.

You can still make operator() const call the alternative function in case you do happen have a const object. But the alternative functionality should be put in a function with a descriptive name.

As for getting a const handle to an object, use static_cast< const Matrix & >( A ).

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.