我有一个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 ++中实现这一点?
如果可能,我如何修改代码中的类方法?
答案 0 :(得分:10)
成员函数由它们的左侧参数匹配,该参数是this-pointer。由于本机类型不能具有成员函数,因此必须通过非成员函数(以及您没有写入权限的其他类型)向用户定义的类型添加右乘法。
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元素实现这些乘法。
这将a)保持类接口最小化,b)防止隐藏转换。例如。如果维度为1x1,则可以使用可隐式转换为标量的Matrix类,如果不提供直接匹配的单独重载,则这些转换可能会无声地发生。
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 Matrix是如何复制而不是引用。这允许编译器进行优化,例如复制省略/移动语义。另请注意,这些运算符的返回类型是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;
}
答案 1 :(得分:8)
你需要一个非成员函数:
template <typename T>
Matrix<T> operator*(T scalar, Matrix<T> const & matrix) {
return matrix * scalar;
}
非成员运算符重载允许您在任一侧指定任何类型,而成员重载总是在左侧获取对象。