Модификация перегруженного оператора-члена с использованием constness - PullRequest
2 голосов
/ 13 декабря 2011

Вот краткий обзор моей проблемы: У меня есть шаблонный класс под названием TWMatrix. Я перегружен оператор (), так что он может взять пару TWMatrix и извлечь соответствующие записи. Я хочу, чтобы «извлечение» дало 2 разных результата для 2 разных случаев. Раньше это работало, когда брал пару целых, но я очень застрял, заставляя его работать для этой немного другой проблемы:

  • В одном случае я хочу, чтобы оператор скопировал записи в другой TWMatrix и вывел его.
  • В другом случае я хочу, чтобы оператор скопировал адреса этих записей в объект типа TWDataPointer, вывел этот объект.

В первом случае метод не нарушает константность. Действительно, сами записи не являются ни измененными, ни уязвимыми для будущих изменений. В последнем весь смысл в том, что объект TWDataPointer может использоваться для изменения этих элементов матрицы. И поэтому соответствующий бит кода:

TWDataPointer<T> operator () (const TWMatrix<int> & I1, const TWMatrix<int> & I2)
{
     return TWDataPointer<T>(*this,I1,I2);
}

TWMatrix<T> operator () (const TWMatrix<int> & I1, const TWMatrix<int> & I2) const 
{
    return SubMat(I1,I2);
}

SubMat - это метод, который создает матрицу с соответствующими записями. Он работает просто отлично, и какие значения он выбирает, здесь не очень важно. Проблема в том, что этот второй оператор, кажется, никогда не вызывается. Так, например, если в моем основном я пишу:

TWMatrix<double> test = D5(I1,I2);

Компилятор жалуется, говоря:

error: conversion from ‘TWDataPointer<double>’ to non-scalar type ‘TWMatrix<double>’ requested

Это очень непохоже:

T operator () (const int & i, const int & j) const 
{
    return data[j+i*nc];
}

T& operator () (const int & i, const int & j) 
{
    return data[j+i*nc];
}

, который работает точно так, как ожидалось, и возвращает либо T, либо T & в зависимости от ситуации. Из того, что я понимаю о перегрузке операторов, именно const позволяет компилятору различать, в какой ситуации использовать. Так почему же это не сработает?

Заранее благодарим за помощь и не стесняйтесь спрашивать о любых дополнительных фрагментах кода, которые могут вам понадобиться.

PS: У меня уже есть решение для этого, и хотя оно не очень уродливо, оно далеко не так просто, элегантно и надежно, как если бы я мог заставить его работать.

edit: Спасибо за помощь, и я все еще жду ваших ответов. В частности, я до сих пор запутался в этом:

"Возвращаясь к примеру с int, почему a = test (0,0) использует версию const соответствующего оператора, даже если test не объявлен как const? Действительно, я проверял, что это так, используя cout операторы в обеих версиях операторов (). "

Ответы [ 3 ]

2 голосов
/ 13 декабря 2011

Есть ли конкретная причина, по которой вам нужен только один const второго метода?Из того, что мне кажется в этом коде, и возможных сценариев использования, в то время как ваш второй метод технически является const методом, он не должен иметь , который должен быть объявлен как таковой.Другими словами, это метод, который может использоваться как const, так и не const версиями вашего экземпляра класса, и вы, очевидно, придете к сценариям, когда вашему экземпляру класса требуется метод, когда он не constобъект.Таким образом, использование маркировки вашего метода как const только потому, что оно не изменяет состояние экземпляра, который вызывает метод, не означает, что вы должны пометить свой метод как const.

Чтобы работать с обоими сценариями, я бы сгенерировал две версии operator(), которые возвращают тип TWMatrix<T> ... одну, которая объявлена ​​const, и одну, которая объявлена ​​как неconst метод, так что он может использоваться как экземплярами класса const, так и не const.Недостатком является то, что вам придется создать отдельный метод для возврата типа TWDataPointer<T>, поскольку вы не можете перегрузить, основываясь только на типе возврата.

1 голос
/ 13 декабря 2011

По-видимому, это потому, что D5 не является постоянным. Именно cv-квалификация этого объекта определяет, какой оператор выбран.

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

0 голосов
/ 13 декабря 2011

Для нестатической функции-члена. Существует неявный объектный аргумент - указатель this. И если нестатическая функция-член объявлена ​​как const, указатель this будет const. Итак, на самом деле ваши две функции выглядят так:

TWDataPointer<T> operator () (this, const TWMatrix<int> & I1, const TWMatrix<int> & I2)
{
     return TWDataPointer<T>(*this,I1,I2);
}

TWMatrix<T> operator () (const this, const TWMatrix<int> & I1, const TWMatrix<int> & I2) const 
{
    return SubMat(I1,I2);
}

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

TWMatrix<T> matrix = ((const TWMatrix<T>&)D5)(I1,I2);

как обходной путь. Но я не думаю, что это хорошая идея. Очень сложно, что константные и неконстантные методы получают разные типы результатов.

Для вашего примера int, если тест не const, я не думаю, что будет вызвана первая функция.

...