7_2、C++程序设计进阶:数据共享
数据与函数
- 数据与函数
- 局部变量
- 全局变量
- 类的数据成员
- 类的静态成员
- 静态数据成员
- 静态函数成员
- 友元
- 友元函数
- 友元类
== 函数之间实现数据共享有以下几种方式:局部变量、全局变量、类的数据成员、类的静态成员和友元。==
如何共享局部变量呢?
- 在主调函数和被调函数之间通过参数传递来共享。
- 全局变量具有文件作用域,所以作用域中的各个函数都能共享全局变量。
- 类的数据成员具有类作用域,能够被类的函数成员共享。
- 类的静态成员。
- 友元共享。
数据与函数
在结构化程序设计中,有人提出“数据结构+算法=程序设计”,数据结构就是数据的组织,算法是用函数实现的,可见数据和函数很早就被看作程序设计的重点了。面向对象程序设计中,这种观点应稍作一下修改:“数据结构+算法=对象”。就是数据和函数构成了类的对象。
面向对象程序设计中,数据用来描述对象的属性,函数是行为,用来处理数据。将数据和函数封装到一个类里,类中的函数成员可以访问数据成员,函数成员之间可以实现数据共享。
局部变量
局部变量其实一般就是说具有块作用域的变量。如果要在不同的块之间共享存储在局部变量中的数据,只能通过参数传递来实现。这种共享只能在主调函数和被调函数之间进行。因为局部变量具有块作用域,所以不同函数中的局部变量是互不可见的,这也是函数之间的一种数据隐藏,在结构化程序设计中这是实现数据隐藏的唯一方式。而在面向对象设计中主要靠封装来隐藏数据。
全局变量
全局变量具有文件作用域,在整个作用域中,除了定义了同名局部变量的块以外的地方都可以直接访问全局变量。不同的函数在不同的地方都能访问相同的全局变量,这样就实现了函数之间对全局变量的共享。
使用全局变量的优缺点:
- 优点:在进行软件开发的时候使用全局变量会很方便,不用那么多的传递参数。
- 缺点:在多处使用了全局变量以后就不清楚此变量在哪些函数中使用过了,除非逐个查找,这样就会带来一个问题,如果全局变量要做一些大的改动,我们就不知道它会影响到哪些函数,这时就要通过大量的测试来排除全局变量变动带来的问题。
结构化程序设计中,只能使用前面提到的局部变量参数传递和全局变量这两种方式共享数据。这两种方式各有利弊,局部变量隐藏性好,但是传递的时候会有很大的系统开销,所以一般只传递少量数据,大量数据通过全局变量的方式共享,但这又使得程序模块间耦合严重,扩展和维护都很困难。C++中可以通过具有文件作用域的全局对象来实现数据和函数的共享,这实际上也属于全局变量的范畴。
类的数据成员
类中封装了数据成员和函数成员。其中数据成员可以被同一个类中的所有函数成员访问,这样就实现了数据的共享。但是我们又可以通过设置访问控制权限,把这种共享限制到类的范围之内,这样类的数据成员对外界来说是隐藏的。也就达到了共享与隐藏的辩证结合。总起来说,要达成这样的效果需要把类的数据成员都设置为私有类型。
- 若将类的数据参数设置为私有,则外部对象不能直接访问该数据对象,只能通过函数接口来访问该私有变量。这样程序模块间的耦合性就大大降低,提高了程序的可扩展性和可维护性,能够大大提高软件开发效率。
类的静态成员
静态成员包括静态数据成员和静态函数成员。
静态数据成员
- 使用场景:
之前讲到的类的数据成员都是一个对象一个拷贝,每个对象都有自己的数据成员的值,但有时候我们需要让某个类的所有对象共享某个数据成员,比如我们有一个学生类CStudent,其中有学号、姓名等数据成员,如果我们想要对学生人数进行统计,那么这个数据应该放在哪里呢?放在类外的某个地方的话数据的隐藏性就不好了。可能有朋友就说了,可以在类中增加一个数据成员存放学生人数,但这样就有两个坏处,第一,该类的每个对象都将有一个这个数据成员的副本,浪费内存;第二,学生人数可能在不同的对象中有不同的数,不一致了。这个时候就需要静态数据成员了。 - 特性
静态数据成员存放的是类的所有对象的某个共同特征的数据,对于每个对象而言,该数据都是相同的,在内存中只存在一份。这与类的一般数据成员不同,一般数据成员会在每个对象中都有一个拷贝,每个拷贝的值可能都不一样。静态数据成员由类的所有对象共同维护和使用,这样就实现了类的对象间的数据共享。 - 使用
声明静态数据成员的方式与一般数据成员不同的是,其前面要加static关键字,比如static int x;。静态数据成员具有静态生存期。它可以通过类名或对象名访问。用类名直接访问的方式为:类名::标识符。在类的声明中仅对静态数据成员进行引用性说明,就是带static的声明,必须在其文件作用域的其他地方进行定义性说明,也可以进行初始化,如果不显式初始化的话会将此静态数据成员初始化为0。
#include <iostream>
using namespace std;
class CStudent // 学生类的声明
{
public: CStudent(int nID) { m_nID = nID; m_nCount++; } // 构造函数CStudent(CStudent &s); // 拷贝构造函数int GetID(){ return m_nID;}void GetCount() { cout<<" 学生人数:"<<m_nCount<<endl; } // 输出静态数据成员
private: int m_nID;static int m_nCount; // 静态数据成员的引用性说明
};
CStudent::CStudent(CStudent &s)
{ m_nID = s.m_nID;m_nCount ++;
}int CStudent::m_nCount=0; // 静态数据成员的定义性说明及初始化
int main()
{CStudent A(6); // 定义对象Acout<<"学生A,"<<A.GetID();A.GetCount(); // 输出此时学生个数CStudent B(A); // 定义对象B,并用A初始化Bcout<<"学生B,"<<B.GetID(); // 输出此时学生个数B.GetCount();return 0;
}
- 若将m_nCount的属性改为public,将可以通过CStudent::m_nCount直接访问。
- 类的使用中一般情况,将数据定义为私有。
静态函数成员
类的私有静态变量无法用限位符来直接调用,此时就采用静态函数来解决。
静态成员函数跟静态数据成员一样,也是由类的所有对象所共有,由他们共同维护和使用。声明时前面也要加static关键字,比如,static void fun(void);。我们可以通过类名或对象名调用公有类型的静态成员函数,而非静态成员函数只能由对象名调用。
静态成员函数可以访问该类的静态数据成员和其他静态成员函数,如果要访问非静态数据成员,则必须将对象作为参数传递进去,然后通过传进去的对象名来访问。
class A
{
public:static void f(A a);
private:int x;
};
void A::f(A a)
{cout<<x; //对x的引用是错误的cout<<a.x; //正确
}
- 所以静态成员函数访问非静态成员很麻烦,它一般用来访问全局变量和同一个类中的静态数据成员。
#include <iostream>
using namespace std;
class CStudent // 学生类的声明
{
public: CStudent(int nID) { m_nID = nID; m_nCount++; } // 构造函数CStudent(CStudent &s); // 拷贝构造函数int GetID() { return m_nID;}static void GetCount() { cout<<" 学生人数:"<<m_nCount<<endl; } // 输出静态数据成员
private: int m_nID;static int m_nCount; // 静态数据成员的引用性说明
};
CStudent::CStudent(CStudent &s)
{ m_nID = s.m_nID;m_nCount ++;
}int CStudent::m_nCount=0; // 静态数据成员的定义性说明及初始化
int main()
{CStudent A(6); // 定义对象Acout<<"学生A,"<<A.GetID();A.GetCount(); // 输出此时学生个数CStudent B(A); // 定义对象B,并用A初始化Bcout<<"学生B,"<<B.GetID(); // 输出此时学生个数CStudent::GetCount(); //直接通过类名和限定符来访问静态函数return 0;
}
友元
友元是一种破坏类的封装性获取类的隐藏数据的方式。
友元机制:B类的成员函数直接访问A的数据成员。
class A
{
public:int Getx() { return x; }
private:int x;
};
class B
{
public:void Set(int y);
private:A a;
};//不正确用法
void B::Set(int y)
{a.x = y;
}
通过友元的方式,某个普通函数或者类的成员函数可以访问某个类中的私有数据,这样就等于在类的封装的很好的外衣上剪开了一个小洞,外界可以通过这个小洞访问到一些类内部的数据。友元提供了一种不同类或对象的成员函数之间、类的成员函数与普通函数之间共享数据的机制。它破坏了类的封装性和类数据的隐藏性,但是又给我们进行软件开发提供了很多方便,在我们实地进行软件开发的时候可以自己在共享和封装之间平衡一下,决定是否选择使用友元。原则上尽量少使用或不使用友元,除非确实很大的提高了开发效率。
- 在一个类中声明友元的方式是,用关键字friend把普通函数、其他类的成员函数或其他类声明为此类的友元,用friend声明的元素就可以访问此类的私有数据。如果友元是普通函数或是类的成员函数就叫做友元函数,如果友元是一个类则叫做友元类,友元类的所有成员函数均为友元函数。
- 友元的声明位置为想使用的资源的范围内。
友元函数
友元函数是在类的声明中用关键字friend修饰的普通函数或者其他类的成员函数。友元函数虽不是本类的成员函数,但在它的函数体中可以访问该类对象的私有成员和保护成员。
#include <iostream>
#include <math.h>
using namespace std;
class Data //Data类声明
{
public: //外部接口Data(int xx=0) { x=xx; }int GetX() { return x; }friend int Add(Data &a, Data &b);
private: //私有数据成员int x;
};
int Add(Data &a, Data &b)
{return a.x + b.x;
}
int main()
{Data a(1);Data b(2);int sum = Add(a, b);cout<<"The sum is "<<sum<<endl;return 0;
}
- 在Data类中声明友元函数Add时只给出了友元函数原型,友元函数Add的实现在类Data外。我们看到,在Add函数体中直接通过对象名访问了Data类的私有成员x,这就是友元的强大作用。我们在类外用一般方式访问x的话必须通过公共接口GetX来实现,若要访问的私有成员很多或者要访问的地方很多就要多次调用函数,对于我们写代码和程序运行都有效率上的损失,但是用友元也有个很大的缺点就是,如果私有数据x发生结构性的变化,那么友元函数就要做相应的修改,所有调用友元函数的地方可能也要修改,这就降低了开发效率,所以是否要使用友元可以自己权衡。
友元类
类也可以声明为另一个类的友元,就像友元函数那样,这个作为另一个类的友元的类就叫做友元类。如果一个类B是类A的友元类,则类B的所有成员函数都是类A的友元函数,都能访问类A的私有成员和保护成员。
class A
{...friend class B; // 将类B声明为类A的友元类...
}
class A
{
public:void Display() { cout<<x<<endl;}friend class B;
private:int x;
}
class B
{
public:void Set(int i);void Display();
private:A a;
};
void B::Set(int i)
{a.x=i; // 因为类B是类A的友元类,所以类B的成员函数可以访问类A对象的私有成员
}
void B::Display()
{a.Display();
}
友元类特性:
- ***友元关系不能传递,***如果类B是类A的友元,类C又是类B的友元,类C和类A如果没有声明则没有友元关系。
- 友元关系是单向的,如果类B是类A的友元,类B的成员函数可以访问类A对象的私有成员和保护成员,但是类A的成员函数不能访问类B对象的私有成员和保护成员。
相关文章:
7_2、C++程序设计进阶:数据共享
数据与函数 数据与函数局部变量全局变量类的数据成员 类的静态成员静态数据成员静态函数成员 友元友元函数友元类 函数之间实现数据共享有以下几种方式:局部变量、全局变量、类的数据成员、类的静态成员和友元。 如何共享局部变量呢? 在主调函数和被调…...
d2-crud-plus 使用小技巧(五)—— 搜索时间(或下拉列表)后,点击X清除按钮后返回值为null,导致异常
问题 使用vue2elementUId2-crud-plus,时间组件自动清除按钮,点击清除按钮后对应的值被设置为null,原本应该是空数组([]),导致数据传到后端后报错。不仅适用于搜索,表单一样有效果。 解决方法 …...
ChatGPT成知名度最高生成式AI产品,使用频率却不高
5月29日,牛津大学、路透社新闻研究所联合发布了一份生成式AI(AIGC)调查报告。 在今年3月28日—4月30日对美国、英国、法国、日本、丹麦和阿根廷的大约12,217人进行了调查,深度调研他们对生成式AI产品的应用情况。 结果显示&…...
R19 NR移动性增强概况
随着5G/5G-A技术不断发展和业务需求的持续增强,未来网络的部署将不断向高频演进。高频小区的覆盖范围小,用户将面临更为频繁的小区选择、重选、切换等移动性过程。 为了提升网络移动性能和保障用户体验,移动性增强一直是3GPP的热点课题。从NR…...
C语言:如何写文档注释、内嵌注释、行块注释?
技术答疑流程 扫描二维码,添加个人微信;支付一半费用,获取答案;如果满意,则支付另一半费用; 知识点费用:10元 项目费用:如果有项目任务外包需求,可以微信私聊...
Turtle中circle用法详解
在Python的Turtle图形库中,circle方法是一个非常灵活的工具,它允许我们以简单的方式绘制圆或圆的一部分。本文将深入探讨circle方法,特别关注radius和extent参数的用途及其正负值的意义。 一、circle方法概览 首先,让我们了解一…...
stack和queue(1)
一、stack的简单介绍和使用 1.1 stack的介绍 1.stack是一种容器适配器,专门用在具有先进后出,后进先出操作的上下文环境中,其删除只能从容器的一端进行元素的插入和弹出操作。 2.stack是作为容器适配器被实现的,容器适配器即是…...
前端3剑客(第1篇)-初识HTML
100编程书屋_孔夫子旧书网 当今主流的技术中,可以分为前端和后端两个门类。 前端:简单的理解就是和用户打交道 后端:主要用于组织数据 而前端就Web开发方向来说, 分为三门语言, HTML、CSS、JavaScript 语言作用HT…...
植被变化趋势线性回归以及可视化
目录 植被变化线性回归ee.Reducer.linearFit().reduce()案例:天水市2004-2023年EVI线性回归趋势在该图中,使用了从红色到蓝色的渐变来表示负趋势到正趋势。红色代表在某段时间中,植被覆盖减少,绿色表示持平,蓝色表示植被覆盖增加。 植被变化线性回归 该部分参考Google…...
大话设计模式学习笔记
目录 工厂模式策略模式备忘录模式(快照模式)代理模式单例模式迭代器模式访问者模式观察者模式解释器模式命令模式模板方法模式桥接模式适配器模式外观模式享元模式原型模式责任链模式中介者模式装饰模式状态模式 工厂模式 策略模式 核心:封装…...
MiniMax公司介绍
MiniMax是一家专注于通用人工智能技术的科技公司,成立于2021年12月。公司致力于成为通用人工智能时代基础设施建设者和内容应用创造者,积极投身于中国人工智能技术高速发展的时代大潮。MiniMax的团队由多位在人工智能领域有着丰富经验的专家组成…...
lucene 9.10向量检索基本用法
Lucene 9.10 中的 KnnFloatVectorQuery 是用来执行最近邻(k-Nearest Neighbors,kNN)搜索的查询类,它可以在一个字段中搜索与目标向量最相似的k个向量。以下是 KnnFloatVectorQuery 的基本用法和代码示例。 1. 索引向量字段 首先…...
【2023百度之星初赛】跑步,夏日漫步,糖果促销,第五维度,公园,新材料,星际航行,蛋糕划分
目录 题目:跑步 思路: 题目:夏日漫步 思路: 题目:糖果促销 思路: 题目:第五维度 思路: 题目:公园 思路: 新材料 思路: 星际航行 思路…...
vs2019 QT UI 添加新成员或者控件代码不提示问题解决方法
右键点击头文件,添加ui的头文件 添加现有项 找到uic目录的头文件 打开ui,QtWidgetsApplication2.ui,进行测试 修改一个名字: 重点: 设置一个布局: 点击生成解决方案: 以后每次添加控件后,记得点击保存 这样…...
【面试八股总结】MySQL事务:事务特性、事务并行、事务的隔离级别
参考资料:小林coding 一、事务的特性ACID 原子性(Atomicity) 一个事务是一个不可分割的工作单位,事务中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节。原子性是通过 undo …...
STL用法总结
文章目录 vector构造常用函数遍历适用情形注意事项使用迭代器删除可能会出现的错误 Set & MultiSet(不能用sort,会自动排序)构造常用函数删除,查找遍历 unordered_set(不排序集合),unordered_multiset Map & M…...
他人项目二次开发——慎接
接了一个朋友的项目——开发及运营迭代差不多2年多了,整体样子移动端和PC都能正常使用,但后期的扩展性及新功能添加出现瓶颈。 因此给了一部分钱,让我接手来开发——重构架构。 背景说明 朋友公司的技术人员是我帮忙招聘的,相关技…...
k8s之PV、PVC
文章目录 k8s之PV、PVC一、存储卷1、存储卷定义2、存储卷的作用2.1 数据持久化2.2 数据共享2.3 解耦2.4 灵活性 3、存储卷的分类3.1 emptyDir存储卷3.1.1 定义3.1.2 特点3.1.3 用途3.1.4 示例 3.2 hostPath存储卷3.2.1 定义3.2.2 特点3.2.3 用途3.2.4 示例 3.3 NFS存储卷3.3.1 …...
新人学习笔记之(JavaScript作用域)
一、作用域 1.通常来说,一段程序代码中所用的名字并不总是有效和可用的,而限定这个名字的可用性的代码范围就是这个名字的作用域。作用域的使用提高了程序逻辑的局部性,增强了程序的可靠性,减少了名字冲突 二、变量的作用域 1.变…...
图论第一天
在单位摸鱼,地铁上看了个开始,图论开了个头,后面也希望能往这个方向上转,努努力吧。 一周没做题啦,后面坚持继续做题+二刷,接着记录每一天!!!加油࿰…...
linux之kylin系统nginx的安装
一、nginx的作用 1.可做高性能的web服务器 直接处理静态资源(HTML/CSS/图片等),响应速度远超传统服务器类似apache支持高并发连接 2.反向代理服务器 隐藏后端服务器IP地址,提高安全性 3.负载均衡服务器 支持多种策略分发流量…...
centos 7 部署awstats 网站访问检测
一、基础环境准备(两种安装方式都要做) bash # 安装必要依赖 yum install -y httpd perl mod_perl perl-Time-HiRes perl-DateTime systemctl enable httpd # 设置 Apache 开机自启 systemctl start httpd # 启动 Apache二、安装 AWStats࿰…...
条件运算符
C中的三目运算符(也称条件运算符,英文:ternary operator)是一种简洁的条件选择语句,语法如下: 条件表达式 ? 表达式1 : 表达式2• 如果“条件表达式”为true,则整个表达式的结果为“表达式1”…...
2.Vue编写一个app
1.src中重要的组成 1.1main.ts // 引入createApp用于创建应用 import { createApp } from "vue"; // 引用App根组件 import App from ./App.vue;createApp(App).mount(#app)1.2 App.vue 其中要写三种标签 <template> <!--html--> </template>…...
DIY|Mac 搭建 ESP-IDF 开发环境及编译小智 AI
前一阵子在百度 AI 开发者大会上,看到基于小智 AI DIY 玩具的演示,感觉有点意思,想着自己也来试试。 如果只是想烧录现成的固件,乐鑫官方除了提供了 Windows 版本的 Flash 下载工具 之外,还提供了基于网页版的 ESP LA…...
数据链路层的主要功能是什么
数据链路层(OSI模型第2层)的核心功能是在相邻网络节点(如交换机、主机)间提供可靠的数据帧传输服务,主要职责包括: 🔑 核心功能详解: 帧封装与解封装 封装: 将网络层下发…...
2025 后端自学UNIAPP【项目实战:旅游项目】6、我的收藏页面
代码框架视图 1、先添加一个获取收藏景点的列表请求 【在文件my_api.js文件中添加】 // 引入公共的请求封装 import http from ./my_http.js// 登录接口(适配服务端返回 Token) export const login async (code, avatar) > {const res await http…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...
稳定币的深度剖析与展望
一、引言 在当今数字化浪潮席卷全球的时代,加密货币作为一种新兴的金融现象,正以前所未有的速度改变着我们对传统货币和金融体系的认知。然而,加密货币市场的高度波动性却成为了其广泛应用和普及的一大障碍。在这样的背景下,稳定…...
AI,如何重构理解、匹配与决策?
AI 时代,我们如何理解消费? 作者|王彬 封面|Unplash 人们通过信息理解世界。 曾几何时,PC 与移动互联网重塑了人们的购物路径:信息变得唾手可得,商品决策变得高度依赖内容。 但 AI 时代的来…...
