friend 的意思是朋友,或者说是好友,与好友的关系显然要比一般人亲密一些。我们会对好朋友敞开心扉,倾诉自己的秘密,而对一般人会谨言慎行,潜意识里就自我保护。在 C++ 中,这种友好关系可以用 friend 关键字指明,中文多译为“友元”,借助友元可以访问与其有好友关系的类中的私有成员。如果你对“友元”这个名词不习惯,可以按原文 friend 理解为朋友。

友元函数

在当前类以外定义的、不属于当前类的函数也可以在类中声明,但要在前面加 friend 关键字,这样就构成了友元函数。友元函数可以是不属于任何类的非成员函数,也可以是其他类的成员函数。

友元函数可以访问当前类中的所有成员,包括 public、protected、private 属性的。
1 将非成员函数声明为友元函数。
示例:

#include <iostream>
using namespace std;class Student{public:Student(char *name, int age, float score);
public:friend void show(Student *pstu);  //将show()声明为友元函数
private:char *m_name;int m_age;float m_score;
};Student::Student(char *name, int age, float score): m_name(name), m_age(age), m_score(score){ }//非成员函数
void show(Student *pstu){cout<<pstu->m_name<<"的年龄是 "<<pstu->m_age<<",成绩是 "<<pstu->m_score<<endl;
}int main(){Student stu("小明", 15, 90.6);show(&stu);  //调用友元函数Student *pstu = new Student("李磊", 16, 80.5);show(pstu);  //调用友元函数return 0;
}

运行结果:

小明的年龄是 15,成绩是 90.6
李磊的年龄是 16,成绩是 80.5

show() 是一个全局范围内的非成员函数,它不属于任何类,它的作用是输出学生的信息。m_name、m_age、m_score 是 Student 类的 private 成员,原则上不能通过对象访问,但在 show() 函数中又必须使用这些 private 成员,所以将 show() 声明为 Student 类的友元函数。

注意:友元函数不同于类的成员函数,在友元函数中不能直接访问类的成员,必须要借助对象。

成员函数在调用时会隐式地增加 this 指针,指向调用它的对象,从而使用该对象的成员;而 show() 是非成员函数,必须通过参数传递对象(可以直接传递对象,也可以传递对象指针或对象引用),并在访问成员时指明对象。

2 将其他类的成员函数声明为友元函数
friend 函数不仅可以是全局函数(非成员函数),还可以是另外一个类的成员函数。请看如下示例:

#include <iostream>
using namespace std;class Address;  //提前声明Address类//声明Student类
class Student{public:Student(char *name, int age, float score);
public:void show(Address *addr);
private:char *m_name;int m_age;float m_score;
};//声明Address类
class Address{private:char *m_province;  //省份char *m_city;  //城市char *m_district;  //区(市区)
public:Address(char *province, char *city, char *district);//将Student类中的成员函数show()声明为友元函数friend void Student::show(Address *addr);
};//实现Student类
Student::Student(char *name, int age, float score): m_name(name), m_age(age), m_score(score){ }
void Student::show(Address *addr){cout<<m_name<<"的年龄是 "<<m_age<<",成绩是 "<<m_score<<endl;cout<<"家庭住址:"<<addr->m_province<<"省"<<addr->m_city<<"市"<<addr->m_district<<"区"<<endl;
}//实现Address类
Address::Address(char *province, char *city, char *district){m_province = province;m_city = city;m_district = district;
}int main(){Student stu("小明", 16, 95.5f);Address addr("河南", "洛阳", "宜阳");stu.show(&addr);Student *pstu = new Student("李磊", 16, 80.5);Address *paddr = new Address("河南", "南阳", "方城");pstu -> show(paddr);return 0;
}

运行结果:

小明的年龄是 16,成绩是 95.5
家庭住址:河南省洛阳市宜阳区
李磊的年龄是 16,成绩是 80.5
家庭住址:河南省南阳市方城区

本例定义了两个类 Student 和 Address,程序第 27 行将 Student 类的成员函数 show() 声明为 Address 类的友元函数,由此,show() 就可以访问 Address 类的 private 成员变量了。

特别注意:

1 . 程序第 4 行对 Address 类进行了提前声明,是因为在 Address 类定义之前、在 Student 类中使用到了它,如果不提前声明,编译器会报错,提示’Address’ has not been declared。类的提前声明和函数的提前声明是一个道理。

2 . 程序将 Student 类的声明和实现分开了,而将 Address 类的声明放在了中间,这是因为编译器从上到下编译代码,show() 函数体中用到了 Address 的成员 province、city、district,如果提前不知道 Address 的具体声明内容,就不能确定 Address 是否拥有该成员(类的声明中指明了类有哪些成员)。

类的提前声明。一般情况下,类必须在正式声明之后才能使用;但是某些情况下(如上例所示),只要做好提前声明,也可以先使用。

3 . 一个函数可以被多个类声明为友元函数,这样就可以访问多个类中的 private 成员。

友元类

不仅可以将一个函数声明为一个类的“朋友”,还可以将整个类声明为另一个类的“朋友”,这就是友元类。友元类中的所有成员函数都是另外一个类的友元函数。

例如将类 B 声明为类 A 的友元类,那么类 B 中的所有成员函数都是类 A 的友元函数,可以访问类 A 的所有成员,包括 public、protected、private 属性的。

更改上例的代码,将 Student 类声明为 Address 类的友元类:

#include <iostream>
using namespace std;class Address;  //提前声明Address类//声明Student类
class Student{public:Student(char *name, int age, float score);
public:void show(Address *addr);
private:char *m_name;int m_age;float m_score;
};//声明Address类
class Address{public:Address(char *province, char *city, char *district);
public://将Student类声明为Address类的友元类friend class Student;
private:char *m_province;  //省份char *m_city;  //城市char *m_district;  //区(市区)
};//实现Student类
Student::Student(char *name, int age, float score): m_name(name), m_age(age), m_score(score){ }
void Student::show(Address *addr){cout<<m_name<<"的年龄是 "<<m_age<<",成绩是 "<<m_score<<endl;cout<<"家庭住址:"<<addr->m_province<<"省"<<addr->m_city<<"市"<<addr->m_district<<"区"<<endl;
}//实现Address类
Address::Address(char *province, char *city, char *district){m_province = province;m_city = city;m_district = district;
}int main(){Student stu("小明", 16, 95.5f);Address addr("河南", "洛阳", "宜阳");stu.show(&addr);Student *pstu = new Student("李磊", 16, 80.5);Address *paddr = new Address("河南", "南阳", "方城");pstu -> show(paddr);return 0;
}

第 24 行代码将 Student 类声明为 Address 类的友元类,声明语句为:

friend class Student;

有的编译器也可以不写 class 关键字,不过为了增强兼容性还是建议写上。

小提示

1 . 友元的关系是单向的而不是双向的。如果声明了类 B 是类 A 的友元类,不等于类 A 是类 B 的友元类,类 A 中的成员函数不能访问类 B 中的 private 成员。

2 . 友元的关系不能传递。如果类 B 是类 A 的友元类,类 C 是类 B 的友元类,不等于类 C 是类 A 的友元类。

C++ friend关键字相关推荐

  1. c语言中external,static关键字用法

    static用法: 在C中,static主要定义全局静态变量.定义局部静态变量.定义静态函数. 1.定义全局静态变量:在全局变量前面加上关键字static,该全局变量变成了全局静态变量.全局静态变量有 ...

  2. java中实现具有传递性吗_Java中volatile关键字详解,jvm内存模型,原子性、可见性、有序性...

    一.Java内存模型 想要理解volatile为什么能确保可见性,就要先理解Java中的内存模型是什么样的. Java内存模型规定了所有的变量都存储在主内存中.每条线程中还有自己的工作内存,线程的工作 ...

  3. volatile关键字之全面深度剖析

    引言 volatile这个关键字可能很多朋友都听说过,或许也都用过.在Java 5之前,它是一个备受争议的关键字,因为在程序中使用它往往会导致出人意料的结果.在Java 5之后,volatile关键字 ...

  4. mysql屏蔽关键字实现方法_PHP屏蔽过滤指定关键字的方法

    本文实例讲述了PHP屏蔽过滤指定关键字的方法.分享给大家供大家参考.具体分析如下: 实现思路: 一.把关键字专门写在一个文本文件里,每行一个,数量不限,有多少写多少. 二.PHP读取关键字文本,存入一 ...

  5. Java 静态变量,静态方法,静态常量(java static 关键字)

    Java 静态变量,静态方法,静态常量  就是变量 ,方法,常量前面添加了static 关键字 为什么要使用静态的呢 有时候在处理问题时会需要两个类在同一个内存区域共享一个数据, 不如现在 Main ...

  6. Java this 关键字使用

    this 引用就是本类的一个对象 理解这句话看下面一段代码 package me; public class Me {String name; //成员变量int age;public Me(Stri ...

  7. java 关键字(面试题)

    学而时习之,温故而知新. 今天群里有人问java中true ,false 是关键字吗, 这里记录下,不是关键字,我还特意翻看之前的书看看 下面是 Java 语言保留使用的 50 个关键字: 关键字 g ...

  8. java中标识符,关键字,数据类型

    什么是标识符? 在java语言中用来给一个类,变量或方法命名的符号 标识符的命名规则 标识符可以由字母.数字.下划线(_).美元符($)组成,但不能包含 @.%.空格等其它特殊字符,不能以数字开头. ...

  9. iOS面试题整理---关键字!!!

    关键字整理 static 1.static全局变量与普通的全局变量有什么区别? 全局变量(外部变量)的说明之前再冠以static 就构成了静态的全局变量.全局变量本身就是静态存储方式, 静态全局变量当 ...

  10. private关键字和构造方法

    1.private: A: 是一个修饰符 B:可以 修饰成员变量,也可以修饰成员方法 C:被private修饰的成员只能在本类中访问 D:针对private修饰的成员变量,可以用getXxx()和se ...

最新文章

  1. (转载)详解Hive配置Kerberos认证
  2. 我的 FPGA 学习历程(11)—— 实验:按键消抖
  3. html实战例子: 简易的qq登录界面
  4. Android Studio下项目构建的Gradle配置及打包应用变体
  5. SQL Server 2008安装配置说明书+简单使用 亲测可用
  6. 跨平台RTSP/RTMP转RTMP转发SDK
  7. 计算机应用基础理论,计算机应用基础理论A卷.doc
  8. 川菜为什么会成为食者最多的地方菜系?
  9. 数据科学(data science)概览
  10. linux断网后自动重连,centos 空闲一段时间后自动断网
  11. Intellij idea 添加浏览器
  12. BM25算法的python实现
  13. 爬虫免费Charles使用教程
  14. 计算机sci论文中的图,一篇计算机sci论文的发表过程
  15. utf-8 汉字对照表
  16. springboot @Value无效原因
  17. DCOS搭建zookeeper集群搭建
  18. 增量式编码器c语言,增量式编码器
  19. ctf 命令执行总结
  20. 基于Java(JSP)+MySQL实现盐鱼二手物品交易网站【100010280】

热门文章

  1. 求一个向量变换为另一个向量的矩阵_OpenGL里旋转等变换矩阵为什么是4x4的矩阵...
  2. 简单参数让谷歌Chrome浏览器单进程运行
  3. 日志中出现乱码_合宙Luat | 乱码搞得一团糟?开源神器帮你轻松修复
  4. JAVA WEB篇4——Filter、Listener
  5. 孩子学计算机最佳年龄,孩子学编程最佳年龄是多少
  6. 如何将一个向量投影到一个平面上_CameraLidar投影:2D3D导航
  7. 路由器局域网设置_路由器基础介绍
  8. 03 - 变量的数据类型
  9. android中给button加图标,Android,如何在我的代码中的TabButton中添加图标
  10. java搭建聊天服务器_使用 ServerSocket 建立聊天服务器-2