11.13 友元
11.13.1 友元类
举例:Remote是Tv的一个友元类,它的方法可以访问Tv的所有成员(包括私有成员和保护成员)
tv.h
#pragma once
#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
11.13.2 友元成员函数
11.13.2.1 为什么可以使用友元成员函数?
因为Remote_1中除了set_chan()成员函数,其他成员都不需要使用Tv_1的私有成员,所以可以只将set_chan()作为友元函数。
11.13.2.2 为什么要前提声明Tv_1?
原因是Remote_1类中使用到Tv_1,使用前提声明是为了告诉编译器Tv_1是一个类。
11.13.2.3 为什么在Remote_1类的声明中没有定义成员函数?
原因是Remote_1类中的成员函数使用了Tv_1的成员函数,但是在这之前还不知道Tv_1类有哪些成员函数。
11.13.2.4 能不能将Tv_1的定义放在Remote_1前面?
不能,原因是Remote_1的成员函数set_chan()是Tv_1的友元函数,如果Tv_1的声明在前面则编译器不知道Remote_1的set_chan()是一个函数。
11.13.2.5 注意事项
内联函数是内部链接的,只能在同一个文件下使用,这里将其写在.h文件中,将其引用即可使用。
tvfm.h
#pragma once
#ifndef Tv_FM_H_
#define Tv_FM_H_
#include<iostream>
class Tv_1; // forward declaration
class Remote_1
{
public:
enum State { Off, On };
enum { MinVal, MaxVal = 20 };
enum { Antenna, Cable };
enum { Tv, DVD };
private:
int mode;
public:
Remote_1(int m = Tv) : mode(m) {}
bool volup(Tv_1& t); // prototype only
bool voldown(Tv_1& t);
void onoff(Tv_1& t);
void chanup(Tv_1& t);
void chandown(Tv_1& t);
void set_mode(Tv_1& t);
void set_input(Tv_1& t);
void set_chan(Tv_1& t, int c);
};
class Tv_1
{
public:
friend void Remote_1::set_chan(Tv_1& t, int c);
enum State { Off, On };
enum { MinVal, MaxVal = 20 };
enum { Antenna, Cable };
enum { TV, DVD };
Tv_1(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;
private:
int state;
int volume;
int maxchannel;
int channel;
int mode;
int input;
};
bool Tv_1::volup()
{
if (volume < MaxVal)
{
volume++;
return true;
}
else
return false;
}
bool Tv_1::voldown()
{
if (volume > MinVal)
{
volume--;
return true;
}
else
return false;
}
void Tv_1::chanup()
{
if (channel < maxchannel)
channel++;
else
channel = 1;
}
void Tv_1::chandown()
{
if (channel > 1)
channel--;
else
channel = maxchannel;
}
void Tv_1::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;
}
}
// Remote_1 methods as inline functions
inline bool Remote_1::volup(Tv_1& t) { return t.volup(); }
inline bool Remote_1::voldown(Tv_1& t) { return t.voldown(); }
inline void Remote_1::onoff(Tv_1& t) { t.onoff(); }
inline void Remote_1::chanup(Tv_1& t) { t.chanup(); }
inline void Remote_1::chandown(Tv_1& t) { t.chandown(); }
inline void Remote_1::set_mode(Tv_1& t) { t.set_mode(); }
inline void Remote_1::set_input(Tv_1& t) { t.set_input(); }
inline void Remote_1::set_chan(Tv_1& t, int c) { t.channel = c; }
#endif
11.13.3 互为友元类
Tvbuzz.h
#pragma once
#ifndef Tv_BUZZ_H_
#define Tv_BUZZ_H_
#include<iostream>
class Remote_2;
class Tv_2
{
friend class Remote_2;
public:
void buzz(Remote_2& r);
enum { Off, On };
enum { MinVal, MaxVal = 20 };
enum { Antenna, Cable };
enum { TV, DVD };
Tv_2(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_2 or DVD
};
class Remote_2
{
friend class Tv_2;
public:
Remote_2(int m = Tv_2::TV) : mode(m) {}
bool volup(Tv_2& t) { return t.volup(); }
bool voldown(Tv_2& t) { return t.voldown(); }
void onoff(Tv_2& t) { t.onoff(); }
void chanup(Tv_2& t) { t.chanup(); }
void chandown(Tv_2& t) { t.chandown(); }
void set_chan(Tv_2& t, int c) { t.channel = c; }
void set_mode(Tv_2& t) { t.set_mode(); }
void set_input(Tv_2& t) { t.set_input(); }
private:
int mode; // controls Tv_2 or DVD
};
inline void Tv_2::buzz(Remote_2& r)
{
std::cout << "电视发出了警报!" << std::endl;
}
bool Tv_2::volup()
{
if (volume < MaxVal)
{
volume++;
return true;
}
else
return false;
}
bool Tv_2::voldown()
{
if (volume > MinVal)
{
volume--;
return true;
}
else
return false;
}
void Tv_2::chanup()
{
if (channel < maxchannel)
channel++;
else
channel = 1;
}
void Tv_2::chandown()
{
if (channel > 1)
channel--;
else
channel = maxchannel;
}
void Tv_2::settings() const
{
using std::cout;
using std::endl;
cout << "Tv_2 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;
}
}
#endif
11.13.4 共享友元函数
共享友元函数:就是函数为两个或多个类的友元函数。
Analyzer_sync_Probe.h
#pragma once
//Analyzer_sync_Probe.h
#ifndef PASYNC_H_
#define PASYNC_H_
#include<iostream>
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 functions
inline void sync(Analyzer& a, const Probe& p)
{
std::cout << "Analyzer sync Probe" << std::endl;
}
inline void sync(Probe& p, const Analyzer& a)
{
std::cout << "Probe sync Analyzer" << std::endl;
}
#endif
11.13.5 举例
代码:
/*
Project name : _15Friend_Classes
Last modified Date: 2022年3月28日09点37分
Last Version: V1.0
Descriptions: 友元
1.友元类,头文件为tv.h
2.友元成员函数,头文件为tvfm.h
3.互为友元类,头文件为Tvbuzz.h
4.共享友元函数,头文件为Analyzer_sync_Probe.h
*/
#include <iostream>
#include "tv.h"
#include "tvfm.h"
#include "Tvbuzz.h"
#include "Analyzer_sync_Probe.h"
int main()
{
using std::cout;
using std::endl;
/*友元类,头文件为tv.h*/
cout << "友元类开始*******************************************************" << endl;
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();
cout << "友元类结束*******************************************************" << endl;
/*友元成员函数,头文件为tvfm.h*/
cout << "友元成员函数开始*************************************************" << endl;
Tv_1 s43;
cout << "Initial settings for 43\" TV:\n";
s43.settings();
s43.onoff();
s43.chanup();
cout << "\nAdjusted settings for 43\" TV:\n";
s43.settings();
Remote_1 grey1;
grey1.set_chan(s43, 10);
grey1.volup(s43);
grey1.volup(s43);
cout << "\n43\" settings after using remote:\n";
s43.settings();
Tv_1 s59(Tv_1::On);
s59.set_mode();
grey1.set_chan(s59, 28);
cout << "\n59\" settings:\n";
s59.settings();
cout << "友元成员函数结束************************************************" << endl;
/*互为友元类,头文件为Tvbuzz.h*/
cout << "互为友元类开始***************************************************" << endl;
Tv_2 s44;
cout << "Initial settings for 44\" TV:\n";
s44.settings();
Remote_2 grey2;
grey2.onoff(s44);
grey2.set_chan(s44, 10);
grey2.volup(s44);
grey2.volup(s44);
cout << "\n44\" settings after using remote:\n";
s44.settings();
s44.buzz(grey2);
cout << "互为友元类结束**************************************************" << endl;
/*共享友元函数,头文件为Analyzer_sync_Probe.h*/
cout << "共享友元函数开始************************************************" << endl;
Probe p1;
Analyzer a1;
sync(p1, a1);
sync(a1, p1);
cout << "共享友元函数结束************************************************" << endl;
return 0;
}
运行结果:
友元类开始*******************************************************
Initial settings for 42" TV:
TV is Off
Adjusted settings for 42" TV:
TV is On
Volume setting = 5
Channel setting = 3
Mode = cable
Input = TV
42" settings after using remote:
TV is On
Volume setting = 7
Channel setting = 10
Mode = cable
Input = TV
58" settings:
TV is On
Volume setting = 5
Channel setting = 28
Mode = antenna
Input = TV
友元类结束*******************************************************
友元成员函数开始*************************************************
Initial settings for 43" TV:
TV is Off
Adjusted settings for 43" TV:
TV is On
Volume setting = 5
Channel setting = 3
Mode = cable
Input = TV
43" settings after using remote:
TV is On
Volume setting = 7
Channel setting = 10
Mode = cable
Input = TV
59" settings:
TV is On
Volume setting = 5
Channel setting = 28
Mode = antenna
Input = TV
友元成员函数结束************************************************
互为友元类开始***************************************************
Initial settings for 44" TV:
Tv_2 is Off
44" settings after using remote:
Tv_2 is On
Volume setting = 7
Channel setting = 10
Mode = cable
Input = TV
电视发出了警报!
互为友元类结束**************************************************
共享友元函数开始************************************************
Probe sync Analyzer
Analyzer sync Probe
共享友元函数结束************************************************
D:\Prj\_C++Self\_15Friend_Classes\Debug\_15Friend_Classes.exe (进程 13476)已退出,代码为 0。
要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
按任意键关闭此窗口. . .