C++友元

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。
要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
按任意键关闭此窗口. . .
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Jasmine-Lily

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值