现在的位置: 首页 > 综合 > 正文

C++中模板类使用友元模板函数

2013年12月07日 ⁄ 综合 ⁄ 共 4344字 ⁄ 字号 评论关闭

问题始于学习数据结构,自己编写一个单链表,其中用到了重载输出运算符<<,我写的大约这样:

template <class T> class List{
    friend std::ostream& operator << (std::ostream& os,const List<T>& slist);
    //……
};用vs2008可编译,但无法链接:无法解析的外部符号……

后来上网查改为template <class T> class List{
    friend std::ostream& operator <<  <>(std::ostream& os,const List<T>& slist);
    //……
};

就可以了。不知所以然,查了下《C++ Primer》才弄明白。

好了,进入正题:

在类模板中可以出现三种友元声明:
(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);}

抱歉!评论已关闭.