欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 编程语言 > c/c++ >内容正文

c/c++

【C++深度剖析教程6】C++之友元

发布时间:2023/12/10 c/c++ 50 豆豆
生活随笔 收集整理的这篇文章主要介绍了 【C++深度剖析教程6】C++之友元 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

这几天在复习数学考试,都没有学C++,今天抽空来学一点。

什么是友元?

  • 友元是C++中的一种关系
  • 友元发生在函数与类之间或者类与类之间
  • 友元关系是单向的,不能传递

在具体讲解友元的性质之前,我们先来看看一个程序,这个程序是计算两点之间的距离:

#include <stdio.h> #include <math.h>class Point { private:double x;double y; public:Point(double x,double y){this->x = x; //this指针指向当前的对象this->y = y;}double getX(){return x;}double getY(){return y;} };double func(Point& p1,Point& p2) {double ret = 0;ret = (p1.getX() - p2.getX()) * (p1.getX() - p2.getX()) +(p1.getY() - p2.getY()) * (p1.getY() - p2.getY());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; }

上面代码运行结果为:

p1(1.000000,2.000000) p2(10.000000,20.000000) |p1-p2| = 20.124612

看着也没什么大问题。下面我们来简单分析一下这个程序的实用性:进行计算这个两点之间的距离时的代码为:

ret = (p1.getX() - p2.getX()) * (p1.getX() - p2.getX()) +(p1.getY() - p2.getY()) * (p1.getY() - p2.getY());

进行了8次函数的调用!!!这么简单的计算,就需要调用8次函数,这效率之慢在当初C++诞生的时候,是不被大多数人接受的,大多数人用C编程习惯了,都是可以直接这样调用的:

ret = (p1.x - p2.x) * (p1.x - p2.x) +(p1.y - p2.y) * (p1.y - p2.y);

然而C++里面你就不能像上面那样直接调用类(C里面可以是结构体或者数组)的成员变量。因为它是private类型的变量。那么在C++诞生的那个年代,人们为了让C++语言完全兼容C语言,就在C++中加入了友元的存在。那么友元的定义以及性质是什么样的呢?

  • 在类中以friend关键字声明友元
  • 类的友元可以是其他类或者具体的函数
  • 友元不是类的一部分
  • 友元不受类中访问级别的限制
  • 友元可以直接访问具体类的所有成员

直接将上面的代码修改一下看看:

#include <stdio.h> #include <math.h>class Point { private:double x;double y; public:Point(double x,double y){this->x = x; //this指针指向当前的对象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 = (p1.x - p2.x) * (p1.x - p2.x) +(p1.y - p2.y) * (p1.y - p2.y);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; }

运行结果为:

p1(1.000000,2.000000) p2(10.000000,20.000000) |p1-p2| = 20.124612

这样看来,我们已经实现了直接访问类的私有成员变量。上面的代码,func函数是Point类的友元,可以直接访问Point的所有数据。但是这样做,又不好,为什么呢?
友元的尴尬:

  • 友元是为了兼顾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.n = B c.n = C

分析代码知:类B是C的友元,类A是B的友元,所以在B中可以直接访问C的私有成员变量,在A中可以直接访问B的成员变量。 那么在A中能否直接访问C呢?试验一下将上面的代码注释掉得部分恢复,编译运行,运行结果为:

test.cpp: In member function ‘void ClassA::getClassCName(ClassC&)’: test.cpp:6: error: ‘const char* ClassC::n’ is private test.cpp:44: error: within this context

很显然,A是不能访问C的私有成员的。

总结一下:

  • 友元是为了兼顾C语言的高效而诞生的
  • 友元直接破坏了面向对象的封装性
  • 友元关系不具备传递性
  • 类的友元可以是其他类的成员函数
  • 类的友元可以是某个完整的类

想获得各种学习资源以及交流学习的加我(有我博客中写的代码的原稿):
qq:1126137994
微信:liu1126137994
可以共同交流关于嵌入式,操作系统,C++语言,C语言,数据结构等技术问题。

总结

以上是生活随笔为你收集整理的【C++深度剖析教程6】C++之友元的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。