今天下午写了一个友元函数的模板,其中在编译的时候碰到了一些问题。首先在编译的时候提示“note: (if this is not what you intended, make sure the function template has already been declared and add <> after the function name here)”,
查了一下网页才知道,原来友元函数在类内声明时按照国际标准是:
friend ostream& operator << <T>(ostream &, const List<T> &);
而我却写成了这样:
friend ostream& operator <<(ostream &, const List<T> &);
改过来之后编译却又提示:实例化错误。后来才发现,当实例化失败的时候,需要使用前向声明友元函数。
即:
template<class T> class List;
template<class T> std::ostream& operator <<(std::ostream& os, const List<T>& l);
template<class T>
class List{
…
friend std::ostream& operator << <T>(std::ostream& os, const List<T>& l);
…
};
最后才能编译成功。
最后粘贴一下别人的内容:
在类模板中可以出现三种友元声明:
(1)普通非模板类或函数的友元声明,将友元关系授予明确指定的类或函数。
(2)类模板或函数模板的友元声明,授予对友元所有实例的访问权。
(3)只授予对类模板或函数模板的特定实例的访问权的友元声明。
要注意的是,友元函数并非成员函数,是改变了它对类成员的访问权限。
(1)没有什么好说的,如:
template<class T>
class A{
friend void fun();
//...
};
此例中fun可访问A任意类实例中的私有和保护成员
(2)
template<class T>
class A{
template<class T>
friend void fun(T u);
//...
};
这时友元使用与类不同的模板形参,T可以是任意合法标志符,友元函数可以访问A类的任何类实例的数据,即不论A的形参是int,double或其他都可以。
(3)
template<class T>
class A{
friend void fun<T>(T u);
//...
};
此时fun只有访问类中特定实例的数据。换句话说,此时具有相同模板实参的fun函数与A类才是友元关系。即假如调用fun时其模板实参为int,则它只具有A<int>的访问权限。当然friend void fun<T>(T u);中<>中的T可以是任意类型,比如int,double等
回到原问题,按(3)可改为:
template <class T> class List{
friend std::ostream& operator << <T>(std::ostream& os,const List<T>& slist);
//……
};
按(2)可改为:
template <class T> class List{
template <class T>
friend std::ostream& operator << (std::ostream& os,const List<T>& slist);
//……
};
在这里其实两者实现的最终效果一样的,因为调用输出运算符时需要访问的类实例的对象是它本身,所以形参T在第一种改法中一定匹配。
一个例子:
#include <iostream>
using namespace std;
template<typename T>
class sample
{
public:
//直接在类内部实现函数定义
friend ostream& operator<<(ostream& out, const sample<T>& operand )
{
out<<"Value : "<<operand.data<<std::endl;
return out;
}
//使用<T>实例化,在类外实现
friend istream& operator>> <T>(istream& in, sample<T>& operand );
//{
// std::cout<<"Input data: ";
// in>>operand.data;
// return in;
//}
friend bool operator== <T>(const sample<T>& left,const sample<T>& right);
//使用自定义<U>实例化,即:参数可以不同,仍然是类外实现
template <class U>
friend bool operator != (const sample<U>& left,const sample<U>& right);
sample(T d = T()):data(d) {}
private:
T data;
};
/* template<typename T>
ostream& operator<<(ostream& out, const sample<T>& operand )
{
out<<"Value : "<<operand.data<<std::endl;
return out;
}*/
template<typename T>
istream& operator>>(istream& in, sample<T>& operand )
{
std::cout<<"Input data: ";
in>>operand.data;
return in;
}
template<typename T>
bool operator==(const sample<T>& left,const sample<T>& right)
{
return left.data == right.data;
}
template<class U>
bool operator != (const sample<U>& left,const sample<U>& right)
{
return left.data!=right.data;
}
//当使用<T>实例化失败的时候,需要使用前向声明友元函数!!
//另一个例子:
#include <cstdio>
#include <cmath>
#include <cstring>
#include <iostream>
using namespace std;
template<class T>class cPoint;
template<class T>bool operator==(const cPoint<T>& my,const cPoint<T>& other);
template<class T>
class cPoint //点 类
{
protected:
T x,y,z;//点的三维坐标
public:
cPoint(T a = 0 ,T b = 0,T c = 0):x(a),y(b),z(c) {};
//重载==操作符
friend bool operator==(const cPoint<T>& my,const cPoint<T>& other) {
return (my.x == other.x)&&(my.y == other.y)&&(my.z == other.z);
};
//两点之间的距离
virtual T distance(const cPoint&);
};
template<class T>
T cPoint<T>::distance(const cPoint<T>& other)
{
if (*this == other)
return T(0);
T dis = (T)sqrt(pow(other.x-x,2)+pow(other.y-y,2)+pow(other.z-z,2));
cout<<"distance is "<<dis<<endl;
return dis;
}
template<class T>class cCir;
template<class T> bool operator ==(const cCir<T>& my,const cCir<T>& other);
template<class T>
class cCir:public cPoint<T>//圆 类
{
protected:
T r;//半径
public:
cCir(T a=0,T b=0,T c=0,T d=0):cPoint<T>(a,b,c),r(d) {};
//重载==
friend bool operator == <T>(const cCir<T>& my,const cCir<T>& other);
//两圆之间的距离
T distance(const cCir&);
};
template<class T>
T cCir<T>::distance (const cCir& other)
{
if (other == *this)
return T(0);
T dis = (T)(sqrt(pow((other.x-this->x),2)+pow(other.y-this->y,2)+pow(other.z-this->z,2))-this->r-other.r);
cout<<"distance is "<<dis<<endl;
return dis;
}
template<class T>
bool operator==(const cCir<T>& my,const cCir<T>& other)
{
return (my.x == other.x)&&(my.y == other.y)&&(my.z == other.z)&&(my.r == other.r);
}
int main(int argc, char **argv)
{
cPoint<double> p1(1.0,2.0,3.0),p2(3.0,4.0,5.0);
p1.distance(p2);
cCir<double> c1(1.0,2.0,3.0,1.0),c2(3.0,4.0,5.0,1.0);
cCir<double> c3(1.0,2.0,3.0,1.0),c4(1.0,2.0,3.0,1.0);
c1.distance(c2);
c3.distance(c4);
//system("pause");
return 0;
}
//还有一种是间接调用类内部实现,自定义一个函数,实现要重载的效果,在类外直接重载操作符,调用该函数!
//比如,在类内添加一个public函数:bool not_equal(const cCir<T>& other);
//实现{return this->r!= other.r...(这里需要比较四个数据!忽略)};(该实现,既可以在类内部,也可以在类外部实现),然后定义全局重载操//
//作符函数:bool operator!=(const cCir<T>& left,const cCir<T>& right);
//实现{return left.not_equal(right);}