I am writing a matrix class and have overloaded the function call operator twice. The core of the matrix is a 2D double array. I am using the MinGW GCC compiler called from a windows console.
The first overload is meant to return a double from the array (for viewing an element). the second overload is meant to return a reference to a location in the array (for changing the data in that location.
double operator()(int row, int col) const ; //allows view of element
double &operator()(int row, int col); //allows assignment of element
I am writing a testing routine and have discovered that the "viewing" overload never gets called. for some reason the compiler "defaults" to calling the overload that returns a reference when the following printf() statement is used.
fprintf(outp, "%6.2f\t", testMatD(i,j));
I understand that I'm insulting the gods by writing my own matrix class without using vectors and testing with CI/O functions. I will be punished thoroughly in the afterlife, no need to do it here.
Ultimately I'd like to know what is going on here and how to fix it. I'd prefer to use the cleaner looking operator overloads rather than member functions.
Any ideas?
The matrix class: irrelevant code omitted.
class Matrix
{
public:
double getElement(int row, int col)const; //returns the element at row,col
//operator overloads
double operator()(int row, int col) const ; //allows view of element
double &operator()(int row, int col); //allows assignment of element
private:
//data members
double **array; //pointer to data array
};
double Matrix::getElement(int row, int col)const{
//transform indices into true coordinates (from sorted coordinates
//only row needs to be transformed (user can only sort by row)
row = sortedArray[row];
result = array[usrZeroRow+row][usrZeroCol+col];
return result;
}
//operator overloads
double Matrix::operator()(int row, int col) const {
//this overload is used when viewing an element
return getElement(row,col);
}
double &Matrix::operator()(int row, int col){
//this overload is used when placing an element
return array[row+usrZeroRow][col+usrZeroCol];
}
The testing program: irrelevant code omitted.
int main(void){
FILE *outp;
outp = fopen("test_output.txt", "w+");
Matrix testMatD(5,7); //construct 5x7 matrix
//some initializations omitted
fprintf(outp, "%6.2f\t", testMatD(i,j)); //calls the wrong overload
}
The const member function (the "viewing" function) will only be called if the object is const:
const Matrix testMatD(5,7);
testMatD(1, 2); // will call the const member function
The overload which is called is determined solely by the parameters (including the this
parameter) and not on the return type, or what you do with the return type.
This means that if you have a non- const
method which has a signature that is otherwise identical to a const
method (apart from possibly the return type) then the const
method will only be used when called on a const
object or through a const
reference or pointer. When you have a non- const
object, then non- const
method will always be a better match.
Typically, the only way to make the distinction on whether you actually write to the returned object is to return some sort of proxy object which has an appropriate implicit conversion for reading and an overloaded assignment operator for writing. Needless to say, this usually adds considerable complexity.
Hey thanks everybody for your help, I had read similar responses to similar questions. I guess i just had to hear it one more time worded slightly differently.
My original problem was i needed two versions of the operator overload to be implemented differently depending on how that operator was being called.
-When the user simply needed to read a value, the overload would treat the matrix as const and do bounds checking to make sure the user was not trying to read data that doesn't exist. -When the user needed to write data, the overload would resize the matrix accordingly.
of course this makes no sense as the method being called has no knowledge of what is calling it or what the user is trying to do (unless some data is passed in).
my solution was to make the operator overload execute the same for both a read and a write. thus, if the user attempts to read a location that doesn't exist, the matrix will re-size itself and return a default value. Ultimately this may sacrifice some speed if the user makes a mistake and reads data that doesn't exist, but if the user is doing that, the speed of the program is the least of his worries. so this requires that the user be a bit more careful, and i might add a data member that is a flag that indicates whether the matrix has been resized to easily allow the user to check if things went as expected.
I'm not going to post the code (unless requested) because this was more a high-level/functional problem, and the code contains so many specifics that it might cloud the discussion.
As others have mentioned, you need a const
object to get a call of a const
overload.
What you are trying to do here is ensure that the reference is transformed into an rvalue for ...
.
fprintf(outp, "%6.2f\t", double( testMatD(i,j) ) ); // double() for temporary
However, that conversion is performed automatically (§5.2.2/7) so special consideration is unnecessary.
Also, you might as well declare the two overloads to match. Make the "viewer" return a reference too.
double const &operator()(int row, int col) const ; //allows view of element
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.