C++中什么是友元?友元的存在形式有?友元有何特点?

目录

一、友元函数

1.非成员函数

2.成员函数

3.友元函数的重载

二、友元类

三、友元与封装性


私有成员只能在类的成员函数内部访问,如果想在别处访问对象的私有成员,只能通过类提供的接口(成员函数)间接地进行。这固然能够带来数据隐藏的好处,利于将来程序的扩充,但也会增加程序书写的麻烦。

C++ 是从结构化的C语言发展而来的,需要照顾结构化设计程序员的习惯,所以在对私有成员可访问范围的问题上不可限制太死。

C++ 设计者认为, 如果有的程序员真的非常怕麻烦,就是想在类的成员函数外部直接访问对象的私有成员,那还是做一点妥协以满足他们的愿望为好,这也算是眼前利益和长远利益的折中。因此,C++ 就有了友元(friend)的概念。打个比方,这相当于是说:朋友是值得信任的,所以可以对他们公开一些自己的隐私。

友元提供了一种 普通函数或者类成员函数 访问另一个类中的私有或保护成员 的机制。也就是说有两种形式的友元:

(1)友元函数:普通函数对一个访问某个类中的私有或保护成员。

(2)友元类:类A中的成员函数访问类B中的私有或保护成员。

下面来具体讨论友元函数友元类的概念。

一、友元函数

引用wikipedia对友元函数的解释

( In object-oriented programming, a friend function, that is a "friend" of a given class, is a function that is given the same access as methods to private and protected data. [1]

A friend function is declared by the class that is granting access, so friend functions are part of the class interface, like methods. Friend functions allow alternative syntax to use objects, for instance f(x) instead of x.f(), or g(x,y) instead of x.g(y). Friend functions have the same implications on encapsulation as methods. )

私有成员只能在类的成员函数内部访问,如果想在别处访问对象的私有成员,只能通过类提供的接口(成员函数)间接地进行。这固然能够带来数据隐藏的好处,利于将来程序的扩充,但也会增加程序书写的麻烦。
 

在面向对象编程中,友元函数(friend function)是一个指定类(class)的“朋友”,该函数被允许访问该类中private、protected、public的数据成员。普通的函数并不能访问这些数据,然而宣告一个函数成为一个类的友元函数则被允许访问这些数据。

友元函数的宣告可以放在类声明的任何地方,不受访问限定关键字private、protected、public的限制。一个相似的概念是友谊类。

友谊关键字应该谨慎使用。如果一个拥有private或者protected成员的类,宣告过多的友元函数,可能会降低封装性的价值,也可能对整个设计框架产生影响。

1.非成员函数

在类的定义中用friend声明了一个外部函数或其他类的成员函数(publicprivate均可)后,这个外部函数称为类的友元函数。

友元函数声明的基本格式为:

  friend 函数原型;

友元函数中可访问类的private成员

用下面的比喻形容友元函数可能比较恰当,将类比作一个家庭,类的private成员相当于家庭的秘密,一般的外人是不允许探听这些秘密的,只有friend(朋友)才有能力探听这些秘密。

见如下代码

//将一个外部函数申明为类的友元函数
#include 	//使用计算平方根的函数sqrt要用到的头文件
#include 
using namespace std;

class Point										//Point类定义
{
private:
	int x, y;
	//	friend float dis(Point &p1, Point & p2);	//友元函数的声明,声明位置没有关系
	//可以是public,也可是private

public:
	Point(int i = 0, int j = 0)	//构造函数,带缺省参数值
	{
		x = i;
		y = j;
	}

	void disp()			//成员函数
	{
		cout << "(" << x << "," << y << ")";
	}
};

float dis(Point & p1, Point & p2)		//友元函数的实现
{
	//友元函数中可访问类的private成员
	float d = sqrt((p1.x - p2.x)*(p1.x - p2.x) + (p1.y - p2.y)*(p1.y - p2.y));
	return d;
}

int main()
{
	Point p1(1, 2), p2(4, 5);	//声明两个Point类的对象p1和p2
	p1.disp();			//显示点p1的信息

	cout << "与";
	p2.disp();			//显示点p2的信息

	cout << "距离=" << dis(p1, p2) << endl;	//利用友元函数计算两点举例

	return 0;
}

2.成员函数

A类的成员函数作为B类的友元函数时,必须先定义A类,而不仅仅是声明它。

注意:将其他类的成员函数申明为本类的友元函数后,该友元函数并不能变成本类的成员函数。也就是说,朋友并不能变成家人。

成员形式的友元函数见下方代码

下述代码中,Line类的成员函数dis(…)的实现必须在类外进行,且必须在Point类的定义之后。因为其参数中包含了Point这种类型。

Line类的dis()函数本来是不能访问Point.xPint.y这种Point类的private成员的,但在Point类中将dis()申明为友元函数后就能访问了。但dis()函数依然不是Point类的成员函数。也就是说,dis() Point类的朋友了,可以访问Point类的私有成员变量xy了。

//将Line类的成员函数dis()作为Point类的友元函数
#include 		//使用计算平方根的函数sqrt要用到的头文件
#include 
#include 
using namespace std;

class Point;		//声明Point类

class Line			//定义Line类
{
public:
	float dis(Point& p1, Point& p2); 		//友元函数的原型,作为Line类的成员函数
};

class Point					//定义Point类
{
private:
	int x, y;				//private型数据成员x和y
	friend float Line::dis(Point &p1, Point &p2);	//友元的声明

public:
	Point(int i = 0, int j = 0)	//Point类的构造函数,带缺省参数
	{
		x = i;
		y = j;
	}

	void disp()			//成员函数disp(),用来输出点的信息
	{
		cout << "(" << x << "," << y << ")";
	}
};

//Line类内成员函数dis的实现,作为Point类的友元函数
float Line::dis(Point &p1, Point &p2)
{
	float d = sqrt((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y));
	//可访问Point类对象的private成员

	return d;
}

int main()
{
	Line line1;			//声明一个Line类的对象line1
	Point p1(1, 2), p2(4, 5);		//声明两个Point类的对象p1和p2

	p1.disp();			//输出点p1的信息 
	cout << " 与 ";
	p2.disp();			//输出点p2的信息

	cout << " 的距离 = " << line1.dis(p1, p2) << endl;
	//通过调用line1的成员函数dis计算两个点间的距离

	return 0;
}

3.友元函数的重载

要想使得一组重载函数全部成为类的友元,必须一一声明,否则只有匹配的那个函数会成为类的友元,编译器仍将其他的当成普通函数来处理。

class Exp
{
public:
firend void test(int); 	
};
void test();
void test(int);
void test(double);

上述代码中,只有“void test(int)”函数是Exp类的友元函数,“void test()”和“void test(double)”函数都只是普通函数。

二、友元类

引用wikipedia对友元类的解释

( A friend class in C++ can access the private and protected members of the class in which it is declared as a friend.[1] A significant use of a friend class is for a part of a data structure, represented by a class, to provide access to the main class representing that data structure. The friend class mechanism allows to extend the storage and access to the parts, while retaining proper encapsulation as seen by the users of the data structure. )

C ++中的友元类可以访问声明为朋友的类的私有成员和受保护成员。[1] 友元类的重要用途是用于表示由类表示的数据结构的一部分,以提供对表示该数据结构的主类的访问。 友元类机制允许扩展存储和对部件的访问,同时保持数据结构的用户所看到的适当封装。

A作为类B的友元时,类A称为友元类。A中的所有成员函数都是B的友元函数,都可以访问B中的所有成员。

A可以在Bpublic部分或private部分进行声明,方法如下:

friend [class]<类名>; //友元类类名

见下方代码

//9-6 友元类
#include
#include 
using namespace std;

class CLine;	//声明类CLine

class CPoint 	//定义CPoint类
{
private:
	int x, y;
	friend class CLine; //友元类的声明,位置同样不受限制

public:
	CPoint(int i = 0, int j = 0) //构造函数,带缺省参数值
	{
		x = i;
		y = j;
	}

	void disp() //成员函数,输出点的信息
	{
		cout << "(" << x << "," << y << ")";
	}
};

class CLine	//类CLine的定义,其中所有的函数都是CPoint类的友元函数
{
public:
	float dis(CPoint& p1, CPoint& p2)	//可访问p1和p2的private成员
	{
		float d;
		d = sqrt((p1.x - p2.x)*(p1.x - p2.x) + (p1.y - p2.y)*(p1.y - p2.y));
		return d;
	}

	void Set(CPoint* p1, int a, int b)		//可访问p1和p2的private成员
	{
		p1->x = a;
		p1->y = b;
	}
};

int main()
{
	CLine cz1;			//声明一个CLine类的对象cz1
	CPoint p1(1, 2), p2(4, 5);	//声明两个CPoint类对象p1和p2

	p1.disp();				//输出点p1的信息 
	cout << "与";
	p2.disp();				//输出点p2的信息
	cout << "距离=" << cz1.dis(p1, p2) << endl;	//调用cz1的成员函数dis计算两点间距

	cz1.Set(&p1, 3, 4);		//调用cz1的成员函数Set改写p1中的private成员x和y
	p1.disp();			//修改后的点p1信息输出

	cout << endl;		//换行

	return 0;
}

三、友元与封装性

优点:提高了程序的运行效率。

缺点:破坏了类的封装性和数据的透明性。

不可否认,友元在一定程度上将类的私有成员暴露出来,破坏了信息隐藏机制,似乎是种副作用很大的药,但俗话说良药苦口,好工具总是要付出点代价的,拿把锋利的刀砍瓜切菜,总是要注意不要割到手指的。

友元的存在,使得类的接口扩展更为灵活,使用友元进行运算符重载从概念上也更容易理解一些,而且,C++规则已经极力地将友元的使用限制在了一定范围内,它是单向的、不具备传递性、不能被继承,所以,应尽力合理使用友元

 

你可能感兴趣的:(C++学习,友元,C++,friend,friend,function,friend,class)