Const operator overloading problems in C++
Solution 1
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
Solution 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;
Solution 3
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.
steigers
Updated on July 01, 2022Comments
-
steigers almost 2 years
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.
-
steigers about 14 yearsI'd like to be able and modify my matrix entries, but only some.
-
steigers about 14 yearsHmm, that sort of contradicts the "use is simple"-paradigm which I wanted to have using that operator...
-
Todd Gardner about 14 yearsWell, 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.
-
steigers about 14 yearsThanks! 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.
-
Todd Gardner about 14 yearsIf 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.
-
steigers about 14 yearsThe 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.
-
steigers about 14 yearsI 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.
-
steigers about 14 yearsOK, advanced... will think about it :-)
-
Potatoswatter about 14 yearsThat is what
const_cast<>
is for. Edit - and you shouldn't do anything with pointers. -
Todd Gardner about 14 yearsNo, it isn't. const_cast is for removing constness, not adding it.
-
Potatoswatter about 14 yearsOops,
static_cast
is weaker and therefore better, but still better to avoid referencing+dereferencing. -
Todd Gardner about 14 yearsA good compiler would probably remove that; but the code would be clearer without pointers. I only used them because I couldn't remember if straight references would compile, while I knew the pointers would. If I would probably write this as implicit_cast<const Matrix&>(A)(2,2)
-
James McNellis about 14 years@Todd:
const_cast
can be used both to add and to removeconst
andvolatile
qualifiers. It's just not generally used for adding the qualifiers since they can be added without using it. @Potatoswatter: Why do you thinkstatic_cast
is preferable in this case? Doesn'tconst_cast
more clearly represent the intent? (I guess I'm not sure why you thinkstatic_cast
is "weaker;" the two casts are complementary in nature). @Todd again: I like the use ofimplicit_cast
for this. -
Todd Gardner about 14 years@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.
-
steigers about 14 yearsI don't like *_cast at all. Always got away without using it so far.
-
doizuc about 10 yearsActually, 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;