一、友元
在C++中,类具有封装性和隐蔽性,类的数据成员一般都定义为私有成员,成员函数一般都定义为公有的,以此提供类与外界的通讯接口。但是,某些成员函数频繁调用时,由于函数参数的传递、C++严格的类型检查和安全性检查将带来时间的开销,为了解决这个问题,C++提出了使用友元作为实现这一要求的辅助手段。友元不是类的成员,但它可以访问类的任何成员(包括私有成员)。声明为友元的外界对象既可以是另一个类的成员函数,也可以是不属于任何类的一般的函数,称之为友元函数;友元也可以是整个的一个类,称之为友元类。
二、友元函数
友元函数是可以直接访问类的私有成员的非成员函数。它是定义在类外的普通函数,它不属于任何类,但需要在类的定义中加以声明,声明时只需在友元的名称前加上关键字friend,其格式如下:
friend 类型 函数名(形式参数);
1、友元函数的定义与成员函数一样,只是在类中用关键字friend予以说明。但友元函数是一个普通的函数,它不是本类的成员函数,因此在调用时不能通过对象调用。也没有this指针。
2、友元函数也可以在类内声明,在类外定义。
3、友元函数对类成员的存取与成员函数一样,可以直接存取类的任何存取控制属性的成员;可通过对象存取形参、函数体中该类类型对象的所有成员。
4、private、protected、public访问权限与友员函数的声明无关,因此原则上,友元函数声明可以放在类体中任意部分,但为程序清晰,一般放在类体的后面。
5、使用友元成员的好处是两个类可以某种方式相互合作、协同工作,共同完成某一任务。
演示
1、不属于任何类的一般的函数声明为友元:
#include "cmath"
#include "iostream"
using namespace std;
class Point
{
public:
Point(double xx, double yy)
{
x = xx;
y = yy;
}
void GetXY();
friend double Distance(Point &a, Point &b);
protected:
private:
double x, y;
};
void Point::GetXY()
{
//cout<<"("<<this->x<<","<<this->y<<")"<<endl;
cout << "(" << x << "," << y << ")" << endl;
}
double Distance(Point &a, Point &b)//前面不能加作用域Point::
{
double length;
length = sqrt((a.x - b.x)*(a.x - b.x) + (a.y - b.y)*(a.y - b.y)); //它可以引用类中的私有成员
return length;
}
int main(void)
{
Point p1(3.0, 4.0), p2(6.0, 8.0);
p1.GetXY(); //成员函数的调用方法,通过使用对象来调用
p2.GetXY();
double d = Distance(p1, p2); //友元函数的调用方法,同普通函数的调用一样,不要像成员函数那样调用
cout << d << endl;
system("pause");
return 0;
}
说明:在该程序中的Point类中说明了一个友元函数Distance(),它在说明时前边加friend关键字,标识它不是成员函数,而是友元函数。它的定义方法与普通函数定义一样,而不同于成员函数的定义,因为它不需要指出所属的类。但是,它可以引用类中的私有成员,函数体中的a.x,b.x,a.y,b.y都是类的私有成员,它们是通过对象引用的。在调用友元函数时,也是同普通函数的调用一样,不要像成员函数那样调用。
2、类成员函数声明为友元示例:
class A;//注意前向引用声明
class B
{
public:
int func(A,int);
};
class A
{
friend int B::func(A,int);
};
说明:因为你要类成员函数作为友元,你在声明友元的时候要用类限定符,所以必须先定义包含友元函数的类,但是在定义友元的函数时候,又必须事先定义原始类。通常的做法先定义包含友元函数的类,再定义原始类,这个顺序不能乱。
三、友元类
友元除可以是函数外,还可以是类,如果一个类声明为另一个类的友元,则该类称为另一个类的友元类。若A类为B类的友元类,则A类的所有成员函数都是B类的友元函数,都可以访问B类的任何数据成员。 友元类的声明是在类名之前加上关键字friend来实现。
1、友元类演示:
#include "iostream"
using namespace std;
class Circle;//注意前向引用声明
class Point
{
private:
double x, y;
void ShowXY()
{
cout << "(" << this->x << "," << this->y << ")" << endl;
}
public:
Point(double xx = 0, double yy = 0)
{
x = xx;
y = yy;
}
void GetXY()
{
cout << "(" << x << "," << y << ")" << endl;
}
friend class Circle;
};
class Circle
{
private:
Point point;
double r;
public:
Circle(Point P, double R)
{
point = P;
r = R;
}
Point Get_top()
{
//可以直接访问Point类的私有成员函数
point.ShowXY();
Point top;
//可以直接访问Point类的私有成员数据
top.x = this->point.x;//this指针可用
top.y = point.y + r;
return top;
}
};
int main(void)
{
Point P1(3.4, 5.6);
double R1 = 2.1;
Point P2;
Circle C(P1, R1);
P2 = C.Get_top();
P2.GetXY();
//P2.ShowXY();则不可以访问其私有成员
return 0;
}
//运行结果:
//(3.4,5.6)
//(3.4,7.7)
2、友元关系具有以下性质:
a、友元关系是不能传递的,B类是A类的友元,C类是B类的友元,C类和A类之间,如果没有声明,就没有任何友元关系,不能进行数据共享。
b、友元关系是单向的,如果声明B类是A类的友元,B类的成员函数就可以访问A类的私有和保护数据,但A类的成员函数却不能访问B类的私有和保护数据。
c、友元不能被继承,B是A的友元类,C是B的子类,不能因此得出C是A的友元。
四、总结
1、友元概念的引入,提高了数据的共享性,加强了函数与函数之间,类与类之间的相互联系,大大提高程序的效率,这是友元的优点,但友元也破坏了数据隐蔽和数据封装,导致程序的可维护性变差,给程序的重用和扩充埋下了深深的隐患,这是友元的缺点。
2、对友元的使用必须慎重,要具体问题具体分析,在提高效率和增加共享之间把握好一个“度”,在共享和封装之间进行恰当的折衷平衡。
如有错误或不足欢迎评论指出!创作不易,转载请注明出处。如有帮助,记得点赞关注哦(⊙o⊙)
更多内容请关注个人博客:https://blog.csdn.net/qq_43148810