C++学习笔记33——友元

1,友元的基本概念

友元:类授权访问其非public成员的机制。类和函数都可以被指定为友元。友元拥有与成员一样的访问权相。
 
友元可以分成3类:
(1)普通函数(非类的成员函数)成为一个类类型B的友元;
(2)一个类A 的成员函数,成为另一个类类型B的友元;
(3)一个类A,成为一个类类型B的友元,如此,则该类A 的所有成员函数都成为类B的友元;
 
友元函数或友元类在类的定义体中,用friend关键字声明。
 
注意:
(1)友元不是类B的成员,所以其没有类B的对象的this指针;
(2)所以,虽然友元可以访问类B的私有成员,但需要程序将类B的对象作为参数传递给友元函数,当然,全局变量除外;
(3)同样由于没有this指针,在友元中使用私有成员时,必须指明对象,而不能像在类B的成员函数里那样隐式地使用this指针;
(4)由于友元不是类的成员,所以friend声明放在public段还是private段都行,且没有区别;
(5)friend关键字不能出现的类定义之外,即,只在声明友元的时候使用friend,定义时不能写(定义时你也不知道他是谁的friend啊)。
 

2,普通函数用作友元

/*******************************************************************/
//      友元
/*******************************************************************/
class Point
{
public:
	Point(double xx, double yy) :x(xx), y(yy) {}//定义构造函数
	void show_pos() { cout << "x: " << x << " " << "y:" << y << endl; }//定义普通成员函数
	friend double Distance(Point &A, Point &B);//声明友元函数
	friend double Distance_2(Point &A, Point &B)//定义友元函数
	{
		double x = A.x - B.x;
		double y = A.y - B.y;
		return sqrt(x*x + y*y);
	}
private:
	double x, y;
};


// 在main函数中调用友元函数
int main()
{	
	Point A(0, 0);
	Point B(3, 4);

	cout << Distance(A, B) << endl;
	cout << Distance_2(A, B) << endl;
	system("pause");
	return 0;
}

//定义友元函数
double Distance(Point &A, Point &B)
{
	double x = A.x - B.x;
	double y = A.y - B.y;
	return sqrt(x*x + y*y);
}

 
最终输出:5
                    5
从例子中可以看出:
(1)Distance()虽然是类Point的友元,但是,还是必须将Point类的对象A和B传递给Distance(),其才能使用Point类的私有成员。
(2)在Point类中声明Distance()为友元的时候,Distance()可以是既没有声明、也没有被定义的状态,即友元不必预先声明,友元声明中声明的函数被视为已使用 extern 关键字声明,此时该友元函数具有文件作用域,或者说命名空间作用域。
(3)但是,在定义友元函数时,类必须是已经声明好的。因为友元要用到类中的成员。总之:类的定义要在友元的定义之前。
(4)友元函数也可以直接在类中定义,如Distance_2()。类声明中定义的友元函数不被认为在封闭类的范围内;它们在文件范围内。
 

3,类的成员函数用作友元

/*******************************************************************/
//      友元
/*******************************************************************/
class Point;//提前声明point类,因为Line的成员函数要用到

//定义友元函数所在的类
class Line
{
public:
	Line(double kk, double bb) :k(kk), b(bb) {}//构造函数
	bool judege_point_in_line(Point &A);//判断点是否在线上,要用到point的私有成员
private:
	double k, b;
};

//定义友元函数要获取权限的类
class Point
{
public:
	Point(double xx, double yy) :x(xx), y(yy) {}//定义构造函数
	void show_pos() { cout << "x: " << x << " " << "y:" << y << endl; }//定义普通成员函数
	friend double Distance(Point &A, Point &B);//声明友元函数
	friend double Distance_2(Point &A, Point &B)//定义友元函数
	{
		double x = A.x - B.x;
		double y = A.y - B.y;
		return sqrt(x*x + y*y);
	}
	friend bool Line::judege_point_in_line(Point &A);//声明另一个类的成员函数为友元
private:
	double x, y;
};

// 定义友元函数
bool Line::judege_point_in_line(Point &p)
{
	return (p.y == k*p.x + b);
}

// 在main()函数中调用友元函数
int main()
{
	Point A(0, 0);
	Point B(3, 4);
	Line l1(1, 0);	

	// 调用一般友元函数
	cout << Distance(A, B) << endl;
	cout << Distance_2(A, B) << endl;

	// 调用类的成员函数友元
	cout << l1.judege_point_in_line(A) << endl;
	cout << l1.judege_point_in_line(B) << endl;

	system("pause");
	return 0;
}
最终输出:5
                    5
                    1
                    0
 
编码的顺序逻辑如下:
要定义Line::judege_point_in_line(Point &p)友元函数,必须要先定义Point类,因为函数的输入参数为Point型,且函数体中用到了Point的成员;
在定义Point类时声明judege_point_in_line为友元函数;
要定义Point类必须先定义Line类,因为Point类中出现了Line类的成员函数judege_point_in_line;
要定义Line类必须先提前声明Point类,因为Line中的成员函数judege_point_in_line(Point &p)使用了Point类型为输入参数;
 
总结下来,如果要声明类A中的成员函数mem_fun()为类B的友元,则正确的编码顺序是:
(1)提前声明类B(仅仅是声明不是定义);
(2)定义类A,在类A中声明(无法定义,因为B还没定义)注定会成为B的友元的那个成员函数mem_fun();
(3)定义类B,在类B中声明A中的成员函数mem_fun()为友元;
(4)定义B的成员函数mem_fun()。
 

4,整个类用作友元

如果类A成为类B的友元,则类A中的每个成员函数都能访问类B的私有和保护成员。
编码的顺序与设置类的成员函数为友元相同。
将Point类的定义部分修改为如下形式,执行结果不变。
class Point
{
public:
	Point(double xx, double yy) :x(xx), y(yy) {}//定义构造函数
	void show_pos() { cout << "x: " << x << " " << "y:" << y << endl; }//定义普通成员函数
	friend double Distance(Point &A, Point &B);//声明友元函数
	friend double Distance_2(Point &A, Point &B)//定义友元函数
	{
		double x = A.x - B.x;
		double y = A.y - B.y;
		return sqrt(x*x + y*y);
	}
	//friend bool Line::judege_point_in_line(Point &A);//声明另一个类的成员函数为友元
	friend class Line;//将整个类声明为友元,class好像写不写都行,存疑

private:
	double x, y;
};
 

5,重载函数与友元

重载函数本质上是不同的函数,只是重名而已。所以必须将重载函数集中每一个想要设为友元的函数都声明为友元。只设置一个却期待重载函数集中的每个函数都成为友元是不对的。——这就好比你和一个叫王海燕的人是朋友,但不代表你和每一个与王海燕重名的人都是朋友。
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值