【问题标题】:Wrong operator() overload called调用了错误的 operator() 重载
【发布时间】:2011-02-06 09:19:36
【问题描述】:

我正在编写一个矩阵类,并且两次重载了函数调用运算符。矩阵的核心是一个二维双数组。我正在使用从 Windows 控制台调用的 MinGW GCC 编译器。

第一个重载意味着从数组中返回一个双精度值(用于查看元素)。 第二个重载旨在返回对数组中某个位置的引用(用于更改该位置中的数据。

double operator()(int row, int col) const ; //allows view of element

double &operator()(int row, int col); //allows assignment of element

我正在编写一个测试例程,发现永远不会调用“查看”重载。由于某种原因,当使用以下 printf() 语句时,编译器“默认”调用返回引用的重载。

fprintf(outp, "%6.2f\t", testMatD(i,j));

我知道我编写自己的矩阵类而不使用向量和使用 C I/O 函数进行测试是在侮辱众神。来世会受到彻底的惩罚,这里不用做。

最后我想知道这里发生了什么以及如何解决它。我更喜欢使用看起来更简洁的运算符重载而不是成员函数。

有什么想法吗?

矩阵类:无关代码省略。


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

测试程序:省略无关代码。

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
}

【问题讨论】:

  • 如果这是 C++,应该像这样编程。使用std::vector不是手动内存管理。使用fstream 而不是fopen/fclose(提示:缺少后者)。另外,有一个get 函数很奇怪,将它用于一个重载,然后对第二个重载不做任何事情(如果我没看错的话,改变行为。)

标签: c++ debugging gcc matrix operator-overloading


【解决方案1】:

嘿,感谢大家的帮助,我已经阅读了对类似问题的类似回复。我想我只需要再听一次,措辞略有不同。

我最初的问题是我需要两个版本的运算符重载,以根据调用该运算符的方式而不同地实现。

-当用户只需要读取一个值时,重载会将矩阵视为 const 并进行边界检查以确保用户没有尝试读取不存在的数据。 -当用户需要写入数据时,过载会相应地调整矩阵的大小。

当然这是没有意义的,因为被调用的方法不知道调用它的内容或用户尝试执行的操作(除非传入一些数据)。

我的解决方案是让操作符重载对读取和写入执行相同的操作。因此,如果用户尝试读取不存在的位置,矩阵将重新调整自身大小并返回默认值。最终,如果用户出错并读取不存在的数据,这可能会牺牲一些速度,但如果用户这样做,程序的速度是他最不担心的。所以这需要用户更加小心,我可能会添加一个数据成员,它是一个标志,指示矩阵是否已调整大小,以便用户轻松检查事情是否按预期进行。

我不会发布代码(除非有要求),因为这更像是一个高级/功能性问题,而且代码包含太多细节,可能会影响讨论。

【讨论】:

    【解决方案2】:

    正如其他人所提到的,您需要一个 const 对象来获得对 const 重载的调用。

    您在这里要做的是确保将引用转换为... 的右值。

    fprintf(outp, "%6.2f\t", double( testMatD(i,j) ) ); // double() for temporary
    

    但是,该转换是自动执行的(第 5.2.2/7 节),因此无需特别考虑。

    另外,您不妨声明两个重载以匹配。让“查看器”也返回一个引用。

    double const &operator()(int row, int col) const ; //allows view of element
    

    【讨论】:

      【解决方案3】:

      调用的重载仅由参数(包括this 参数)决定,而不是返回类型或您对返回类型的操作。

      这意味着如果您有一个非const 方法,该方法的签名与const 方法相同(除了可能的返回类型),那么const 方法将仅在调用时使用在 const 对象上或通过 const 引用或指针。当你有一个非const 对象时,非const 方法总是更好的匹配。

      通常,区分您是否实际写入返回的对象的唯一方法是返回某种代理对象,该对象具有适当的读取隐式转换和写入的重载赋值运算符。不用说,这通常会增加相当大的复杂性。

      【讨论】:

        【解决方案4】:

        只有当对象是 const 时才会调用 const 成员函数(“查看”函数):

        const Matrix testMatD(5,7);
        
        testMatD(1, 2); // will call the const member function
        

        【讨论】:

          猜你喜欢
          • 2018-05-15
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-01-25
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-05-07
          相关资源
          最近更新 更多