前言
简单记录一下C++中的友元,记录于此主要是方便自己查阅和回顾。
正文
定义
友元(使用关键字Friend修饰) 是一个非常强大的特性,它让类的成员函数或全局函数能够访问其他类的私有成员(private)和保护成员(protected)。
优缺点
优点:某些情况下,能够让代码更加灵活和高效。
缺点:破坏了封装。
友元函数
友元函数是在类内部声明(用friend
关键字修饰)的外部函数,它可以访问该类的私有和保护成员。
友元普通函数
普通函数,然后在类中使用friend修饰和声明,这样此普通函数可以访问此类中的所有成员。
下面是计算面积的函数computerArea,如果在Rectangle类中进行使用friend修饰和声明,那么函数computerArea就可以直接访Rectangle类中的所有成员。
- #include <iostream>
- #include <cmath>
-
- class Rectangle {
- //一个定义为private,一个定义为protected
- private:
- int height;
- protected:
- int width;
- public:
- Rectangle() {
- height = 0;
- width = 0;
- }
-
- Rectangle(int left, int top, int right, int bottom) {
- height = abs(bottom - top);
- width = abs(right - left);
- }
-
- int getHeight() {
- return height;
- }
-
- int getWidth() {
- return width;
- }
-
- //使用friend关键字声明为友元
- friend int computerArea(Rectangle& rectangle);
- };
-
- int computerArea(Rectangle& rectangle) {
- //普通函数只能通过public的方法获取
- //return rectangle.getHeight() * rectangle.getWidth();
- //除了方法,友元函数可以直接访问私有成员
- return rectangle.height * rectangle.width;
- }
-
- int main()
- {
- Rectangle rectangle(0, 0, 100, 200);
- int area = computerArea(rectangle);
- std::cout << rectangle.getWidth() << " * " << rectangle.getHeight() << " = " << area << std::endl;
- }
在类内部使用friend声明后,computerArea()可以方法类中所有的成员变量和成员函数。
友元普通函数可以看做类的一个[成员函数],但并非真正类的成员函数,但权限是一样的。
友元类函数
一个类A中使用friend修饰另外一个类B的成员函数C,那么类B的函数C可以访问类A中的所有成员。
下面例子:父亲想获取儿子的零花钱,一般情况,只能通过儿子去存钱罐中拿钱,但是如果声明未友元,父亲可以直接访问儿子的存钱罐。
- #include <iostream>
-
- class Son;//提前声明
-
- class Father {
- public:
- float getPocketMoneyFriend(Son& son);
- float getPocketMoney(Son& son);
- };
-
- class Son {
- private:
- float pocketMoney; //零花钱
- public:
- Son() {
- pocketMoney = 1100;
- }
- //如果通过儿子,只能使用这个函数
- float getSonPocketMoney() {
- //超过1000时分享零花钱
- if (pocketMoney > 1000) {
- return pocketMoney - 1000;
- }
- return 0;
- }
-
- //但是申请友元,直接访问儿子存钱罐
- friend float Father::getPocketMoneyFriend(Son& son);
- };
-
- //友元类
- float Father::getPocketMoneyFriend(Son& son) {
- //找儿子要钱
- //return son.getSonPocketMoney();
- //直接访问存钱罐
- return son.pocketMoney;
- }
-
- //非友元类
- float Father::getPocketMoney(Son& son) {
- //找儿子要钱
- return son.getSonPocketMoney();
- }
-
- int main()
- {
- Father father;
- Son son;
- float result = father.getPocketMoneyFriend(son);
- std::cout << result << std::endl;
- result = father.getPocketMoney(son);
- std::cout << result << std::endl;
- }
从上面可以知道:
友元类函数(getPocketMoneyFriend)可以访问Son的所有成员
普通类函数(getPocketMoney)只能通过Son的public方法访问
友元类
除了友元函数,C++ 还允许整个类作为友元类。友元类可以访问另一个类的私有和保护成员。
跟友元类函数的例子差不多,还是父类找儿子要钱,这次把父亲声明未友元类。
- #include <iostream>
-
- class Son;
-
- class Father {
- public:
- float getPocketMoney1(Son& son);
- float getPocketMoney2(Son& son);
- };
-
- class Son {
- private:
- float pocketMoney; //零花钱
- public:
- Son() {
- pocketMoney = 1100;
- }
- float getSonPocketMoney() {
- //超过1000时分享零花钱
- if (pocketMoney > 1000) {
- return pocketMoney - 1000;
- }
- return 0;
- }
- friend class Father;
- };
-
- float Father::getPocketMoney1(Son& son) {
- //找儿子要钱
- //return son.getSonPocketMoney();
- //直接访问存钱罐
- return son.pocketMoney;
- }
-
- float Father::getPocketMoney2(Son& son) {
- //找儿子要钱
- //return son.getSonPocketMoney();
- //直接访问存钱罐
- return son.pocketMoney;
- }
-
- int main()
- {
- Father father;
- Son son;
- float result = father.getPocketMoney1(son);
- std::cout << result << std::endl;
- result = father.getPocketMoney2(son);
- std::cout << result << std::endl;
- }
从上面可以知道:
声明友元类后,Father的所有函数都成为友元函数了,都可以访问Son的所有成员
注意
友元关系是不能传递的,如A是B的友元,B是C的友元,但A不是C的友元
友元关系是单向的,A是B的友元,A可以访问B的私有属性,反之不成立
友元关系是不被继承的,A是B的友元,但A的派生类不是B的友元
参考文章
《C++从入门到精通(第6版)》
《》
《