转自这里
今天写了下面这个类来练习运算符的重载:
template<class T>
class CTest
{
public:
CTest(const T& val): _item(val){}
~Ctest(void){}
ostream & operator<<(ostream & os,const CTest<U>&rhs);
private:
T _item;
};
template <class T>
ostream & CTest<T>::operator<<(ostream &os,const CTest<T>& rhs)
{
os<<"this is CTest:"<<rhs._item<<endl;
return os;
}
结果gcc报错,说ostream & CTest<T>::operator()函数带且只带一个实参。于是我把ostream & Ctest<T>::operator()改成下面这样。
template <class T>
ostream & CTest<T>::operator<<onst CTest<T>& rhs)
{
cout<<"this is CTest:"<<rhs._item<<endl;
return cout;
}
这回编译器没报错了,于是就写了个测试函数。但是发现效果并不是我想要的,因为重载后的运算符只能被该类的对象调用而且<<后面的对象类型一定要相同。为了解决这个问题,我把重载函数声明为友元,于是类就成了这个样子:
template<class T>
class CTest
{
public:
CTest(const T& val): _item(val){}
~CTest(void){}
friend ostream & operator<<(ostream & os,const CTest<T>&rhs);
private:
T _item;
};
template <class T>
ostream & operator<<(ostream &os,const CTest<T>& rhs)
{
os<<"this is CTest:"<<rhs._item<<endl;
return os;
}
但是这样修改之后,编译器又报错了。按照语法来说,如果这个是一个普通的类而不是类模板的话,我这样写是不可能会出错的,于是赶紧查阅资料,终于在《C++ Primer 3》的16.4节找到了我要的答案。
按照书上所说的,类模板的友元声明一共有3种情况:
1。非模板友元类或者友元函数:如果是把普通的函数或者把整个类声明为友元,则它们不必在全局中被声明或者定义,但是如果把其他类的成员声明为友元,那么该类一定是已经定义了的,而且类成员只能由该类的定义引入。
2。绑定友元类模板或者函数模板:在一个模板可以被用在一个类模板的声明中之前,它的声明或者定义必须先给出。特别地,函数模板在类中的声明格式为:
friend 返回类型 函数名 <模板实参>(参数列表);
这种语法可以用来指定该友元声明所引用的函数模板的实例。如果省略了显式的模板实参,则友元函数会被解释为非模板函数。模板函数和同名的非模板函数可以共存,所以我们必须为引用函数模板实例的友元声明指定显式的模板参数表。
3。非绑定的友元类模板或者函数模板。这其实上是模板的成员模板问题,可以归类到另外一个问题上来介绍了。用简单的一句话来说那就是把友元类模板和模板成员都在类里面进行声明,而且在其声明前都必须加上template< class T > ,其中T 可以是和把它们声明为友元的类模板的模板参数不一样。
根据上面提到的做法,那么我写的类则可以有下面两种写法:
1,根据情况2,绑定模板友元函数。
template<class T>
class CTest;
template <class T>
ostream & operator<<(ostream &os,const CTest<T>& rhs);
template<class T>
class CTest
{
public:
CTest(const T& val): _item(val){}
~CTest(void){}
friend ostream & operator<< <T>(ostream & os,const CTest<T>&rhs);
private:
T _item;
};
template <class T>
ostream & operator<<(ostream &os,const CTest<T>& rhs)
{
os<<"this is CTest:"<<rhs._item<<endl;
return os;
}
2.根据情况3,用非绑定形式的模板函数
template<class T>
class CTest
{
public:
CTest(const T& val): _item(val){}
~Ctest(void){}
template<class U>
friend ostream & operator<<(ostream & os,const CTest<U>&rhs);
private:
T _item;
};
template <class T>
ostream & operator<<(ostream &os,const CTest<T>& rhs)
{
os<<"this is CTest:"<<rhs._item<<endl;
return os;
}
上面两种改法都在gcc上面编译通过