【C++】 类的新成员:static成员和类的好朋友:友元

欢迎来到CILMY23的博客

🏆本篇主题为: 类的新成员:static成员和类的好朋友:友元

🏆个人主页:CILMY23-CSDN博客

🏆系列专栏:Python | C++ | C语言 | 数据结构与算法 | 贪心算法 | Linux

🏆感谢观看,支持的可以给个一键三连,点赞关注+收藏。


✨写在前头:

这么长时间,我们终于把构造函数的内容解决了,初始化列表,默认构造函数,构造函数和析构函数的顺序,全缺省的默认构造函数都值得我们细细品味,本期将接触类和对象中新的部分,static成员和类的好朋友:友元


static成员

1.1  static成员的引入

之前我们学过了构造函数的顺序,我们来看看以下代码:

int n = 0;class A
{
public:A(){++n;}A(const A& a){++n;}
private:
};A Func()
{A aa;return aa;
}int main()
{A aa1;A aa2;Func();cout << n << endl;return 0;
}

稍微分析一下我们就会发现,这是四次的创建,但是有的编译器会优化,可能就是三次,但是不影响我们这里的讨论。如果我们把int n 从全局放到类里面,我们要如何增加次数呢?于是C++里提供了static成员。 

1.2  static成员的概念

在C++中,static关键字在类的中用于声明静态成员。静态成员可以是静态成员变量(也叫静态数据成员)或静态成员函数静态成员是类的一部分,但它们不是类的对象的一部分,属于所有对象,属于所有类。

 ◼️例如:静态成员变量如下

class A
{
public:A(){++n;}A(const A& a){++n;}
private://静态成员是类的一部分,但它们不是类的对象的一部分,属于所有对象,属于整个类//声明static int n;
};//定义,类中的全局变量
int A::n = 0;A Func()
{A aa;return aa;
}int main()
{A aa1;A aa2;Func();return 0;
}

1.3  static成员变量的访问

第一种: 通过类域访问,将private改为public,放开访问权限。

 第二种:提供公有的函数GetN,用来获取私有的成员变量

1.4  static静态成员函数

在上述访问中,如果我们将成员函数GetN加上static,它就变成了静态的成员函数。

class A
{
public:A(){++n;}A(const A& a){++n;}//static 成员函数没有this指针static int GetN(){//a++ 不能访问其他的return n;}private:int a;static int n;
};//定义,类中的全局变量
int A::n = 0;A Func()
{A aa;return aa;
}int main()
{A aa1;A aa2;Func();cout << aa1.GetN() << endl;cout << A::GetN() << endl;return 0;
}

注意:静态成员函数没有this指针 ,它也不能访问非静态成员

1.5  static静态成员的特点 

  1. 静态成员所有类对象所共享,不属于某个具体的对象,存放在静态区
  2. 静态成员变量必须在类外定义,定义时不添加static关键字,类中只是声明
  3. 类静态成员即可用  类名::静态成员  或者  对象.静态成员  来访问
  4. 静态成员函数没有隐藏的this指针,不能访问任何非静态成员
  5. 静态成员也是类的成员,受public、protected、private 访问限定符的限制

两个问题: 

1. 静态成员函数可以调用非静态成员函数吗?

答:静态成员函数不能直接调用非静态成员函数。静态成员函数是属于类的,而非静态成员函数是属于类的某个特定对象的。因为静态成员函数在调用时不依赖于类的任何特定对象,它没有this指针,所以它不能直接调用那些依赖于特定对象(即需要通过this指针访问的)的非静态成员函数。

2. 非静态成员函数可以调用类的静态成员函数吗?

 答:非静态成员函数可以调用类的静态成员函数。因为静态成员函数不依赖于类的具体实例,所以它们可以被类的任何成员函数调用,无论是静态的还是非静态的。在非静态成员函数中调用静态成员函数不需要特定的对象实例,可以直接调用。

友元 

前言:

 在前几篇中,我们就涉及过了友元,无论是在写日期计算器(链接),还是在写赋值运算符重载(链接)的时候,友元提供了一种突破封装的方式,有时提供了便利。但是友元会增加耦合度,破坏了封装,所以友元不宜多用。

2.1 友元概念

 友元(Friend)是C++中的一个关键概念,它允许某些特定的外部函数或类访问另一个类的私有(private)或保护(protected)成员。友元破坏了类的封装性,但在某些情况下能提供方便的访问方式。友元又分为:友元函数友元类

  1. 友元函数: 当某个函数被声明为一个类的友元时,这个函数就可以访问该类的所有成员,包括私有和保护成员。友元函数不是类的成员函数,它可以是任何普通函数,甚至可以是另一个类中的成员函数。

  2. 友元类: 如果一个类被声明为另一个类的友元,那么这个友元类的所有成员函数都可以访问另一个类的私有和保护成员。这种关系在两个密切相关的类之间非常有用,例如,在实现某些设计模式时。

 2.2 友元函数

 在之前我们实现日期计算器的时候,重载operator<<,然后发现没办法将operator<<重载成成员函数。因为cout的输出流对象隐含的this指针在抢占第一个参数的位置。this指针默认是第一个参数也就是左操作数了。但是实际使用中cout需要是第一个形参对象,才能正常使用。所以要将operator<<重载成全局函数。但又会导致类外没办法访问成员,此时就需要友元来解决,operator>>同理。

友元函数:

 

//Date.h
//用户输出
ostream& operator<<(ostream& out,const Date& d);
//用户输入
istream& operator>>(istream& in, Date& d);//Date.cpp
ostream& operator<<(ostream& out, const Date& d)
{out << d._year << "年" << d._month << "月" << d._day << "天" << endl;return out;
}istream& operator>>(istream& in, Date& d)
{while (1){cout << "请输入对应的年月日" << endl;in >> d._year>> d._month>> d._day;if (!d.CheckInvalid()){cout << "日期输入错误,请重新输入" << endl;}else{break;}}return in;
}

友元函数可以直接访问类的私有成员,它是定义在类外部的普通函数,不属于任何类,但需要在 类的内部声明,声明时需要加friend关键字。 

友元函数的特点:

  • 友元函数可访问类的私有和保护成员,但不是类的成员函数
  • 友元函数不能用const修饰
  • 友元函数可以在类定义的任何地方声明不受类访问限定符限制
  • 一个函数可以是多个类的友元函数
  • 友元函数的调用与普通函数的调用原理相同 

2.3 友元类 

 比较亲近的两种类,例如日期类和时间类,例如:

class Time
{friend class Date;// 声明日期类为时间类的友元类,则在日期类中就直接访问Time类 中的私有成员变量
public:Time(int hour = 0, int minute = 0, int second = 0) : _hour(hour), _minute(minute), _second(second){}private:int _hour;int _minute;int _second;
};
class Date
{
public:Date(int year = 1900, int month = 1, int day = 1) : _year(year), _month(month), _day(day){}void SetTimeOfDate(int hour, int minute, int second) {// 直接访问时间类私有的成员变量   _t._hour = hour;_t._minute = minute;_t._second = second;}private:int _year;int _month;int _day;Time _t;
};

友元类的特点:

#️⃣友元类的所有成员函数都可以是另一个类的友元函数,都可以访问另一个类中的非公有成员

1️⃣友元关系是单向的,不具有交换性。
比如上述Time类和Date类,在Time类中声明Date类为其友元类,那么可以在Date类中直接访问Time类的私有成员变量,但想在Time类中访问Date类中私有的成员变量则不行。

2️⃣友元关系不能传递
如果C是B的友元, B是A的友元,则不能说明C时A的友元。

3️⃣友元关系不能继承


💡总结

1️⃣ 静态成员是类的一部分,但它们不是类的对象的一部分,属于所有对象,属于所有类。

2️⃣ 静态成员函数没有this指针 ,它也不能访问非静态成员

3️⃣ 友元还是要慎用,因为它突破了封装,提供了一个“后门”

4️⃣友元函数可以直接访问类的私有成员,它是定义在类外部的普通函数,不属于任何类,但需要在类的内部声明,声明时需要加friend关键字。 

5️⃣友元类的所有成员函数都可以是另一个类的友元函数,都可以访问另一个类中的非公有成员。

6️⃣友元关系是单向的,不具有交换性,友元关系不能传递也不能继承 


感谢各位同伴的支持,本期C++就讲解到这啦,如果你觉得写的不错的话,可以给个一键三连,点赞,关注+收藏,若有不足,欢迎各位在评论区讨论。  

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

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

相关文章

网络编程套接字(一) 【简单的Udp网络程序】

网络编程套接字<一> 理解源端口号和目的端口号PORT VS PID认识TCP协议和UDP协议网络字节序socket编程接口sockaddr结构简单的UDP网络程序服务端创建套接字服务端绑定运行服务器客户端创建套接字关于客户端的绑定问题启动客户端启动客户端本地测试INADDR_ANY 理解源端口号…

怎么给视频加水印?2招轻松搞定

在数字媒体时代&#xff0c;视频水印作为一种有效的版权保护手段&#xff0c;被广泛应用于各种场景。给视频添加水印不仅可以防止内容被恶意盗用&#xff0c;还能增加视频的辨识度&#xff0c;提升品牌形象。本文将为您介绍2种简单易行的方法&#xff0c;教您怎么给视频加水印&…

Linux进程控制——Linux进程等待

前言&#xff1a;接着前面进程终止&#xff0c;话不多说我们进入Linux进程等待的学习&#xff0c;如果你还不了解进程终止建议先了解&#xff1a; Linux进程终止 本篇主要内容&#xff1a; 什么是进程等待 为什么要进行进程等待 如何进程等待 进程等待 1. 进程等待的概念2. 进…

软件杯 深度学习的水果识别 opencv python

文章目录 0 前言2 开发简介3 识别原理3.1 传统图像识别原理3.2 深度学习水果识别 4 数据集5 部分关键代码5.1 处理训练集的数据结构5.2 模型网络结构5.3 训练模型 6 识别效果7 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 深度学习…

【数据结构】平衡二叉树(插入、查找、删除)解析+完整代码

3.2 平衡二叉树 3.2.1 定义 平衡二叉树&#xff0c;简称平衡树&#xff08;AVL树&#xff09; 树上任一结点的左右子树高度差不超过1。 结点的平衡因子左子树高-右子树高 3.2.2 插入操作 插入结点后&#xff0c;可能造成不平衡 要调整最小不平衡子树&#xff0c;使其恢复平衡。…

【回溯 代数系统】679. 24 点游戏

本文涉及知识点 回溯 代数系统 LeetCode679. 24 点游戏 给定一个长度为4的整数数组 cards 。你有 4 张卡片&#xff0c;每张卡片上都包含一个范围在 [1,9] 的数字。您应该使用运算符 [‘’, ‘-’, ‘*’, ‘/’] 和括号 ‘(’ 和 ‘)’ 将这些卡片上的数字排列成数学表达式…

SQLserver - 笔记

1 SQLserver - 用户管理 4、SQL SERVER数据库用户管理_哔哩哔哩_bilibili 创建用户 - user 2.选择用户&#xff0c;修改属性

Qt---绘图和绘图设备

一、QPainter绘图 绘图事件 void paintEvent() 声明一个画家对象&#xff0c;OPainter painter(this) this指定绘图设备 画线、画圆、画矩形、画文字 设置画笔QPen 设置画笔宽度、风格 设置画刷QBrush 设置画刷风格 代码示例&#xff1a; #includ…

LeetCode---循环队列

循环队列就是只有固定的内存&#xff0c;存数据&#xff0c;出数据&#xff0c;但是也和队列一样&#xff0c;先进先出。如下图所示&#xff0c;这是他的样子 在head出&#xff0c;tail进&#xff0c;但是这个如果用数组解决的话&#xff0c;就有问题&#xff0c;力扣给我们的接…

Building3D An Urban-Scale Dataset and Benchmarks 论文阅读

文章主页 Building3D 任务 提出了一个城市规模的数据集&#xff0c;由超过 16 万座建筑物以及相应的点云、网格和线框模型组成&#xff0c;覆盖爱沙尼亚的 16 个城市&#xff0c;面积约 998 平方公里。 动机 现有的3D建模数据集主要集中在家具或汽车等常见物体上。缺乏建…

CAPL入门之使用CAPL记录测试Logging

0 前言 以往测试的log都是直接从trace导出&#xff0c;但是最近发现trace中能导出的数据是有限的&#xff0c;如果测试的时间过长&#xff0c;新的数据就会把之前的数据全部覆盖&#xff0c;并且对于长时间的测试&#xff0c;直接导出trace的内容也会造成查找效率低下的问题。因…

centos7下使用docker安装fastdfs服务

先查看容器是否已经存在 docker ps -a 删除掉之前的tracker及storage服务 docker rm tracker docker rm storage 1、没有镜像先下载镜像 docker pull morunchang/fastdfs 2、运行服务 a、不指定物理服务器路径 docker run -d --name tracker --nethost morunchang/fastdfs sh…

Java面试八股之String s = “String“;和String s = new String(“String“);有什么区别

Java中String s "String";和String s new String("String");有什么区别 字符串字面量&#xff08;"String"&#xff09;&#xff1a; 常量池&#xff1a;使用字面量方式创建字符串时&#xff0c;Java虚拟机&#xff08;JVM&#xff09;会在运…

Jmeter接口测试之参数化

在接口测试中&#xff0c;某些时候一些场景会使用到参数化的场景&#xff0c;参数化简单的说就是同一个请求需要不同的数据&#xff0c;比如在性能测试中需要并发多个用户的场景&#xff0c;这样的目的是为了模拟真实的用户场景&#xff0c;需要模拟不同的账号&#xff0c;这里…

算法练习第21天|216.组合总和|||、17.电话号码的字母组合

216.组合总和 III 216. 组合总和 III - 力扣&#xff08;LeetCode&#xff09;https://leetcode.cn/problems/combination-sum-iii/ 题目描述&#xff1a; 找出所有相加之和为 n 的 k 个数的组合&#xff0c;且满足下列条件&#xff1a; 只使用数字1到9每个数字 最多使用一…

北亚MF2200手机取证平台介绍

一、产品介绍。 北亚MF2200手机取证平台是由北亚企安科技&#xff08;北京&#xff09;有限公司&#xff08;Frombyte&#xff09;自主研发的一款针对智能手机&#xff08;iPhone、Android&#xff09;及 iPad 取证分析的法证平台。本平台采集速度快&#xff0c;可通过自动提取…

【VUE】VUE3绘制箭头组件

效果预览&#xff1a; 长、宽、粗细等等根据情况合理调整即可。 组件&#xff1a; <template><div class"line" :style"props.arrowsColor"></div> </template><script setup> import { defineProps, ref, onMounted } fr…

为什么使用AI 在游戏中不犯法

使用AI在游戏中本身并不违法&#xff0c;甚至在很多情况下&#xff0c;游戏公司自己也会在游戏中集成AI来提高游戏体验&#xff0c;例如通过AI驱动的非玩家角色&#xff08;NPC&#xff09;来增加游戏的互动性和挑战性。然而&#xff0c;使用AI是否违法取决于AI的使用方式和目的…

36. 有效的数独 - 力扣(LeetCode)

基础知识要求&#xff1a; Java&#xff1a;方法、for循环、if判断、数组 Python&#xff1a; 方法、for循环、if判断、列表、集合 题目&#xff1a; 请你判断一个 9 x 9 的数独是否有效。只需要 根据以下规则 &#xff0c;验证已经填入的数字是否有效即可。 数字 1-9 在每一…

word2019 64位 NoteExpress突然无法使用解决方法

之前用的好好的&#xff0c;去除格式化运行过一次。 打开别的文档&#xff0c;突然发现红框中的图标全变灰了 根据教程添加 加载项&#xff0c;然后word以管理员身份重启&#xff0c;NE也以管理员身份运行&#xff0c;又可以了 然后突然又不行了&#xff0c;重启电脑后NE变成…