C++友元函数(类)用法

1,friend 申明一个友元
friend 一般为一句申明式,它位于一个类的内部,它申明一个类或者一个函数为该类的友元。friend 并不是定义一个成员函数,所以 friend 放在 public,protected 或者 private 前都可以,完全是一样的。做为一个友元,即表示在该类或者该函数内部可以访问这个类的私有成员(通过接口传过来的类,以及函数体里面的类,都可以像成员函数一样访问私有成员),你和朋友之间是不是应该没有什么隐藏的呢。例子:

class A
{
public:
A(int _a) : a(_a) {}
friend void test(A&);
friend class B;
private:
int a;
};
void test(A& x)
{
x.a=100;//拥有私有成员 a 的访问权限
}
class B
{
public:
void foo();
};
如果 friend 申明式为一般的非模板类或者函数,则该处可以为首次申明。对于一个类,只能是申明式,对于函数,可以是它的定义式。
class A
{
public:
A(int _a) : a(_a) {}
friend void test(A& x)
{
x.a = 100;//定义::test()友元函数
}
friend class B;
private:
int a;
};
注意尽管将函数的定义式放在类内部,但它并不是一个成员函数,对于省略受限的定义形式它将成为一个全局函数::test(),当然你也可以申明另外一个类的成员函数为友元,如:
class A
{
public:
A(int _a) : a(_a) {}
friend void B::foo();
private:
int a;
};

总的来说,如果你想在哪里访问类 A 的私有成员,就在类 A 内写上一句该处的申明式,并在前面加上 friend 关键字。这是一般情况,很简单,但是它会破坏封装的初衷,所以尽量少用;Effective C++中有一个应用的例子,对一个类定义的二元操作符,如果你希望它能对操作数都进行隐式转化,那么就定义一个全局函数,并申明成该类的友元。
2,模板函数作友元
先给一个模板函数,它是一个模板,并不是一个函数:
template<typename T>
void foo1(T);
在定义 foo1 为某类的友元时,或者要实例化模板参数 T,或者给出可演绎的申明式,而且就算是可以演绎的,一对尖括号也不能省。如:

class A
{
public:
friend void foo1<char>(char);
friend void foo1<>(double);
};
或者给出限制符:::
class A
{
public:
friend void ::foo1(char);
};
当然,如果有一般函数具有这种形式,那会优先于模板函数匹配。最后这里的申明式都不能是定义式,必须前至申明(定义)。
3,模板类里的友元
模板类里也能申明 2 中的友元,但是模板类有模板参数,如果利用了这个模板参数的友元申明,就属这种情形。

template<typename T>
class A
{
public:
friend void foo1<T>(T);
};
但是,在这里,必须要求 foo1 在这里是可见的,即不能是首次申明式。如果不使用模板参数,那会是一种有趣的情形。

template<typename T>
class A
{
public:
friend void foo(){}
};

注意这里是一个定义式,它定义了一个::foo()函数为该模板类的友元,在该模板类具现的时候,::foo()也被具现出来,即:

A<int> a1;// ::foo()首次定义
A<char> a2;// ::foo()第二次定义,违背 C++一次定义原则

4,友元模板
如果想定义一系列函数为该类的友元,可以使用友元模板。它和模板的申明式类似,只是在template<>后加了 friend 关键字。

class A
{
public:
template<typename T>
friend void foo();
};
5,能否做为定义式 

能做为定义式的情况是:非受限,没有前至::,没有模板参数列表,没一对尖括号。如果是模板申明式,不能是首次申明,在该处必须是可见的。

6,一个完整的例子

template<typename T>
class Rat
{
public:
Rat(T _a, T _b) : a(_a), b(_b) {}
friend Rat<T> operator*<T>(Rat<T>&,Rat<T>&);
private:
T a,b;
};
template<typename T>
Rat<T> operator*(Rat<T> & x, Rat<T> & y)
{
return Rat<T>(x.a*y.a,x.b*y.b);
}

Rat<T>为 T 类型的有理数类,定义它的相乘运算,定义一个全局函数,并申明为友元,该函数也应该是模板,希望有如上的程序通过编译。在 friend 式之前没有 operator*()的申明,所以这里不能是首次申明,在前面必须加上申明式:

template<typename T>
Rat<T> operator*(Rat<T> & x, Rat<T> & y);

在这之前又没有 Rat<T>的申明,再加上:
template<typename T>
class Rat;

通过编译,或者改成友元模板:
template<typename T>
class Rat
{
public:
Rat(T _a, T _b) : a(_a), b(_b) {}
template<typename U>
friend Rat<U> operator*(Rat<U>&,Rat<U>&);
private: 
T a,b;
};
template<typename T>
Rat<T> operator*(Rat<T> & x, Rat<T> & y)
{
return Rat<T>(x.a*y.a,x.b*y.b);
}
有细微的不同,Rat<T>申明了一系列友元 operator*<U>,当然没必要,只要 operator*<T>就够了,但是形式上简单一些。还有一种更简单的形式,就是将定义式放在里面,正是 Effective C++里使用的方法:

template<typename T>
class Rat
{
public:
Rat(T _a, T _b) : a(_a), b(_b) {}
friend Rat<T> operator*(Rat<T>&x,Rat<T>&y) //定义并申明了::operator*()
{
return Rat<T>(x.a*y.a,x.b*y.b);
}
private:
T a,b;
};








评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值