Разумно ли возвращать указатель из перегруженного арифметического оператора, объявленного в абстрактном классе? - PullRequest
2 голосов
/ 28 января 2012

У меня есть пара чистых виртуальных классов, Matrix и Vector.Во всей моей кодовой базе я стараюсь создавать только зависимости от них, а не их конкретные подклассы, например SimpleTransformationMatrix44 и SimpleTranslationVector4.Мотивация для этого заключается в том, что я могу использовать сторонние (адаптированные) классы вместо моих без особых проблем.

Я бы хотел перегрузить арифметические операторы (полученные из здесь ):

T T::operator +(const T& b) const;
T T::operator -(const T& b) const;
T T::operator *(const T& b) const;

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

std::unique_ptr<T> T::operator +(const T& b) const;
std::unique_ptr<T> T::operator -(const T& b) const;
std::unique_ptr<T> T::operator *(const T& b) const;

, которое позволяет это (без бросков вниз!):

std::unique_ptr<Matrix> exampleFunction(const Matrix& matrix1, const Matrix& matrix2)
{
    std::unique_ptr<Matrix> product = matrix1 * matrix2;
    return std::move(product);
}

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

Итак, я предполагаю, что мой вопрос таков: ушел ли я из сюжета с этой идеей?Если бы вы увидели это в каком-то коде, над которым вы работали, вы бы подумали о WTF?Есть ли лучший способ добиться этого?

Ответы [ 2 ]

1 голос
/ 03 февраля 2012

Прежде всего: перегрузка операторов - это то, что лучше всего подходит для типов значений. Как вы узнали, полиморфизм не очень хорошо с ним работает. Если вы готовы ходить на костылях, это может помочь, хотя:

Если вы последуете совету Часто задаваемые вопросы по перегрузке оператора Stackoverflow , вы будете внедрять operator+() как элемент, не являющийся членом operator+=(). Последний возвращает ссылку . Это все еще проблема, потому что он может возвращать только ссылку на базовый класс, но пока вы используете его только для выражений, ожидающих этого, у вас все хорошо.

Если вы затем шаблонизируете operator+() , как предложил DeadMG , вы можете делать то, что хотите:

template<typename T>
T operator+(const T lhs, const T& rhs)
{
  lhs += rhs;
  return lhs;
}

Обратите внимание, что это перехватит любую T, для которой не найдена более подходящая перегрузка operator+(). (Это может показаться хорошей идеей - пока вы не забудете включить заголовок, и этот оператор перехватывает x+y, заставляя код компилироваться, но молча приводить к неверным результатам.) Поэтому вы можете захотеть ограничить это.

Один из способов - поместить его в то же пространство имен, что и матричные и векторные типы. Или вы используете static_assert, чтобы обеспечить передачу только типов, производных от двух.

0 голосов
/ 28 января 2012

Я ушел с сюжета с этой идеей?

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

...