类并非只能拥有友元函数,也可以将类作为友元。在这种情况下,友元类的所有方法都可以访问原始类的私有成员和保护成员。另外,也可以做更严格的限制,只将特定的友元函数指定为另一类的友元。有一些函数,成员函数或类为友元只能由类定义,而不能从外部强加友情。
class Tv
{
public:
friend class remote;
enum{off,on};
Tv();
bool volup();
...
private:
int state;
...
}
class Remote
{
private:
int mode;
public:
bool volup(Tv &t){return t.volup();}
}
friend class Remote 语句使 Remote成为友元类,友元声明可以位于公有,私有或保护部分,其所在的位置无关紧要。
大多数的Remote方法都是用Tv类的公有接口实现。这意味着这些方法不是正真的需要作为友元。事实上,唯一直接访问Tv成员的Remote方法是 Remote::set_chan(),因此它是唯一需要作为友元的方法。确实可以选择仅让特定的类成员成为另一个类的友元,而不必让整个类成为友元。
让Remote::set_chan()成为Tv类的友元的方法是,在Tv类声明中将其声明为友元:
class Tv
{
friend void Remote::set_chan(Tv & t,int c);
}
不过要使编译器能处理这条语句,它必须知道Remote的定义。否则,它无从知道Remote是一个类,而set_chan是这个类的方法。这意味着需要将Remote类放在Tv类的前面。但是Remote方法提到了类的对象,Tv的定义需要在Remote的前面。避开这种循环依赖的方法是,使用前向声明。
class Tv;
class Remote{...};
class Tv{...};
当 一些Remote方法可以影响Tv对象,而一些Tv方法也可以Remote对象。这可以让类彼此成为对方的友元来实现。
对于使用Remote对象的Tv方法,其原型可在Remote类声明之前声明,但必须在Remote类声明之后定义。
class Tv
{
friend class remote;
public:
void buzz(Remote &r);
...
};
class Remote
{
friend class Tv;
public:
void bool volup(Tv &t){ t.volup();}
...
};
由于Remote的声明位于Tv的后面,可以在类声明中定义Remote::volup(); 但是Tv::buzz()方法必须在Tv声明的外部定义,使其位于Remote声明的后面。如果不希望buz()是内联的,则应该在一个单独的方法中定义。