参考资料--《C++ Primer Plus 第六版》
1.友元函数
区别于普通非成员函数,友元函数是一种特殊的非成员函数,它可以访问类的私有成员;
友元函数访问权限与成员函数相同,都可以访问私有、公有数据,因此友元函数相当于类的扩展接口;
示例:
//声明,声明要放在类的声明中
friend Time operator*(double m, const Time & t);
//定义
Time operator*(double mult, const Time & t)
{
Time result;
long totalminutes = hours * mult * 60 + minutes * mult;
result.hours = totalminutes / 60;
result.minutes = totalminutes % 60;
return result;
}
//调用
A = operator*(2.75, B);
其中,友元函数声明要放在类的声明中,在其原型上加上 friend 关键字;
其次,在定义时不要使用类限定符(Time::),且不要再定义中使用 friend 关键字;
2.友元类
在类中除了可以声明友元函数外,还可以声明友元类,此时友元类的所有方法都都可以访问原始类的私有成员和保护成员;
下面语句使Remote成为友元类:
friend class Remote; // Remote can access Tv private parts
友元声明可以放在公有、私有、保护的任何地方,位置无关紧要;
如下示例,因为Remote类中会用到Tv类的方法,所以编译器必须先知道Tv类,所以要先定义Tv类:
// tv.h -- Tv and Remote classes
#ifndef TV_H_
#define TV_H_
class Tv
{
public:
friend class Remote; // Remote can access Tv private parts
enum {Off, On};
enum {MinVal,MaxVal = 20};
enum {Antenna, Cable};
enum {TV, DVD};
Tv(int s = Off, int mc = 125) : state(s), volume(5),
maxchannel(mc), channel(2), mode(Cable), input(TV) {}
void onoff() {state = (state == On)? Off : On;}
bool ison() const {return state == On;}
bool volup();
bool voldown();
void chanup();
void chandown();
void set_mode() {mode = (mode == Antenna)? Cable : Antenna;}
void set_input() {input = (input == TV)? DVD : TV;}
void settings() const; // display all settings
private:
int state; // on or off
int volume; // assumed to be digitized
int maxchannel; // maximum number of channels
int channel; // current channel setting
int mode; // broadcast or cable
int input; // TV or DVD
};
class Remote
{
private:
int mode; // controls TV or DVD
public:
Remote(int m = Tv::TV) : mode(m) {}
bool volup(Tv & t) { return t.volup();}
bool voldown(Tv & t) { return t.voldown();}
void onoff(Tv & t) { t.onoff(); }
void chanup(Tv & t) {t.chanup();}
void chandown(Tv & t) {t.chandown();}
void set_chan(Tv & t, int c) {t.channel = c;}
void set_mode(Tv & t) {t.set_mode();}
void set_input(Tv & t) {t.set_input();}
};
#endif
可以看到除了构造函数,Romote方法都将Tv对象引用作为参数;且所有的方法都是使用Tv的方法,所以这里只需要定义Tv的方法即可,如下所示:
// tv.cpp -- methods for the Tv class (Remote methods are inline)
#include <iostream>
#include "tv.h"
bool Tv::volup()
{
if (volume < MaxVal)
{
volume++;
return true;
}
else
return false;
}
bool Tv::voldown()
{
if (volume > MinVal)
{
volume--;
return true;
}
else
return false;
}
void Tv::chanup()
{
if (channel < maxchannel)
channel++;
else
channel = 1;
}
void Tv::chandown()
{
if (channel > 1)
channel--;
else
channel = maxchannel;
}
void Tv::settings() const
{
using std::cout;
using std::endl;
cout << "TV is " << (state == Off? "Off" : "On") << endl;
if (state == On)
{
cout << "Volume setting = " << volume << endl;
cout << "Channel setting = " << channel << endl;
cout << "Mode = "
<< (mode == Antenna? "antenna" : "cable") << endl;
cout << "Input = "
<< (input == TV? "TV" : "DVD") << endl;
}
}
测试程序:
//use_tv.cpp -- using the Tv and Remote classes
#include <iostream>
#include "tv.h"
int main()
{
using std::cout;
Tv s42;
cout << "Initial settings for 42\" TV:\n";
s42.settings();
s42.onoff();
s42.chanup();
cout << "\nAdjusted settings for 42\" TV:\n";
s42.settings();
Remote grey;
grey.set_chan(s42, 10);
grey.volup(s42);
grey.volup(s42);
cout << "\n42\" settings after using remote:\n";
s42.settings();
Tv s58(Tv::On);
s58.set_mode();
grey.set_chan(s58,28);
cout << "\n58\" settings:\n";
s58.settings();
// std::cin.get();
return 0;
}
3.友元成员函数--略
4.共同的友元
第一种是让类彼此成为对方的友元,比如让Remote是Tv的友元,Tv也是Remote的友元;
class Tv
{
friend class Remote;
public:
void buzz(Remote & r);
...
};
class Remote
{
friend class Tv;
public:
void Bool volup(Tv & t) { t.volup }
};
inline void Tv::buzz(Remote & r)
{
...
}
第二种是一个函数分别是两个类的友元,可分别访问两个类的私有数据,如下:
class Analyzer; //forward declaration
class Probe
{
friend void sync(Analyzer & a, const Probe & p); //sync a to p
friend void sync(Probe & p, const Analyzer & a); //sync p to a
...
};
class Analyzer
{
friend void sync(Analyzer & a, const Probe & p); //sync a to p
friend void sync(Probe & p, const Analyzer & a); //sync p to a
...
};
//define the friend function
inline void sync(Analyzer & a, const Probe & p)
{
...
}
inline void sync(Probe & p, const Analyzer & a)
{
...
}
这里的前向声明 class Analyzer ,使编译器看到 Probe 类声明中的友元声明时,知道Analyzer是一种类型;