C++超详细讲解友元的使用
作者:清风自在 流水潺潺
采用类的机制后实现了数据的隐藏与封装,类的数据成员一般定义为私有成员,成员函数一般定义为公有的,依此提供类与外界间的通信接口。但是,有时需要定义一些函数,这些函数不是类的一部分,但又需要频繁地访问类的数据成员,这时可以将这些函数定义为该类的友元函数
一、友元的概念
- 什么是友元?
- 友元是 C++ 中的一种关系
- 友元关系发生在函数与类之间或者类与类之间
- 友元关系是单项的,不能传递
二、友元的用法
- 在类中以 friend 关键字声明友元
- 类的友元可以是其它类或者具体函数
- 友元不是类的一部分
- 友元不受类中访问级别的限制
- 友元可以直接访问具体类的所有成员
三、友元的语法
在类中用 friend 关键字对函数或类进行声明
先看一个不使用友元的代码:
#include <stdio.h> #include <math.h> class Point { double x; double y; public: Point(double x, double y) { this->x = x; this->y = y; } double getX() { return x; } double getY() { return y; } //friend double func(Point& p1, Point& p2); }; double func(Point& p1, Point& p2) { double ret = 0; ret = (p2.getY() - p1.getY()) * (p2.getY() - p1.getY()) + (p2.getX() - p1.getX()) * (p2.getX() - p1.getX()); ret = sqrt(ret); return ret; } int main() { Point p1(1, 2); Point p2(10, 20); printf("p1(%f, %f)\n", p1.getX(), p1.getY()); printf("p2(%f, %f)\n", p2.getX(), p2.getY()); printf("|(p1, p2)| = %f\n", func(p1, p2)); return 0; }
输出结果如下:
这个程序在x 和 y中计算两点之间的距离时需要频繁访问私有成员 x 和 y,所以不得不调用getX() 和getY() 来访问x 和 y,x 和 y 函数中调用了 8 次getX() 和getY(),很麻烦。
这个时候,就该我们的友元上场了:
#include <stdio.h> #include <math.h> class Point { double x; double y; public: Point(double x, double y) { this->x = x; this->y = y; } double getX() { return x; } double getY() { return y; } friend double func(Point& p1, Point& p2); }; double func(Point& p1, Point& p2) { double ret = 0; ret = (p2.y - p1.y) * (p2.y - p1.y) + (p2.x - p1.x) * (p2.x - p1.x); ret = sqrt(ret); return ret; } int main() { Point p1(1, 2); Point p2(10, 20); printf("p1(%f, %f)\n", p1.getX(), p1.getY()); printf("p2(%f, %f)\n", p2.getX(), p2.getY()); printf("|(p1, p2)| = %f\n", func(p1, p2)); return 0; }
输出结果如下:
四、友元的尴尬
- 友元是为了兼顾 C 语言的高效而诞生的
- 友元直接破坏了面向对象的封装性
- 友元在实际产品中的高效是得不偿失的
- 友元在现代软件工程中已经逐渐被遗弃
五、注意事项
- 友元关系不具备传递性
- 类的友元可以是其它类的成员函数
- 类的友元可以是某个完整的类
- 所有的成员函数都是友元
下面来深入分析一下友元:
#include <stdio.h> 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); } /* void getClassCName(ClassC& c) { printf("c.n = %s\n", c.n); } */ }; int main() { ClassA A("A"); ClassB B("B"); ClassC C("C"); A.getClassBName(B); B.getClassCName(C); return 0; }
B 是 C 的友元,A 是 B 的友元,输出结果如下:
既然 A 可以访问 B,B 可以访问 C,那么 A 可以访问 C 么?把上面代码取消注释:
void getClassCName(ClassC& c) { printf("c.n = %s\n", c.n); }
输出报错,这说明友元关系不具备传递性
六、小结
- 友元是为了兼顾 C 语言的高效而诞生的
- 友元直接破坏了面向对象的封装性
- 友元关系不具备传递性
- 类的友元可以是其它类的成员函数
- 类的友元可以是某个完整的类
到此这篇关于C++超详细讲解友元的使用的文章就介绍到这了,更多相关C++友元内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!