Страницы

Поиск по вопросам

среда, 5 декабря 2018 г.

Наследование перегруженных арифметических операторов c++

Есть шаблонные классы
template< int rows, int columns, typename Type > class Matrix : public Tensor {...}
template< int size, typename Type > class Vector : public Tensor {...}
template< typename Type > class Quaternion : public Tensor<4, Type> {...}
Которые все унаследованы от шаблонного базового класса:
template< int elements, typename Type = DEFUALT_TYPE > class Tensor { Tensor() {...} Tensor( const Tensor& other ) {...} ~Tensor() {...}
template< int elements, typename Type, typename Scalar > friend Tensor< elements, Type> operator+( const Tensor< elements, Type>& left, const Scalar right ); ... // overloading operators -,*,/,+=,-=,*=,/= protected: Type array[elements]; }
Который, в основном, отвечает за базовые арифметические операции: сложение, вычитание, умножение, деление на скаляр, так как для всех наследованных типов эти операции одинаковы.
Но проблема в том, что эти операторы возвращают базовый класс Tensor, что, в свою очередь, порождает некоторые проблемы:
Нельзя присвоить результат сложение вектора и скаляра вектору:
Vector<3,double> vec1; Vector<3,doubel> vec2 = vec1+1; Для классов Matrix, Vector, Quaternion перегружен оператор стандартного вывода, но такое не сработает:
std::cout << vec1+2; Нельзя сразу же использовать результат сложения:
(vec1+5).length();
Хотя, это почти то же самое что и 2 пункт.
Первую проблему можно решить, например, создав для Matrix, Vector, Quaternion конструктор копирования, который бы создавал объект из объекта класса Tensor:
Vector( const Tensor& tensor ) : Tensor( tensor ) {...}
Но это не решает остальных проблем, и пропускает такой, заведомо ложный код:
Matrix<2,2,double> mat1; Vector<4,double> vec1 = mat1+2;
Сейчас я решил проблему тем, что для каждого наследуемого класса я определяю эти операторы заново. Но это во-первых муторно, ведь для каждого класса их примерно 12 штук. А если надо что-то поменять? Добавить новый класс? А во-вторых это дублирование идентичного кода.
Как можно разрешить эту проблему поэлегантнее?


Ответ

Можно воспользоваться техникой известной под именем CRTP. Приведу пример, как Вам можно это реализовать, а Вы уже сами заточите под свой код:
#include
template class Base { public: Derived operator+(int scalar) { //добавим сюда сложение return *self(); } private: Derived* self() { return static_cast(this); } };
template class A: public Base> { public: A() = default; A(const A&) { std::cout << "A copy ctor
"; } };
template class B: public Base> { public: B() = default; B(const B&) { std::cout << "B copy ctor
"; } };
int main(int argc, char* argv[]) { A a; B b; a = a + 1; b = b + 5;
// Следующие строки не скомпилируются //a = b + 1; //b = a + 1; }

Комментариев нет:

Отправить комментарий