1、友元的概念
- 什么是友元?
— 友元是C++ 中的一种关系
— 友元关系是单向的,不能传递
— 友元关系发生在 函数与类之间 或者 类与类 之间
左边的函数是右边类的友元,左边的函数就成了友元
2、友元的用法
- 友元可以直接访问具体类的所有成员
- 在类中以 friend 关键字声明友元
- 类的友元可以是其它类或者具体函数
- 友元不是类的一部分
- 友元不受类中访问级别的限制
3、友元的语法
- 在类中用 friend 关键字对函数或类进行声明
class Test
{
double x;
double y;
friend void func(Test& t);
};
void func(Test& t)
{
}
在这个程序中,函数 func 是Test 类的友元,因此,函数就可以直接访问类中的所有成员
#include <stdio.h>
#include <math.h>
class Test
{
double x;
double y;
public:
Test(double x, double y)
{
this->x = x;
this->y = y;
}
double getX()
{
return x;
}
double getY()
{
return y;
}
friend double func(Test& t3, Test& t4);
};
double func(Test& t3,Test& t4)
{
double ret = 0;
//ret = (t4.getY() - t3.getY())*(t4.getY() - t3.getY()) +
// (t4.getX() - t3.getX())*(t4.getX() - t3.getX());
ret = (t4.y - t3.y)*(t4.y - t3.y) +
(t4.x - t3.x)*(t4.x - t3.x);
ret = sqrt(ret);
return ret;
}
int main()
{
Test t1(1, 2);
Test t2(10, 20);
printf("t1(%lf,%lf)\n", t1.getX(), t1.getY());
printf("t2(%lf,%lf)\n", t2.getX(), t2.getY());
printf("|(t1,t2)| = %lf\n",func(t1, t2));
return 0;
}
分析:我们定义一个 func 函数来计算两个对象坐标的距离。如果我们不把 func 函数定义为Test 类的友元,那么计算函数里面我们只能借助对象参数来调用 getX()和getY()函数。如果是这样,那么一共要调用8次函数(详见程序的27 和28 行代码),极其麻烦。
如果我们把 func 函数定义为Test 类的友元,那么参数对象就可以直接访问类里面的所有成员,包括私有成员。(详见程序的 30 和 31 行代码),这样就避免了一直要访问函数
4、友元的尴尬
- 友元是为了兼顾C语言的高效而诞生的
- 友元直接破坏了面向对象的封装性
- 友元在实际产品中的高效是得不偿失的
- 友元在现代软件工程中已经逐渐被遗弃
5、注意事项
- 友元关系不具备传递性
- 类的友元可以是其它类的成员函数
- 类的友元可以是某个完整的类
— 所有的成员函数都是友元
#include <stdio.h>
class classC
{
private:
const char* n3;
public:
classC(const char* n3)
{
this->n3 = n3;
}
friend class classB;
};
class classB
{
private:
const char* n2;
public:
classB(const char* n2)
{
this->n2 = n2;
}
void getClassCname(classC& c)
{
printf("%s\n", c.n3);
}
friend class classA;
};
class classA
{
private:
const char* n1;
public:
classA(const char* n1)
{
this->n1 = n1;
}
//A是B的友元,所以在B的类中声明,A可以任意访问B中的所有成员
void getClassBname(classB& b)
{
printf("%s\n", b.n2);
}
};
int main()
{
classA A("A");
classB B("B");
classC C("C");
A.getClassBname(B);
B.getClassCname(C);
return 0;
}
分析:其实这个程序我还是折腾了挺久的,因为它老是报错。
首先来源于我对知识点认知的错误,一开始我以为友元可以直接访问具体类的所有成员,所以我就在主函数定义用类A定义对象来访问另一个类B(A是B的友元)里面的私有成员,发现一直报错。后来才发现:声明为友元,只是允许在A的作用域里随意访问,主函数不是A的作用域。也就是说我们可以在A类里面成员函数的参数里面定义B的对象,在这个函数里面访问类B。
其次,这个类的先后顺序还是很重要的,如果你定义类A是类B的友元,类A可以随意访问类B里面的所有成员,那么你要先定义class B,再定义class A。
最后:A是B的友元,A是成员函数或者类,B一定是类。在B的类中声明,B要比A先定义出来,A可以任意访问B中的所有成员,A类的所有成员函数都可以访问B中的所有成员。
小结:
- 友元是为了兼顾C语言的高效而诞生的
- 友元直接破坏了面向对象的封装性
- 友元的关系不具备传递性
- 类的 友元可以是其它类成员的成员函数
- 类的友元可以是某个完整类。