C++友元

友元类:
什么时候希望一个类成为另一个类友元类呢?
举个例子,假设需要编写一个模拟电视和遥控器的简单程序,定义了一个Tv类和Remote类表示。这两个类之间存在某种关系,电视机并非遥控器,反之亦然,所以公有继承is-a关系并不适用。遥控器也并非电视机的一部分,反之亦然,因此包含或私有继承和保护继承的has-a关系也不适用。事实上,遥控器可以改变电视机的状态,这表明应将Remote类作为Tv类的一个友元类。友元类可以访问当前类的私有和保护成员。

友元函数:

#include<iostream>
#include<string>
using namespace std;
class Tv
{
	enum { OFF, ON };//枚举类型没有占用内存(占用内存的只是变量)
	enum { Antenna,Cable};
private:
	int state;
	int mode;
	int channel;
	int maxchannel;
public:
	friend class Remote;//友元类前向声明
	Tv(int s=OFF) :state(s) ,mode(Cable),channel(0),maxchannel(100){}
	void onoff() { state ^= state; }
	bool ison() { return state == ON; }
	void set_mode(){ mode ^= mode; }
};
class Remote
{
private:
	//
public:
	Remote() {}
	void onoff(Tv&t) { t.onoff(); }
	void set_mode(Tv&t) { t.set_mode(); }
	void set_channel(Tv&t, int c) { t.channel = c; }
};
void main()
{
	Tv haier;
	Remote r1;
	r1.onoff(haier);
	r1.set_mode(haier);
	r1.set_channel(haier, 10);
	cout << sizeof(Tv) << endl;//16字节
	cout << sizeof(Remote) << endl;//1字节,内存大小最少是1字节(所以class Remote这里是1字节)
}

友元成员函数:
上述的代码中Remote的大多数方法是通过调用Tv的公有接口实现的。意味这些方法不是真正需要作为友元。事实上唯一直接访问Tv成员的Remote方法是Remote::set_channel( …),因此这是唯一一个需要作为友元的方法。
在Tv类中声明中将其声明为友元:

class Tv
{
	friend void Remote::set_channel(Tv&t, int c);
	...
};

这时候需要修改一下类的声明顺序:

class Tv;//前向声明
class Remote{...};
class Tv{...};
#include<iostream>
#include<string>
using namespace std;
class Tv;
class Remote
{
private:

public:
	Remote() {}
	void onoff(Tv&t) ;
	void set_mode(Tv&t) ;
	void set_channel(Tv&t, int c);

};
class Tv
{
	enum { OFF, ON };
	enum { Antenna,Cable};
private:
	int state;
	int mode;
	int channel;
	int maxchannel;
public:
	friend void Remote::set_channel(Tv&t, int c);
	Tv(int s=OFF) :state(s) ,mode(Cable),channel(0),maxchannel(100){}
	void onoff() { state ^= state; }
	bool ison() { return state == ON; }
	void set_mode(){ mode ^= mode; }
};
inline  void Remote::onoff(Tv & t){t.onoff();}
inline void Remote::set_mode(Tv & t){t.set_mode();}
inline void Remote::set_channel(Tv & t, int c){t.channel = c;}
void main()
{
	Tv haier;
	Remote r1;
	r1.onoff(haier);
	r1.set_mode(haier);
	r1.set_channel(haier, 10);
}

还有一点需要注意:Remote类使用到Tv对象的方法,必须先声明,但不能给定义(原因:和编译器有关)。定义必须在后面再给出详细的定义,比较短的代码可以定义成内联函数。

其他用法:
1两个类可以是相互的友元

class Tv
{
	friend class Remote;
	publicvoid buzz(Remote&r);
	...
};
class Remote
{
	friend class Tv;
	public...
};
inline void Tv::buzz(Remote::r)
{
	...
}

2共同的友元
当函数需要访问两个类的私有成员时,那么当前类可以是一个类的成员,同时是另一个类的友元,但是有时将函数作为两个类的友元更加合理:

class A;//前向声明
class B
{
	friend void sync(A&a,const B&b);
	friend void sync(B&b,const A&a);
	...
}
class A
{
	friend void sync(A&a,const B&b);
	friend void sync(B&b,const A&a);
	...
}

inline void sync(A&a,const B&b)
{
}
inline void sync(B&b,const A&a)
{
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值