C++面向对象(OOP)编程-友元(友元函数和友元类)

本文主要介绍面向对象编程的友元的使用,以及友元的特性和分类,提供C++代码。

1 为什么引进友元

        面向对象编程(OOP)的三大特性中的封装,是通过类实现对数据的隐藏和封装。一般定义类的成员变量为私有成员,成员函数为公有函数,通过公有函数作为类的接口实现与外部交互。一些情况下,类外的某些函数需要频繁访问类的成员变量,因此引入了友元的概念,将类外的函数定义为该类的友元函数,从而实现对该类私有成员的访问。由此,还引入友元类,就是一个类是另一个类的友元类,友元类可以访问另一个类的所有成员。友元函数和友元类称为友元。

        友元的作用是提高了程序的运行效率(减少了类型检查和安全检查的耗时),但是友元破坏了类的封装和隐藏性,让非类成员函数可以类的私有成员。 

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

        与类有友元关系的函数称为友元函数,与类有友元关系的类称为友元类。

2 友元的性质

        (1)在被访问类中以friend关键字修饰友元类或者友元函数

        (2)友元不属于该类,且不受该类的访问限制,可以直接访问具体类的所有成员

        (3)友元关系不能被继承

        (4)友元关系是单向的,不具有交换性,只能是一个函数访问一个类的所有成员,或者一个类允许访问另一个类的所有成员,反之不行

        (5)友元关系不具有传递性

3 友元的本质

        友元的本质是提供不属于该类成员,包括全局函数、其他类的成员函数、其他类,访问本类所有成员和成员属性的属性。

4 友元分类

4.1 全局函数为友元函数

        全局函数拥有访问一个类所有成员的能力,需要在被访问类中用关键字friend声明f被访问类的友元函数。一个类可以拥有多个友元函数。一个函数也可以是多个类的友元函数。

代码如下:

#include <iostream>
#include <string>
using namespace std;class A
{private:string name_;int age_;public:A(const string name,const int age) : name_(name), age_(age) {cout << "A构造函数 初始化参数" << endl;};virtual ~A(){cout << "A析构函数 " << endl;}void func(){std::cout << "A's func()" << std::endl;}friend void get_members_global(A & a);  // 友元全局函数,可以访问A的私有成员变量和所有的公有成员};// 全局函数作为友元函数
void get_members_global(A & a)
{cout << a.name_ << " is " << a.age_ << " years old " << endl;a.func();
}int main()
{A a("Hubery",45);cout << "***************************全局函数作为友元函数***************************" << endl;get_members_global(a);return 0;
}

运行结果:

4.2 类的成员函数为友元函数

        类成员函数作为类的友元声明时只需在友元的名称前加上关键字friend,其格式如下:

friend 类型 类名::函数名(形式参数);

一个函数可以是多个类的友元函数,只需要在各个类中分别声明。

代码如下:

#include <iostream>
#include <string>
using namespace std;class A;class C
{public://类的成员函数作为友元函数void get_members_member(A &a);C(){cout << "C构造函数" << endl;}~C(){cout << "C析构函数" << endl;}
};class A
{private:string name_;int age_;public:A(const string name,const int age) : name_(name), age_(age) {cout << "A构造函数 初始化参数" << endl;};virtual ~A(){cout << "A析构函数 " << endl;}void func(){std::cout << "A's func()" << std::endl;}friend void C::get_members_member(A &a); // C的成员函数做友元函数,可以访问所有成员};// 类的成员函数作为友元函数
void C::get_members_member(A &a)
{cout << a.name_ << " is " << a.age_ << " years old " << endl;a.func();
}int main()
{A a("Hubery",45);C c;cout << "***************************类的成员函数作为友元函数***************************" << endl;c.get_members_member(a);return 0;
}

运行结果:

这里用到类的前向声明。前向声明,是一种不完全型(forward declaration)声明,即只需提供类名(无需提供类实现)即可。前向声明功能有限:
        (1)不能定义类的对象。
      (2)可以用于定义指向这个类型的指针或引用。
      (3)用于声明(不是定义)使用该类型作为形参或者返回类型的函数。

4.3 类作为友元

        友元类的所有成员函数都是另一个类的友元函数,都可以访问另一个类中的隐藏信息(包括私有成员和保护成员)。当希望一个类可以访问另一个类的私有成员、保护成员时,可以将该类声明为另一类的友元类。

定义友元类的语句格式如下:

friend class 类名;
friend和class是关键字,类名必须是程序中的一个已定义的类。

代码如下:

#include <iostream>
#include <string>
using namespace std;class B; // 前向声明class A
{private:string name_;int age_;public:A(const string name,const int age) : name_(name), age_(age) {cout << "A构造函数 初始化参数" << endl;};virtual ~A(){cout << "A析构函数 " << endl;}void func(){std::cout << "A's func()" << std::endl;}friend class B; // 声明B为A的友元类,B中成员函数可以访问A中所有的成员};class B
{private:string name_;int age_;public:B(const string name,const int age) : name_(name), age_(age) {cout << "B构造函数 初始化参数" << endl;};virtual ~B(){cout << "B析构函数 " << endl;}void func(){std::cout << "B's func()" << std::endl;};// 友元类void get_members_class(A & a){cout << a.name_ << " is " << a.age_ << " years old " << endl;a.func();};};int main()
{A a("Hubery",45);B b("Tom",24);cout << "***************************友元类***************************" << endl;b.get_members_class(a);return 0;
}

运行结果:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/220362.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

模拟目录管理 - 华为OD统一考试(C卷)

OD统一考试(C卷) 分值: 200分 题解: Java / Python / C++ 题目描述 实现一个模拟目录管理功能的软件,输入一个命令序列,输出最后一条命令运行结果。 支持命令: 1)创建目录命令: mkdir 目录名称,如mkdir abc为在当前目录创建abc目录,如果已存在同名目录则不执行任何操作…

CentOS7安装 Docker Compose

docker系列 CentOS7安装 Docker Compose docker系列前言1、下载 Docker Compose2、 授权执行权限3、添加软链接4、验证安装 前言 下面的操作是在centos7中完成的。这里安装的是2.23.3版本的docker-compose。 1、下载 Docker Compose 确保你具有 curl 工具&#xff0c;然后使用…

每个开发人员都想使用的编程语言

在任何时候&#xff0c;一些编程语言都会把大量的开发人员变成热情的布道者&#xff0c;试图说服世界其他地方的人相信它的伟大。 当热起来的时候&#xff0c;这种语言可能会成为行业标准&#xff0c;但其他时候&#xff0c;这种受欢迎程度就会消失。 在这个故事中&#xff0…

【JVM从入门到实战】(五)类加载器

一、什么是类加载器 类加载器&#xff08;ClassLoader&#xff09;是Java虚拟机提供给应用程序去实现获取类和接口字节码数据的技术。 类加载器只参与加载过程中的字节码获取并加载到内存这一部分。 二、jdk8及之前的版本 类加载器分为三类&#xff1a; 启动类加载器-加载Ja…

express 下搞一个 websocket 长连接

安装模块 npm i express npm i express-ws 新建文件app.js 先安排源码 监听端口 7777 var express require(express) var app express() require(express-ws)(app)var port 7777 var clientObject {} app.ws(/, (client, req) > {// 连接var key req.socket.re…

预测性维护对制造企业设备管理的作用

制造企业设备管理和维护对于生产效率和成本控制至关重要。然而&#xff0c;传统的维护方法往往无法准确预测设备故障&#xff0c;导致生产中断和高额维修费用。为了应对这一挑战&#xff0c;越来越多的制造企业开始采用预测性维护技术。 预测性维护是通过传感器数据、机器学习和…

上海亚商投顾:沪指再度失守3000点 北向资金净卖出近百亿

上海亚商投顾前言&#xff1a;无惧大盘涨跌&#xff0c;解密龙虎榜资金&#xff0c;跟踪一线游资和机构资金动向&#xff0c;识别短期热点和强势个股。 一.市场情绪 三大指数昨日集体调整&#xff0c;尾盘均跌超1%&#xff0c;北证50则逆势拉升涨超3%。医药股逆势走强&#xf…

打印机怎么扫描文件到电脑?6个步骤!轻松完成!

“在工作时我经常需要用到打印机&#xff0c;有时候需要将部分文件扫描到电脑。但是我不是很清楚应该如何操作&#xff0c;有什么方法可以让打印机快速传输文件到电脑的方法吗&#xff1f;” 在人们的工作和学习中&#xff0c;打印机成了很多用户的必备工具。人们可以用它来打印…

本地搭建Linux DataEase数据可视化分析工具并实现公网访问

文章目录 前言1. 安装DataEase2. 本地访问测试3. 安装 cpolar内网穿透软件4. 配置DataEase公网访问地址5. 公网远程访问Data Ease6. 固定Data Ease公网地址 前言 DataEase 是开源的数据可视化分析工具&#xff0c;帮助用户快速分析数据并洞察业务趋势&#xff0c;从而实现业务…

React中类组件和函数组件的区别?

面试官&#xff1a;说说对React中类组件和函数组件的理解&#xff1f;有什么区别&#xff1f; 一、类组件 类组件&#xff0c;顾名思义&#xff0c;也就是通过使用ES6类的编写形式去编写组件&#xff0c;该类必须继承React.Component 如果想要访问父组件传递过来的参数&#…

kernel(三):kernel移植

本文主要探讨210官方kernel移植。 配置文件选择 选择配置文件smdkv210_android_defconfig(arch/arm/configs) 修改主Makefile 配置cpu架构和交叉编译工具链 vim MakefileARCH ? armCROSS_COMPILE ? /root/arm-2009q3/bin/arm-none-linux-gnueabi- 初步编译烧…

使用对象处理流ObjectOutputStream读写文件

注意事项: 1.创建的对象必须实现序列化接口,如果属性也是类&#xff0c;那么对应的类也要序列化 2.读写文件路径问题 3.演示一个例子 &#xff08;1&#xff09;操作的实体类FileModel&#xff0c;实体类中有Map,HashMap这些自带的本身就实现了序列化。 public class File…

Gradio: 实时性能反馈的机器学习演示工具 | 开源日报 No.107

comfyanonymous/ComfyUI Stars: 17.5k License: GPL-3.0 这个项目是 ComfyUI&#xff0c;它提供了一个图形化界面和后端来设计和执行复杂的稳定扩散工作流程。 节点/图表/流程图接口用于实验并创建复杂的稳定扩散工作全面支持不同版本的 Stable Diffusion异步队列系统部分更新…

薅github的羊毛-用pages建自己的博客或资源站 - 博客工具 - 2/2

笔者调研了好多个静态博客工具&#xff0c;最后锁定Hexo了&#xff0c;但不等于其他博客不行。我只吐槽两个 Hugo - 难用Gridea - 简直就是骗钱的&#xff0c;我交钱用不了 theme没有链接&#xff0c;同步也同步不了&#xff0c;估计以前是可以&#xff0c;现在经营不下去&…

十大经典排序算法知识体系终结篇

目录 一. 前言 二. 冒泡排序&#xff08;Bubble Sort&#xff09; 2.1. 概念 2.2. 算法步骤 2.3. 代码实现 三. 选择排序&#xff08;Selection Sort&#xff09; 3.1. 概念 3.2. 算法步骤 3.3. 代码实现 四. 插入排序&#xff08;Insertion Sort&#xff09; 4.1. …

wireshark使用

1、抓包界面介绍 2、过滤 (1) ip过滤 or 端口过滤 ip.src 192.168.1.104 显示源地址为192.168.1.104的数据包列表 ip.dst192.168.1.104, 显示目标地址为192.168.1.104的数据包列表 ip.addr 192.168.1.104 显示源IP地址或目标IP地址为192.168.1.104的数据包列表 port 80 …

C++进阶篇9---类型转换

C语言中的类型转换 在C语言中&#xff0c;如果赋值运算符左右两侧类型不同&#xff0c;或者形参与实参类型不匹配&#xff0c;或者返回值类型与 接收返回值类型不一致时&#xff0c;就需要发生类型转化&#xff0c;C语言中总共有两种形式的类型转换&#xff1a;隐式类型 转换和…

RRC下的NAS层

无线资源控制&#xff08;Radio Resource Control&#xff0c;RRC&#xff09;&#xff0c;又称为无线资源管理&#xff08;RRM&#xff09;或者无线资源分配&#xff08;RRA&#xff09;&#xff0c;是指通过一定的策略和手段进行无线资源管理、控制和调度&#xff0c;在满足服…

2.操作符详解

1.10进制转二进制方法 所以125的二进制就是1111101 2.2进制转8进制: 从2进制序列中右边最低位开始向左每3个2进制位换算为一个8进制位&#xff0c;剩余不够3个2进制位的直接换算 例:01101011转为01 101 011 即1 5 3 即8进制的153 还原回去的话: 将3化为011放最右边,5化…

使用PM2,在生产环境稳定运行你的node项目

PM2 一个 node&#xff0c;本身就用几行代码&#xff0c;就可以启动个 server 进程&#xff0c;监听个端口&#xff0c;为大家提供 Web 服务 一、依赖安装 npm install pm2 -g 二、命令行启动 普通执行启动 pm2 start <js 文件路径 >.js 携带参数启动 pm2 start < 某种…