у меня есть Matrix
класс и он перегружен *
операторы для скалярных и матричных умножений.
template <class T> class Matrix
{
public:
// ...
Matrix operator*(T scalar) const;
// ...
}
// ...
template <class T>
Matrix<T> Matrix<T>::operator*(T RightScalar) const
{
Matrix<T> ResultMatrix(m_unRowSize, m_unColSize);
for (uint64_t i=0; i<m_unRowSize; i++)
{
for (uint64_t j=0; j<m_unColSize; j++)
{
ResultMatrix(i, j) = TheMatrix[m_unColSize * i + j] * RightScalar;
}
}
return ResultMatrix;
}
// ...
Я могу умножить матричный объект на скаляр с правой стороны без каких-либо проблем:
Matrix<double> X(3, 3, /* ... */); // Define a 3x3 matrix and initialize its contents
Matrix<double> Y; // Define an output matrix
Y = X * 10.0; // Do the linear operation
Но как мне умножить это с левой стороны таким же образом?
Matrix<double> X(3, 3, /* ... */);
Matrix<double> Y;
Y = 10.0 * X;
В арифметике это обычное обозначение для записи констант слева при выполнении умножения. Я хотел бы соблюдать это правило, чтобы сделать мой код более читабельным.
Возможно ли реализовать это в C ++?
Если это возможно, как я могу изменить метод класса в моем коде?
Функции-члены сопоставляются по их левому аргументу, который является указателем this. Поскольку нативные типы не могут иметь функции-члены, вы должны добавить умножение справа с пользовательскими типами через функции, не являющиеся членами (а также для других типов, к которым у вас нет прав записи).
template<typename T>
Matrix<T> operator*(T const& scalar, Matrix<T> rhs)
{
// scalar multiplication is commutative: s M = M s
return rhs *= scalar; // calls rhs.operator*=(scalar);
}
НОТА: Я написал выше не член operator*
осуществляется с точки зрения члена operator*=
, Рекомендуется записывать все умножения как функции, не являющиеся членами, и использовать член operator*=
реализовать эти умножения с элементом матрицы lhs.
Это а) сохранит интерфейс класса минимальным и б) предотвратит скрытые преобразования. Например. у вас может быть класс Matrix, который неявно преобразуется в скаляр, если размеры 1×1, и эти преобразования могут происходить без вывода сообщений, если вы не предоставите отдельную перегрузку, которая является прямым соответствием.
template<typename T>
Matrix<T> operator*(Matrix<T> lhs, T const& scalar)
{
return lhs *= scalar; // calls lhs.operator*=(scalar);
}
template<typename T>
Matrix<T> operator*(Matrix<T> lhs, Matrix<T> const& rhs)
{
return lhs *= rhs; // calls lhs.operator*=(rhs);
}
Обратите внимание, что матрица lhs является копией, а не ссылкой. Это позволяет компилятору оптимизировать, например, копировать семантику elision / move. Также обратите внимание, что тип возвращаемых данных операторов Matrix<T>
и не const Matrix<T>
что было рекомендовано в некоторых старых книгах по C ++, но препятствует семантике перемещения в C ++ 11.
// class member
template<typename T>
Matrix<T>& Matrix<T>::operator*=(Matrix<T> const& rhs)
{
// your implementation
return *this;
}
// class member
template<typename T>
Matrix<T>& Matrix<T>::operator*=(T const& scalar)
{
// your implementation
return *this;
}
Для этого вам понадобится функция, не являющаяся членом:
template <typename T>
Matrix<T> operator*(T scalar, Matrix<T> const & matrix) {
return matrix * scalar;
}
Перегруженные операторы, не являющиеся членами, позволяют указывать любой тип с любой стороны, в то время как перегрузки членов всегда получают объект с левой стороны.