友元函数模板问题

来源:互联网 发布:网络兼职有哪些可靠 编辑:程序博客网 时间:2024/05/04 06:02

今天下午写了一个友元函数的模板,其中在编译的时候碰到了一些问题。首先在编译的时候提示“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的形参是intdouble或其他都可以。

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可以是任意类型,比如intdouble

回到原问题,按(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);}

 

原创粉丝点击