C++ 类的静态成员
在结构化程序设计中程序模块的基本单位是函数,因此模块间对内存中数据的共享是通过函数与和函数之间的数据共享来实现的,其中包括两个途径——参数传递和全局变量。
面向对象的程序设计方法兼顾数据的共享和保护,将数据与操作数据的函数封装在一起,构成集成度更高的模块。类中的数据成员可以被同一类中的任何一个函数访问。这样一方面在类内部的函数之间实现了数据的共享,另一方面这种共享是受限制的,可以设置适当的访问控制属性。把共享只限制在类的范围之内,对类外来说,类的数据成员仍是隐藏的,达到了共享与安全两全。
然而这些还不是数据共享的全部。对象与对象之间也需要共享数据。
类的静态成员是解决同一个类中不同对象之间数据和函数共享问题的。
例如可以抽象出某公司全体雇员的共性,设计如下雇员类:
class Employee
{int empNo;int id;string name;...//其他数据成员与函数成员略
};
如果需要统计雇员总数,这个数据存放在什么地方呢?若以类外的变量来存储总数,不能实现数据的隐藏。若在类中增加一个数据成员来存放总数,必然在每一个对象中都存储一个副本,不仅冗余,而且每个对象分别维护一个“总数”,容易造成数据的不一致性。由于这个数据应该为Employee类的所有对象所共享的,比较理想的方案是类的所有对象共同拥有一个用来存放总数的数据成员,即静态数据成员。
1.静态数据成员
我们说“一个类的所有对象具有相同的属性”,是指属性的个数、名称、数据类型相同,各个对象的属性值则可以各不相同,这样的属性在面向对象方法中,称为“实例属性”,在C++程序中以类的非静态数据成员表示。例如上述的Employee类中的empNo,id,name都是以非静态数据成员表示的实例属性,它们在类的每一个对象中都拥有一个副本,这样的实例属性正是每个对象区别其他对象的特征。
如果某个属性为整个类所共有,不属于任何一个具体对象,则采用static关键字来声明为静态成员。静态成员在每个类只有一个副本,由该类的所有对象共同维护和使用,从而实现了同一类的不同对象之间的数据共享。
**类属性是描述类的所有对象共同特征的一个数据项,对于任何对象实例,它的属性值是相同的。**简单地说,如果将“类”比作一个工厂,对象是工厂生产出的产品,那么静态成员是存放在工厂中、属于工厂的,而不属于每个产品。
**静态数据成员具有静态生存期。**由于静态数据成员不属于任何一个对象,因此可以通过类名对它进行访问,一般的用法是类名::标识符
。在类的定义中仅仅对静态数据成员进行引用性声明,必须在命名空间作用域的某个地方使用类名限定定义性声明,这时也可以进行初始化。在UML语言中,静态数据成员通过在数据成员下方添加下划线来表示。
【注意】之所以类的静态成员需要在类定义之外再加以定义,是因为需要以这种方式专门为它们分配空间。非静态数据成员无须以这种方式定义,因为它们的空间是与它们所属对象的空间同时分配的。
【例】具有静态数据成员的Point类,静态数据成员count用于统计Point类的对象个数。
#include<iostream>
using namespace std;class Point//Point类的定义
{
public://外部接口Point(int x = 0, int y = 0) :x(x), y(y)//构造函数{//在构造函数中对count累加,所有对象共同维护同一个countcount++;}Point(Point& p)//拷贝构造函数{x = p.x;y = p.y;count++;}~Point(){count--;}int getX(){return x;}int getY(){return y;}void ShowCount()//输出静态数据成员{cout << " 对象数量:" << count << endl;}
private://私有成员int x, y;static int count;//静态数据成员声明,用于记录点的个数
};
int Point::count = 0;//静态数据成员定义和初始化,使用类名限定int main()//主函数
{Point a(4, 5);//定义对象a,其构造函数会使count加一cout << "Point A:" << "(" << a.getX() << ", " << a.getY() << ")";a.ShowCount();//输出对象的个数Point b(a);//定义对象b,其构造函数会使count加一cout << "Point B:" << "(" << b.getX() << ", " << b.getY() << ")";b.ShowCount();//输出对象的个数return 0;
}
运行结果及分析:
上例中,类Point的数据成员count被声明为静态,用来给Point类的对象计数,每定义一个新对象,count的值就相应加1。静态数据成员count的定义和初始化在类外进行,初始化时引用的方式也值得注意,首先应该注意的是要利用类名来引用,其次,虽然这个静态数据成员是私有类型,在这里却可以直接初始化。除了这种特殊场合,在其他地方,例如主函数中就不允许直接访问。count的值是在类的构造函数中计算的,a对象生成时,调用有默认参数的构造函数,b对象生成时,调用拷贝构造函数,两次调用构造函数都访问的是同一个静态成员count。通过对象a和对象b分别调用ShowCount函数,输出的也是同一个count在不同时刻的数值。这样就实现了a,b两个对象之间的数据共享。
【注意】在对类的静态私有数据成员初始化的同时,还可以引用类的其他私有成员。例如,如果一个类T存在类型为T的静态私有对象时,那么可以用该类的私有构造函数将其初始化。
2.静态函数成员
在上例中,函数ShowCount是专门用来输出静态成员count的。要输出count只能通过Point类的某个对象来调用函数ShowCount。在所有对象声明之前count的值是初始值0。如何输出这个初始值呢?显然由于尚未声明如何对象,无法通过对象来调用ShowCount。由于count是为整个类所共有的,不属于任何对象,因此我们自然会希望对count的访问也不要通过整个对象。将程序代码进行改写如下:
#include<iostream>
using namespace std;class Point//Point类的定义
{
public://外部接口Point(int x = 0, int y = 0) :x(x), y(y)//构造函数{//在构造函数中对count累加,所有对象共同维护同一个countcount++;}Point(Point& p)//拷贝构造函数{x = p.x;y = p.y;count++;}~Point(){count--;}int getX(){return x;}int getY(){return y;}void ShowCount()//输出静态数据成员{cout << " 对象数量:" << count << endl;}
private://私有成员int x, y;static int count;//静态数据成员声明,用于记录点的个数
};
int Point::count = 0;//静态数据成员定义和初始化,使用类名限定int main()//主函数
{Point::ShowCount();//直接通过类名调用函数,输出对象个数的初始值Point a(4, 5);//定义对象a,其构造函数会使count加一cout << "Point A:" << "(" << a.getX() << ", " << a.getY() << ")";a.ShowCount();//输出对象的个数Point b(a);//定义对象b,其构造函数会使count加一cout << "Point B:" << "(" << b.getX() << ", " << b.getY() << ")";b.ShowCount();//输出对象的个数return 0;
}
在主函数中,加入语句Point::ShowCount();
直接通过类名调用函数,输出对象个数的初始值,但是编译会出错,因为对普通函数成员的调用必须通过对象名。
尽管如此C++中还是可以有办法实现我们上述期望,这就是通过使用静态成员函数。
**所谓静态成员函数就是使用static关键字声明的函数成员。**和静态数据成员一样,静态成员函数也属于整个类,由于同一个类的所有对象共同拥有,为这些对象所共享。
静态成员函数可以通过类名或者对象名两种方式调用,而非静态成员函数只能通过对象名来调用。
【注意】虽然静态函数成员可以通过类名或者对象名两种方式调用,,但一般习惯通过类名调用。因为即使通过对象名调用,起作用的也只是对象的类型信息,与所使用的对象毫无关系。
**静态成员函数可以通过类名可以直接访问该类的静态数据和函数成员。而访问非静态成员,必须通过对象名。**例如:
class A
{
public:static void f(A a);
private:int x;
};
void A::f(A a)
{cout << x;//error 对x的引用错误cout << a.x;//正确
}
可以看到,通过静态函数成员访问非静态成员相当麻烦,一般情况下,静态函数成员主要用来访问同一个类中的静态数据成员,维护对象之间共享的数据。
【注意】之所以在静态成员函数中访问类的非静态成员需要指明对象,是因为静态成员函数对静态成员函数的调用是没有目的对象的,因此不能像非静态成员函数那样,隐含地通过目的对象访问类的非静态成员。
【例】具有静态数据和静态函数成员的Point类
class Point//Point类的定义
{
public://外部接口Point(int x = 0, int y = 0) :x(x), y(y)//构造函数{//在构造函数中对count累加,所有对象共同维护同一个countcount++;}Point(Point& p)//拷贝构造函数{x = p.x;y = p.y;count++;}~Point(){count--;}int getX(){return x;}int getY(){return y;}static void ShowCount()//静态函数成员{cout << " 对象数量:" << count << endl;}
private://私有成员int x, y;static int count;//静态数据成员声明,用于记录点的个数
};
int Point::count = 0;//静态数据成员定义和初始化,使用类名限定int main()//主函数
{Point a(4, 5);//定义对象a,其构造函数会使count加一cout << "Point A:" << "(" << a.getX() << ", " << a.getY() << ")";Point::ShowCount();//直接通过类名调用函数,输出对象的个数Point b(a);//定义对象b,其构造函数会使count加一cout << "Point B:" << "(" << b.getX() << ", " << b.getY() << ")";Point::ShowCount();//直接通过类名调用函数,输出对象的个数return 0;
}
运行结果及分析:
与第一个例子相比,这里只是在类的定义中,将ShowCount函数改写为静态成员函数。于是在主函数中既可以使用类名也可以使用对象名来调用ShowCount。
这个程序与第一个例子的输出结果完全相同。相比而言,采用静态函数成员的好处就是可以不依赖任何对象,直接访问静态数据。
相关文章:

C++ 类的静态成员
在结构化程序设计中程序模块的基本单位是函数,因此模块间对内存中数据的共享是通过函数与和函数之间的数据共享来实现的,其中包括两个途径——参数传递和全局变量。 面向对象的程序设计方法兼顾数据的共享和保护,将数据与操作数据的函数封装…...

360T7路由器进行WiFi无线中继教程
360T7路由器进行WiFi中继教程 1. 概述2. 360T7路由器进行WiFi中继实现教程2.1 登录路由器管理界面2.2 选择上网方式2.3 搜索WiFi2.4 连接WiFi2.5 点击确认2.6 在主页面查看网络 1. 概述 中继路由系统由一组中继路由器组成,为不能交换路由信息的路由域提供中继路由。…...

主成分分析
主成分分析 相关概念方差协方差协方差矩阵特征值和特征向量 主成分分析数据降维主成分分析原理主成分分析过程sklearn库中的PCA主成分分析实现案例 相关概念 方差 方差是一个用来衡量一组数据离散程度的统计量,它是各样本与样本均值的差的平方和的平均值。方差越大…...

笙默考试管理系统-MyExamTest(26)
笙默考试管理系统-MyExamTest(26) 目录 一、 笙默考试管理系统-MyExamTest 二、 笙默考试管理系统-MyExamTest 三、 笙默考试管理系统-MyExamTest 四、 笙默考试管理系统-MyExamTest 五、 笙默考试管理系统-MyExamTest 笙默考试管理系统-MyEx…...

重新理解 RocketMQ Commit Log 存储协议
最近突然感觉:很多软件、硬件在设计上是有 root reason 的,不是 by desgin 如此,而是解决了那时、那个场景的那个需求。一旦了解后,就会感觉在和设计者对话,了解他们的思路,学习他们的方法,思维…...

ES6基础知识十:你是怎么理解ES6中 Decorator 的?使用场景?
一、介绍 Decorator,即装饰器,从名字上很容易让我们联想到装饰者模式 简单来讲,装饰者模式就是一种在不改变原类和使用继承的情况下,动态地扩展对象功能的设计理论。 ES6中Decorator功能亦如此,其本质也不是什么高大…...

接口/Web自动化测试如何做?框架如何搭建封装?
目录:导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结(尾部小惊喜) 前言 自动化测试怎么做…...

Linux怎么从网络上下载文件
wget命令用于从网络上下载文件 下载文件: wget [URL]使用wget命令加上要下载的文件的URL,可以将文件下载到当前目录。 指定保存的文件名: wget -O [保存的文件名] [URL]使用-O选项后跟保存的文件名,可以指定下载的文件保存的名称…...

Flutter携带JSON参数post请求
在Flutter中发送带有JSON参数的网络请求,你可以使用HTTP库(如http或dio)来实现。以下是使用http库发送网络请求并携带JSON参数的示例: import package:http/http.dart as http; import dart:convert;// 创建参数Map Map<Strin…...

【vue】vue-image-lazy图片懒加载使用与介绍【超详细+npm包源代码】
简介 当前插件是基于vue3,写的一个图片懒加载,文章最下方是npm包的源码,你可以自己拿去研究和修改,如有更好的想法可以留言,如果对你有帮助,可以点赞收藏和关注,谢谢。 后续会添加图片放大和切…...

MFC第二十四天 使用GDI对象画笔和画刷来开发控件(分页控件选择态的算法分析、使用CToolTipCtrl开发动静态提示)
文章目录 GDI对象画笔和画刷来开发控件梯形边框的按钮控件CMainDlg.hCMainDlg.cppCLadderCtrl.hCLadderCtrl.cpp 矩形边框的三态按钮控件 CToolTipCtrl开发动静态提示CMainDlg.hCMainDlg.cppCLadderCtrl.hCLadderCtrl.cpp: 实现文件 矩形边框的三态按钮控件 CToolTipCtrl开发动…...

【NLP-新工具】语音转文本与OpenAI的用途
一、说明 OpenAI最近2022发布了一个名为Whisper的新语音识别模型。与DALLE-2和GPT-3不同,Whisper是一个免费的开源模型。它的主要功能就是将语音翻译成文本。本文将介绍如何使用这个重要应用库。 二、 Whisper概念 2.1 Whisper是啥? Whisper 是一种自动…...

try-catch-finally的字节码原理
Java 中有一个非常重要的内容是 try-catch-finally 的执行顺序和返回值问题,其中 finally 一定会执行,但是为什么会这样? 下面看下 try-catch-finally 背后的实现原理 try-catch public class Test {public static void main(String[] args)…...

基于双层优化的微电网系统规划设计方法(Matlab代码实现)
目录 💥1 概述 1.1 微电网系统结构 1.2 微电网系统双层规划设计结构 1.3 双层优化模型 1.4 上层容量优化模型 1.5 下层调度优化模型 📚2 运行结果 🎉3 文献来源 🌈4 Matlab代码、数据、文章讲解 💥1 概述 文献来源&…...

【Nginx13】Nginx学习:HTTP核心模块(十)Types、AIO及其它配置
Nginx学习:HTTP核心模块(十)Types、AIO及其它配置 今天学习的内容也比较简单,主要的是 Types 相关的配置,另外还会了解一下 AIO 以及部分没有特别大的分类归属的配置指令的使用。后面的内容都是 HTTP 核心模块中比较小…...

2023年华数杯数学建模C题思路分析
文章目录 0 赛题思路1 竞赛信息2 竞赛时间3 组织机构4 建模常见问题类型4.1 分类问题4.2 优化问题4.3 预测问题4.4 评价问题 0 赛题思路 (赛题出来以后第一时间在CSDN分享) https://blog.csdn.net/dc_sinor 1 竞赛信息 为了培养学生的创新意识及运用数…...

安卓手机变身Linux服务器
文章目录 前言一、准备工作1、安卓手机2、下载软件二、开始安装1、检查系统,确认版本并安装2、配置(安卓7.0 及以上的用户忽略此步)3、问题处理【没有异常的小伙伴忽略】总结前言 在实际开发中有很多地方都需要服务器资源,但是服务器资源不论在哪里都是比较紧缺的资源,今…...

【Ansible】Ansible自动化运维工具之playbook剧本
playbook 一、playbook 的概述1. playbook 的概念2. playbook 的构成 二、playbook 的应用1. 安装 httpd 并启动2. 定义、引用变量3. 指定远程主机 sudo 切换用户4. when条件判断5. 迭代6. Templates 模块6.1 添加模板文件6.2 修改主机清单文件6.3 编写 playbook 7. tags 模块 …...

Yolov8目标检测
Yolov8目标检测 目录 Yolov8目标检测一、准备数据集二、源码下载配置2.1 下载库2.2 修改配置2.3 训练2.4 验证2.5 测试2.6 模型导出2.7 本地测试 一、准备数据集 Yolov8只支持yolo格式的数据,所以,需要将数据集格式调整为 datasets|images|train|00000…...

Jmeter用于接口测试中,关联如何实现
Jmeter用于接口测试时,后一个接口经常需要用到前一次接口返回的结果,应该如何获取前一次请求的结果值,应用于后一个接口呢,拿一个登录的例子来说明如何获取。 1、打开jmeter, 使用的3.3的版本,新建一个测试计划&#x…...

线程状态
从卖包子的案例学习进程间的通信 public class Test {public static void main(String[] args) {Object objnew Object();Thread th1new Thread(){Overridepublic void run() {synchronized (obj){System.out.println("来三个包子!");try {obj.wait(); /…...

HTML一些基础知识
1、Web标准:主要包含结构、表现、行为。结构用于对网页元素进行整理和分类,主要指HTML。表现用于设置网页元素的板式、颜色、大小等外观样式,主要指的是CSS。行为主要指的是网页模型的定义以及交互的编写,主要是js文件。 Html相当…...

git 命令总结
一、本地分支和仓库里的分支不同步(本地看不到最新的分支) 1.使用 git fetch origin 或者git remote update origin --prune命令更新 2.git branch -r 查看 即可 二、git 合并代码 1. git 如何把分支代码合并到master 1.1 首先切换到分支 git checkou…...

【Django】如何优化数据库访问
原文作者:我辈李想 版权声明:文章原创,转载时请务必加上原文超链接、作者信息和本声明。 文章目录 前言一、数据库层面优化常用优化postgresql查询分库分表 二、内存层面优化三、代码层面优化 前言 Django是一个高级的Web框架,它…...

常压室温超导材料:揭开物理学的新篇章
常压室温超导材料:揭开物理学的新篇章 目录 引言超导现象简介常压室温超导材料的重要性常压室温超导材料的研究进展常压室温超导材料的挑战与前景结论 1. 引言 自从1911年荷兰物理学家海克卡默林奥涅斯发现超导现象以来,超导技术在许多领域都有着广泛…...
【《C# 10 和 .NET 6入门与跨平台开发(第6版)》——一本循序渐进的C#指南】
这个新版本对上一版做了全面修订,涵盖C# 10和.NET 6的所有新功能. 本书讨论面向对象编程、编写函数、测试函数、调试函数、实现接口以及继承类等主题;介绍.NET API,这些API可执行多种任务,如管理和查询数据,监视和改进…...

2.5 BUMP图改进
一、Bump Mapping介绍 凹凸贴图映射技术是对物体表面贴图进行变化然后进行光计算的一种技术。例如给法线分量添加噪音,或者在一个保护扰动值的纹理图中进行查找。这是一个提升物理真实感的有效方法,但却不需要额外的提升物体的几何复杂度。这种法式在提…...

第六篇-ChatGLM2-6B-CentOS7安装部署-GPU版
环境 系统:CentOS-7 CPU: 14C28T 显卡:Tesla P40 24G 驱动: 515 CUDA: 11.7 cuDNN: 8.9.2.26模型文件 https://huggingface.co/THUDM/chatglm2-6b 下载模型相关文件到自己目录 我的是/models/chatglm2-6b [rootai-server chatglm2-6b]# pwd /models/c…...

dotnet 依赖注入-批量注入Controller,service,Dao
此类为扩展注入类,使用autofuc 仅供参考 注入接口和实现。 使用方法: //配置项调用ConfigContainer public void ConfigureContainer(ContainerBuilder builder){TestMicroService.ConfigContainer(builder);} //service调用RegisteApiController …...

【Spring】Spring对IoC的实现
根据 【动力节点】最新Spring框架教程,全网首套Spring6教程,跟老杜从零学spring入门到高级 以及老杜的原版笔记 https://www.yuque.com/docs/share/866abad4-7106-45e7-afcd-245a733b073f?# 《Spring6》 进行整理, 文档密码:mg9b…...