在c++中对类的成员设置了保护,如private和protected是不允许外部访问的,有时候有一个外部函数就是需要访问,为了解决这个问题,c++开了个后门,就是友元函数,友元函数就是将外部函数在类中进行申明,声明时前面添加friend关键字,将其声明为类的友元函数后就可以任意访问类中成员。示例如下:
class person { public: string name; private: int age; friend void print(person p); //将print声明为友元函数 }; void print(person p) { cout << "name: " <友元函数的声明位置不限制,可以是在public也可以是在private和protected。
友元函数是不带this指针的,所以不能直接访问类中的变量,只能通过形参传参访问。
友元函数的访问是一个单向的,外部函数可以访问类中的所有成员,但是类中的成员不可以访问友元函数内部的成员,友元函数在类的封装上打了个洞,这个洞对面向对象是一种破坏,
在c++中有很多语法会破坏面向对象的封装,所以c++并不是一个纯面向对象的语言,可以说为了效率,怎么弄效率高就怎么弄。
友元成员友元函数是另一个类中的成员函数被称为友元成员、友元成员方法、友元成员函数。实现示例如下:
class person { public: friend void animal::print(person& p); //将其他类的成员函数声明为友元函数 };类的前置声明当多个类相互引用时,由于编译器是从上往下编译,会出现“未定义”尴尬,此时可以使用前置声明,前置声明就是一个class的定义没有实体,如class person,但由于这种前置声明只是一个类的声明,不包含类的细节,如果类的实体出现前使用了类内部的东西(成员方法和函数),那么一样会报错误。如上例中声明的友元函数是类中的细节,所以animal这个类必须定义在前面,如果不能写在前面,那么就只能用指针或引用来代替我们要访问的细节。
在设计多个类的体系时,尽量设计好层次关系成单向,尽量避免互相引用的情况。
友元类友元类和友元函数高度相似,如将类A声明为类B的友元类,那么类A中所有的成员函数都成了类B的友元函数,所有成员函数都可以访问类A的成员,示例如下,
class animal { public: friend class person; //声明一个友元类 };友元类其实是批量制造友元函数,相当于一次打了多个洞,这对面向对象是一个极大的破坏,除非确实必要,否则建议按需定义友元函数,尽量维护面向对象,使得代码更安全、更健壮。
互为友元类友元类是单向的,即类B对类A公开,但是A对B不是公开。如果要构成双向,可以相互声明友元类,即在A中声明B是友元类,在B中声明A是友元类,示例如下,当然两个类中的成员函数也可以独立互为友元函数。
class animal { friend class person; //声明person友元类 }; class person { friend class animal; //声明animal友元类 };为什么有友元函数友元函数的缺点是破坏了封装性,所以尽量不要使用友元函数,优点是在实现数据共享时减少了开销,提高了效率,当利大于弊的时候我们就可以考虑友元函数。
如运算符重载,前面我们提到尽量使用外部运算符重载,理由是语义更清晰,更符合c的编程习惯,如c=a+b实现成外部运算符重载时分解后就是c=operator+(a,b),在类的内部则是c=a.operator+(b);为了追求编程的习惯,所以我们使用外部函数重载时有意义的,但是外部函数不能直接访问类的私有成员,我们的方法就是运算符重载函数声明为类的friend友元函数,也间接的说明在这里适合用友元函数。
然而并不是所有的运算符重载都可以定义成外部含数,在c++中至少有“=”、“->”、“[ ]”、“()”不能做外部运算符重载。
“=”赋值运算符之所以不能做成外部运算符重载是因为类给我们提供了一个默认的“=”赋值运算符重载,编译器只会检查类的内部是否有运算符重载,没有就使用默认的,显然当我们使用外部友元赋值运算符重载函数,编译器找不到,就会使用内部的。
默认赋值运算符重载原理c=a+7;
如上式c和a都是一个类,7是一个数字,这段代码中首先是a和7不是同类型的,不能直接 *** 作,编译器会将7隐式转换成与a一样的类型,怎么转了?先创建一个与a类型相同的类b同时传参7去初始化内部成员b(7),此时如果我们在a的类中写了带参的构造函数,就会被调用,如果没写就完蛋了。待b初始化完成后就成了c=a+b,这时候再调用类中的“+”运算符重载函数对a和b相加后再赋值给c。
两个类的数据共享类的成员变量共享有三种方法:
友元函数和成员函数的区别
- 直接将变量声明为public。
- 将要共享的数据独立定义一个类A,在其它的类中去共同引用A,通过A来进行传递。
- 使用友元函数打洞,使相互可以访问成员变量,这也是推荐的方法,因为效率高。
共有友元函数
- 友元函数没有this指针,毕竟友元只是朋友,不是自家人,
- 友元函数不能被继承,就像父亲的朋友不是儿子的朋友。
- 友元函数不具有传递性,类A是类B的友元,类B是类c的友元,那么类c不一定是类A的友元。总之友元在哪里声明,哪里才是友元,其它的都不好使。
1个函数(可以是外部函数也可以是其它类的成员函数)在两个类中都是友元,这个是很正常的。然而一个函数成为了两个类的友元,就在无形中将完全不相干的两个类的成员打通了,不是说两个类可以相互访问,而是可以在友元函数中对两个类中的成员做赋值、比较等多种 *** 作,这无疑是将两个类的成员打通了。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)