I'm writing a matrix class (CMatrix), with such derived classes as a 3d vector(CVector) and a rotation matrix(CRotMatrix). My CMatrix object could be multiplied by an another CMatrix-based object or by an any numerical value(scalar). This code represents the essence of the problem I got:
template<class T> class CMatrix
{
public:
template<class U> const CMatrix& operator=(const CMatrix<U> &inp){return (*this);}
CMatrix& operator*(const CMatrix &inp)
{
cout<<"Multiplication by CMatrix"<<endl;
return (*this);
}
template<class U>开发者_运维百科;
CMatrix& operator*(const U &inp)
{
cout<<"Multiplication by a scalar."<<endl;
return (*this);
}
};
template<class T> class CVector: public CMatrix<T>{};
template<class T> class CRotMatrix: public CMatrix<T>{};
int main()
{
CMatrix<int> foo1;
CMatrix<int> foo2;
CVector<int> dfoo1;
CRotMatrix<int> dfoo2;
foo1 = foo1*foo2; //calls CMatrix method
foo1 = foo1*5; //calls scalar method
foo1 = foo1*dfoo2; //calls scalar method, shoud be CMatrix
foo1 = dfoo2*dfoo1; //calss scalar method, shoud be CMatrix
return 0;
}
The problem is that the compiler prefers the template version of operator*(). Is there any way to make the compiler choose the proper method for derived CMatrix classes in this situation? If I cut off this method
CMatrix& operator*(const U &inp)
The compiler does it in the right way, but the class loses the ability to be multiplied by a scalar. I'm using msvc10. Thank you in advance.
The reason is that the template operator is considered an exact match while the matrix version requires a conversion to parent reference. Thus the compiler pick the template as a better match.
First consider if you really need the child classes that you've created and that they provide the appropriate functionality/overrides.
If you need them then I would solve the problem by making one or both of the operations not an operator. By making operator*
do both kinds of multiply you violate the principle of least surprise having it do two wildly different things depending on context. I would suggest named methods for both so it's obvious, but otherwise I would suggest operator*
to be matrix math and a function ScalarMultiply
to do the single scalar type.
The problem is that the compiler prefers the template version of operator*(). Is there any way to make the compiler choose the proper method for derived CMatrix classes in this situation?
That's because you told it to. Your Multiplication by a scalar
method is more generic than is your Multiplication by CMatrix
method.
Make your "Multiplication by a scalar" method be what the comment says it is:
CMatrix& operator*(const T & inp)
{
std::cout<<"Multiplication by a scalar."<<std::endl;
return (*this);
}
Addendum
Your template<class U> CMatrix& operator*(const U &inp)
is so generic that it matches anything. Multiple by a std::istream
: No problem. It prints Multiplication by a scalar.
You want your multiplication by a scalar to be restrictive, not a catch-all for any random type.
精彩评论