简体   繁体   中英

Wrong operator() overload called

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM