什么叫做友元?它是C++中的一种关系,包括类与类之间和函数与类之间,友元关系是单向的,并且不能传递。
为什么本节名字叫尴尬友元?因为由于友元的强大能力降低了程序的效率以及破坏了C++中的封装性,导致了在现代软件开发中已经几乎摒弃了这种能力。在类中,以friend关键字作为声明友元关系的关键字,一个类的友元可以是另一个类或者是一个函数,但是友元却并不是类中的一部分,存在友元关系的可以不受类中的访问级别的制约直接访问类中的所有成员变量,包括私有变量。先展示一下友元的强大能力,看一个函数作为友元的例子,利用友元访问类中所有成员变量:
class Point
{
double x;
double y;
public:
Point(double x, double y)
{
this->x = x;
this->y = y;
}
friend double distance(Point& p1, Point& p2);
};
double distance(Point& p1, Point& p2)
{
double dis = 0;
dis = sqrt( (p2.y - p1.y) * (p2.y - p1.y) +(p2.x - p1.x) * (p2.x - p1.x) );
return dis;
}
int main()
{
Point p1(1, 2);
Point p2(10, 20);
printf("Distance(p1, p2) = %f\n", distance(p1, p2));
return 0;
}
类Point中有两个私有成员变量,一个构造函数,里面利用this指针初始化对象成员变量(将this指针利用起来,值得学习),在类的最后声明了一个友元关系,表示函数distance能够随便访问类Point的成员变量,在类的外部实现了一个函数,通过访问对象成员变量计算距离。
这样看起来是不是觉得友元的能力十分强大,竟然连类的私有变量都能够访问。友元是为了兼顾C的高效而诞生的,,但是友元的使用直接破坏了面向对象的封装性,友元在实际产品中的高效是得不偿失的,在现代软件工程中已经逐渐被遗弃。
虽然影响了效率,但是可能在某些场合下是不得不使用的,所以它的注意事项还是需要知道的:
1、友元关系不具备传递性。
2、类的友元可以是其他类的成员函数。
3、类的友元可以是某个完整的类,即所有的成员函数都是类的友元(本质)。
看一个类作为友元例子,理解类之间的友元不具有传递性;
class ClassC
{
const char* n;
public:
ClassC(const char* n)
{
this->n = n;
}
friend class ClassB;
};
class ClassB
{
const char* n;
public:
ClassB(const char* n)
{
this->n = n;
}
void getClassCName(ClassC& c)
{
printf("c.n = %s\n", c.n);
}
friend class ClassA;
};
class ClassA
{
const char* n;
public:
ClassA(const char* n)
{
this->n = n;
}
void getClassBName(ClassB& b)
{
printf("b.n = %s\n", b.n);
}
/***友元不具有传递性,所以不能访问ClassC
void getClassCName(ClassC& c)
{
printf("c.n = %s\n", c.n);
}
****/
};
定义了三个类,A是B的友元,B是C的友元,所以A可以访问B的成员变量,B可以访问C的成员变量,最后试图在A中访问C的成员变量,但是编译器会报错。
友元关系看似很强大,但实则并不是多么高效,在面向对象的程序设计中就应该尽量不使用面向过程的设计方法。