我正在编写一个矩阵类,并且已经重载了函数调用操作符两次。矩阵的核心是2D双阵列。我正在使用从Windows控制台调用的MinGW GCC编译器。
第一个重载是从数组中返回一个double(用于查看元素)。 第二个重载是为了返回对数组中某个位置的引用(用于更改该位置的数据。
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
}
答案 0 :(得分:5)
只有当对象为const时才会调用const成员函数(“查看”函数):
const Matrix testMatD(5,7);
testMatD(1, 2); // will call the const member function
答案 1 :(得分:3)
调用的重载仅由参数(包括this
参数)决定,而不是返回类型,或者您对返回类型执行的操作。
这意味着,如果您的非const
方法具有与const
方法相同的签名(除了可能的返回类型),那么const
方法仅在const
对象或const
引用或指针上调用时使用。当您拥有非const
对象时,非const
方法将始终是更好的匹配。
通常,区分是否实际写入返回对象的唯一方法是返回某种代理对象,该代理对象具有适当的隐式转换以及用于写入的重载赋值运算符。不用说,这通常会增加相当大的复杂性。
答案 2 :(得分:1)
我最初的问题是我需要两个版本的运算符重载,这取决于调用该运算符的方式。
- 当用户只需要读取一个值时,重载会将矩阵视为const并进行边界检查以确保用户没有尝试读取不存在的数据。 - 当用户需要写入数据时,重载会相应地调整矩阵的大小。
当然这没有任何意义,因为被调用的方法不知道调用它的内容或用户尝试做什么(除非传入一些数据)。
我的解决方案是让操作符重载对读取和写入执行相同的操作。因此,如果用户试图读取不存在的位置,则矩阵将重新调整其大小并返回默认值。最终,如果用户犯了错误并读取不存在的数据,这可能会牺牲一些速度,但如果用户这样做,程序的速度是他最不担心的。因此,这需要用户更加小心,我可能会添加一个数据成员,该成员是一个标志,指示矩阵是否已调整大小以便用户轻松检查事情是否按预期进行。
我不打算发布代码(除非请求),因为这更像是一个高级/功能问题,而且代码包含很多细节,可能会使讨论变得模糊。
答案 3 :(得分:0)
正如其他人所提到的,您需要一个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