Вызвана неправильная перегрузка operator () - PullRequest
0 голосов
/ 10 апреля 2010

Я пишу матричный класс и дважды перегрузил оператор вызова функции. Ядро матрицы представляет собой двумерный двойной массив. Я использую компилятор MinGW GCC, вызываемый из консоли Windows.

Первая перегрузка предназначена для возврата двойного из массива (для просмотра элемента). вторая перегрузка предназначена для возврата ссылки на местоположение в массиве (для изменения данных в этом месте.

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. Я буду наказан полностью в загробной жизни, нет необходимости делать это здесь.

В конечном счете, я хотел бы знать, что здесь происходит и как это исправить. Я бы предпочел использовать более чистые операторские перегрузки, а не функции-члены.

Есть идеи?

Класс матрицы: нерелевантный код опущен.


    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
}

Ответы [ 4 ]

5 голосов
/ 10 апреля 2010

Функция-член const (функция просмотра) будет вызываться только в том случае, если объект const:

const Matrix testMatD(5,7);

testMatD(1, 2); // will call the const member function
3 голосов
/ 10 апреля 2010

Вызываемая перегрузка определяется исключительно параметрами (включая параметр this), а не типом возврата или тем, что вы делаете с типом возврата.

Это означает, что если у вас есть метод, отличный от const, который имеет сигнатуру, которая в остальном идентична методу const (кроме, возможно, возвращаемого типа), то метод const будет использоваться только при вызове на const объекте или через const ссылку или указатель. Если у вас есть объект не const, тогда метод не const всегда будет лучшим совпадением.

Как правило, единственный способ сделать различие в том, действительно ли вы записываете в возвращаемый объект, - это вернуть некоторый тип прокси-объекта, который имеет соответствующее неявное преобразование для чтения и перегруженный оператор присваивания для записи. Излишне говорить, что это обычно добавляет значительную сложность.

1 голос
/ 23 апреля 2010

Привет всем за вашу помощь, я читал похожие ответы на подобные вопросы. Думаю, мне просто пришлось услышать это еще раз, сформулировав немного по-другому.

Моя первоначальная проблема заключалась в том, что мне нужно было две версии перегрузки оператора, которые должны быть реализованы по-разному, в зависимости от того, как этот оператор вызывается.

- Когда пользователю просто нужно прочитать значение, перегрузка будет обрабатывать матрицу как const и выполнять проверку границ, чтобы убедиться, что пользователь не пытается прочитать данные, которые не существуют. - Когда пользователю необходимо записать данные, перегрузка изменит размер матрицы соответственно.

конечно, это не имеет смысла, так как вызываемый метод не знает, что его вызывает или что пытается сделать пользователь (если только не передаются некоторые данные).

Мое решение состояло в том, чтобы перегрузка оператора выполнялась одинаково как для чтения, так и для записи. таким образом, если пользователь попытается прочитать местоположение, которое не существует, матрица изменит свой размер и вернет значение по умолчанию. В конечном итоге это может принести в жертву некоторую скорость, если пользователь делает ошибку и читает данные, которых не существует, но если пользователь делает это, скорость программы - это его наименьшее беспокойство. так что для этого требуется, чтобы пользователь был немного более осторожен, и я мог бы добавить элемент данных, который является флагом, указывающим, был ли изменен размер матрицы, чтобы легко позволить пользователю проверить, все ли прошло как ожидалось.

Я не собираюсь публиковать код (если не будет запрошен), потому что это была скорее высокоуровневая / функциональная проблема, а код содержит так много специфики, что это может затмить обсуждение.

0 голосов
/ 10 апреля 2010

Как уже упоминалось, вам нужен объект const для вызова перегрузки const.

То, что вы пытаетесь сделать здесь, это убедиться, что ссылка преобразована в r-значение для ....

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
...