开发者

How to make the compiler choose the non-template version of a method for derived classes?

开发者 https://www.devze.com 2023-03-28 10:12 出处:网络
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

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.

0

精彩评论

暂无评论...
验证码 换一张
取 消