当前位置: 首页 > news >正文

【C++】static修饰的“静态成员函数“--静态成员在哪定义?静态成员函数的作用?

声明为static的类成员称为类的静态成员,用static修饰的成员变量,称之为静态成员变量;用

static修饰的成员函数,称之为静态成员函数。静态成员变量一定要在类外进行初始化

 

一、静态成员变量

1)特性

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

2)使用场景

现在我们有一个要求,需要统计现存对象以及累计创建对象的个数,所以我们依赖一个在没有实例存在的时候仍能存在的变量,而且该变量要和该类强相关,此时我们便可以利用到静态变量的特性,创建两个静态变量在public中(公共区中),并在类的外面定义他们,初始值为零,在每次调用构造函数或者拷贝构造函数时都使n加一,m也加一,每次调用析构函数时,m就减一,如此,n的数值就是累计创建的个数,m的值就是现存对象的个数,它们和类直接关联,而且在所有实例被清除后它们仍能存在着去记录数据。

总结:静态成员变量的作用就是突破类域

3)缺点:可能会在意外调用后被修改

但是这样使用静态变量也有一定的弊端,当有使用者(非用户,而是使用该类的其他人)在改变m和n的值时,将会影响我们的判断。

解决办法就是将这种变量全都放在private中,这样只有我们自己能使用它,它的适用范围变为了类的内部,我们称他为“类全局”。当然,如果有友元函数声明或者友元类声明也能调用他们。

4)注意

定义在类中的全局变量不走初始化列表

空指针、匿名对象都能访问他,因为他放在整个类中(限制于公有的前提)

 

二、静态成员函数

1)特性

1.静态成员一大特征就是无this指针,因此!!它没办法调用非静态的成员函数,毕竟非静态成员函数里面可都是有this指针的,所以一般和静态成员变量配套使用;

2.它可直接被调用而无需创建对应的"实例",类似这样:

YourClass:: YourStaticFunction();

3.它只能访问静态变量,这里的静态变量指同一类中的静态变量。如果是子类或者友元类的静态成员函数也可以访问该类中的静态成员变量。

 

三、实例观察现象

一下是作者编写的用于观察现象的小实例:

#include<iostream>
using namespace std;
//我们创建一个用于演示的"A"类
class A
{
public:A();//此处采用定义和声明分离的方法A(const A& other);~A();static void Print();//声明给静态,定义不用加staticA& operator= (const A aa);
private:static int _Creat;//静态成员变量_Creat声明static int _NumNow;//静态成员变量_NumNowint _num;
};//现在是在类外
//直接使用类名加冒号加变量名的方式直接给该类变量定义
//而且可以在这里个静态成员变量赋初识值
int A::_Creat = 0;
int A::_NumNow = 0;//声明一个非静态成员函数f2
A f2(void);
void func1(void);//构造函数
A::A():_num(0)
{cout << "A( )" << endl;//在构造函数中我们可以调用该类中的静态成员变量//这样我们就能统计存在和累计创建实例的个数了_Creat++;_NumNow++;
}//拷贝构造函数
A::A(const A& other)
{_num = other._num;cout << "A(const A& other)" << endl;
}//析构函数
A::~A()
{cout << "~A( )" << endl;_NumNow--;
}//输出两个变量的函数
void  A::Print()
{cout << "现存数量:" << _NumNow << " , " << "累计创建:" << _Creat << endl;
}//赋值运算符重载
A& A::operator= (const A aa)
{_num = aa._num;return *this;
}using namespace std;//命名空间展开
//定义一个非静态成员函数f2
A f2(void)
{A a;        //生成一个实例后传值返回return a;
}
//定义一个非静态成员函数f1用于演示
void func1(void)
{cout << "/********生成一个实例********/" << endl;A aa0;         //生成一个实例A::Print();    //输出变量cout << "/******创建一个匿名对象******/" << endl;A();           //创建一个匿名对象A::Print();    //输出变量cout << "/**************************/" << endl;cout << " 将f2返回值传值返回给实例temp1" << endl;A temp1 = f2();  //将f2返回值传值返回给实例temp1A::Print();    //输出变量cout << "/****先创建后使用运算符赋值**/" << endl;A temp2;temp2 = f2();A::Print();    //输出变量cout << "/****f2返回值赋给匿名对象****/" << endl;A() = f2();    //f2返回值赋给匿名对象cout << "/**************************/" << endl;
}//主函数
int main(void)
{func1();//函数结束后再观察一次变量std::cout << "func1 done" << endl;A::Print();return 0;
}

通过观察显现我们还可以看到编译器存在将多次构造再拷贝构造直接优化为一次构造的情况,例如第三组的输出情况。


四、遇到的问题:

遇到了现存数出现负数的问题:

赋值运算符重载返回值不是传引用返回导致多次调用析构的问题,在刚开始的现象中出现了现存数量为-1的情况,原因是析构函数多调用了一次,刚开始认为是赋值给匿名对象的原因,于是注释掉后重试发现想象仍然存在,有两组涉及到赋值运算符的组,编译器优化掉赋值的一组没有问题,最后发现问题在没有优化的有这组里,那么就可以确定是赋值运算符重载的问题了

然后发现是赋值运算符重载采用了传值返回,将其改为传引用返回后可以正常运行,我们平成使用赋值运算符重载也要使用传引用返回,这样可以减少不必要的拷贝,并且传引用返回可以链式赋值,而传值返回则不行,

然后尝试性得给赋值运算符重载的返回值从传值返回改为传引用返回,然后就得到了正确的结果

void func1(void)
{cout << "/******************/" << endl;A() = f2(); A::Print();    //输出变量cout << "/******************/" << endl;
}

 那么为什么赋值运算符重载传值返回会出现多次析构的问题呢?

经过在代码中添加输出,得到了以下结果:

赋值运算符重载调用了拷贝构造,如果是传引用返回则不会调用这一次拷贝构造,

所以我猜测是传值返回本质是将一个临时的自定义类型对象的值拷贝给另外一个对象的过程,但是不知道为什么这个过程中创建临时变量的构造没有触发,或者理解为没有显示调用但是析构却显示调用了,导致计数出现问题,应该是编译器部分优化的问题。

如果说怎样规避这样的问题的话那就是尽可能减少这类隐式的转化。


以下是问题代码:

#include<iostream>
using namespace std;
//我们创建一个用于演示的"A"类
class A
{
public:A();//此处采用定义和声明分离的方法A(const A& other);~A();static void Print();//声明给静态,定义不用加staticA operator= (const A aa);
private:static int _Creat;//静态成员变量_Creat声明static int _NumNow;//静态成员变量_NumNowint _num;
};//现在是在类外
//直接使用类名加冒号加变量名的方式直接给该类变量定义
//而且可以在这里个静态成员变量赋初识值
int A::_Creat = 0;
int A::_NumNow = 0;//声明一个非静态成员函数f2
A f2(void);
void func1(void);//构造函数
A::A():_num(0)
{cout << "A( )" << endl;//在构造函数中我们可以调用该类中的静态成员变量//这样我们就能统计存在和累计创建实例的个数了_Creat++;_NumNow++;
}//拷贝构造函数
A::A(const A& other)
{_num = other._num;cout << "A(const A& other)" << endl;
}//析构函数
A::~A()
{cout << "~A( )" << endl;_NumNow--;
}//输出两个变量的函数
void  A::Print()
{cout << "现存数量:" << _NumNow << " , " << "累计创建:" << _Creat << endl;
}//赋值运算符重载
A A::operator= (const A aa)
{_num = aa._num;return *this;
}using namespace std;//命名空间展开
//定义一个非静态成员函数f2
A f2(void)
{A a;        //生成一个实例后传值返回return a;
}
//定义一个非静态成员函数f1用于演示
void func1(void)
{cout << "/******************/" << endl;A aa0;         //生成一个实例A::Print();    //输出变量cout << "/******************/" << endl;A();           //创建一个匿名对象A::Print();    //输出变量cout << "/******************/" << endl;A temp1 = f2();  //将f2返回值给实例temp1A::Print();    //输出变量cout << "/******************/" << endl;//A() = f2();    //f2返回值赋给匿名对象//这个行为很危险,具体逻辑可能需要看到汇编层才能判断//如果这样赋值会出现多次析构的情况//我们尝试另一个例子和上一组形成对照A temp2;temp2 = f2();A::Print();    //输出变量cout << "/******************/" << endl;
}//主函数
int main(void)
{func1();//函数结束后再观察一次变量std::cout << "func1 done" << endl;A::Print();return 0;
}

多次析构情况如下:

相关文章:

【C++】static修饰的“静态成员函数“--静态成员在哪定义?静态成员函数的作用?

声明为static的类成员称为类的静态成员&#xff0c;用static修饰的成员变量&#xff0c;称之为静态成员变量&#xff1b;用 static修饰的成员函数&#xff0c;称之为静态成员函数。静态成员变量一定要在类外进行初始化 一、静态成员变量 1)特性 所有静态成员为所有类对象所共…...

=computed() =ref()

computed() ref() 在 Vue 中&#xff0c;computed() 和 ref() 是 Vue 3 组合式 API 的核心工具&#xff0c;它们分别用于 计算属性 和 响应式数据。以下是它们的区别和用法&#xff1a; 1. ref() 作用 用于创建响应式的单一数据。可以是基本类型&#xff08;如字符串、数字、…...

webgl threejs 云渲染(服务器渲染、后端渲染)解决方案

云渲染和流式传输共享三维模型场景 1、本地无需高端GPU设备即可提供三维项目渲染 云渲染和云流化媒体都可以让3D模型共享变得简单便捷。配备强大GPU的远程服务器早就可以处理密集的处理工作&#xff0c;而专有应用程序&#xff0c;用户也可以从任何个人设备查看全保真模型并与…...

【shell编程】函数、正则表达式、文本处理工具

函数 系统函数 常见内置命令 echo打印输出 #!/bin/bash # 输出普通文本 echo "Hello, World!"# 输出变量值 name"Alice" echo "Hello, $name"# 输出带有换行符的文本 echo -n "Hello, " # -n 选项不输出换行 echo "World!&quo…...

解决 npm xxx was blocked, reason: xx bad guy, steal env and delete files

问题复现 今天一位朋友说&#xff0c;vue2的老项目安装不老依赖&#xff0c;报错内容如下&#xff1a; npm install 451 Unavailable For Legal Reasons - GET https://registry.npmmirror.com/vab-count - [UNAVAILABLE_FOR_LEGAL_REASONS] vab-count was blocked, reas…...

如何进行高级红队测试:OpenAI的实践与方法

随着人工智能&#xff08;AI&#xff09;技术的迅猛发展&#xff0c;AI模型的安全性和可靠性已经成为业界关注的核心问题之一。为了确保AI系统在实际应用中的安全性&#xff0c;红队测试作为一种有效的安全评估方法&#xff0c;得到了广泛应用。近日&#xff0c;OpenAI发布了两…...

Java:二维数组

目录 1. 二维数组的基础格式 1.1 二维数组变量的创建 —— 3种形式 1.2 二维数组的初始化 \1 动态初始化 \2 静态初始化 2. 二维数组的大小 和 内存分配 3. 二维数组的不规则初始化 4. 遍历二维数组 4.1 for循环 ​编辑 4.2 for-each循环 5. 二维数组 与 方法 5.1…...

Android 天气APP(三十七)新版AS编译、更新镜像源、仓库源、修复部分BUG

上一篇&#xff1a;Android 天气APP&#xff08;三十六&#xff09;运行到本地AS、更新项目版本依赖、去掉ButterKnife 新版AS编译、更新镜像源、仓库源、修复部分BUG 前言正文一、更新镜像源① 腾讯源③ 阿里源 二、更新仓库源三、修复城市重名BUG四、地图加载问题五、源码 前…...

Xilinx IP核(3)XADC IP核

文章目录 1. XADC介绍2.输入要求3.输出4.XADC IP核使用5.传送门 1. XADC介绍 xadc在 所有的7系列器件上都有支持&#xff0c;通过将高质量模拟模块与可编程逻辑的灵活性相结合&#xff0c;可以为各种应用打造定制的模拟接口&#xff0c;XADC 包括双 12 位、每秒 1 兆样本 (MSP…...

计算机网络socket编程(2)_UDP网络编程实现网络字典

个人主页&#xff1a;C忠实粉丝 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 C忠实粉丝 原创 计算机网络socket编程(2)_UDP网络编程实现网络字典 收录于专栏【计算机网络】 本专栏旨在分享学习计算机网络的一点学习笔记&#xff0c;欢迎大家在评论区交流讨…...

c#窗体列表框(combobox)应用——省市区列表选择实例

效果如下&#xff1a; designer.cs代码如下&#xff1a; using System.Collections.Generic;namespace 删除 {public partial class 省市区选择{private Dictionary<string, List<string>> provinceCityDictionary;private Dictionary<string,List<string&…...

Nginx 架构与设计

Nginx 是一个高性能的 HTTP 和反向代理服务器&#xff0c;同时也可以用作邮件代理和通用的 TCP/UDP 负载均衡器。它的架构设计以高并发、高可扩展性和高性能为目标&#xff0c;充分利用操作系统提供的多路复用机制和事件驱动模型。以下是 Nginx 的架构和设计特点&#xff1a; 1…...

python Flask指定IP和端口

from flask import Flask, request import uuidimport json import osapp Flask(__name__)app.route(/) def hello_world():return Hello, World!if __name__ __main__:app.run(host0.0.0.0, port5000)...

多线程 相关面试集锦

什么是线程&#xff1f; 1、线程是操作系统能够进⾏运算调度的最⼩单位&#xff0c;它被包含在进程之中&#xff0c;是进程中的实际运作单位&#xff0c;可以使⽤多线程对 进⾏运算提速。 ⽐如&#xff0c;如果⼀个线程完成⼀个任务要100毫秒&#xff0c;那么⽤⼗个线程完成改…...

【数据结构】—— 线索二叉树

引入 我们现在提倡节约型杜会&#xff0c; 一切都应该节约为本。对待我们的程序当然也不例外&#xff0c;能不浪费的时间或空间&#xff0c;都应该考虑节省。我们再观察团下图的二叉树&#xff08;链式存储结构)&#xff0c;会发现指针域并不是都充分的利用了&#xff0c;有许…...

uni-app 发布媒介功能(自由选择媒介类型的内容) 设计

1.首先明确需求 我想做一个可以选择媒介的内容&#xff0c;来进行发布媒介的功能 &#xff08;媒介包含&#xff1a;图片、文本、视频&#xff09; 2.原型设计 发布-编辑界面 通过点击下方的加号&#xff0c;可以自由选择添加的媒介类型 但是因为预览中无法看到视频的效果&…...

How to update the content of one column in Mysql

How to update the content of one column in Mysql by another column name? UPDATE egg.eggs_record SET sold 2024-11-21 WHERE id 3 OR id 4;UPDATE egg.eggs_record SET egg_name duck egg WHERE id 2;...

URL在线编码解码- 加菲工具

URL在线编码解码 打开网站 加菲工具 选择“URL编码解码” 输入需要编码/解码的内容&#xff0c;点击“编码”/“解码”按钮 编码&#xff1a; 解码&#xff1a; 复制已经编码/解码后的内容。...

Python3 爬虫 Scrapy的安装

Scrapy是基于Python的分布式爬虫框架。使用它可以非常方便地实现分布式爬虫。Scrapy高度灵活&#xff0c;能够实现功能的自由拓展&#xff0c;让爬虫可以应对各种网站情况。同时&#xff0c;Scrapy封装了爬虫的很多实现细节&#xff0c;所以可以让开发者把更多的精力放在数据的…...

QT中QString类的各种使用

大部分的QString使用可以参考:QT中QString 类的使用--获取指定字符位置、截取子字符串等_qstring 取子串-CSDN博客 补充一种QString类的分离:Qt QString切割(Split()与Mid()函数详解)_qstring split-CSDN博客 1. Trimmed和Simplified函数(去除空白) trimmed&#xff1a;去除了…...

linux 网络安全不完全笔记

一、安装Centos 二、Linux网络网络环境设置 a.配置linux与客户机相连通 b.配置linux上网 三、Yum详解 yum 的基本操作 a.使用 yum 安装新软件 yum install –y Software b.使用 yum 更新软件 yum update –y Software c.使用 yum 移除软件 yum remove –y Software d.使用 yum …...

uniapp将图片url转换成base64支持app和h5

uniapp将图片url转换成base64支持app和h5 imageToBase64支持app和h5, app内使用plus.io.resolveLocalFileSystemURL方法转换 h5内使用uni.request方法转换 // 图片转base64 export const imageToBase64 (path) > {// #ifdef APP-PLUSreturn new Promise((resolve, rejec…...

odoo17 档案管理之翻译2

翻译格式&#xff1a;#: model_terms:对象名称,arch_db:模块名.xml_id #. module: dms #: model_terms:ir.ui.view,arch_db:dms.view_dms_directory_kanban #: model_terms:ir.ui.view,arch_db:dms.view_dms_file_kanban #: model_terms:ir.ui.view,arch_db:dms.view_dms_tag_…...

风尚云网前端学习:制作一款简易的在线计算器

风尚云网前端学习&#xff1a;制作一款简易的在线计算器 简介 在前端开发的学习过程中&#xff0c;实现一个简单的在线计算器是一个常见的练习项目。它不仅能够帮助我们熟悉HTML、CSS和JavaScript的基本用法&#xff0c;还能够加深我们对事件处理和DOM操作的理解。今天&#…...

Android蓝牙架构,源文件目录/编译方式学习

Android 版本 发布时间 代号&#xff08;Codename&#xff09; Android 1.0 2008年9月23日 无 Android 1.1 2009年2月9日 Petit Four Android 1.5 2009年4月27日 Cupcake Android 1.6 2009年9月15日 Donut Android 2.0 2009年10月26日 Eclair Android 2.1 2…...

ubuntu中使用ffmpeg和nginx推流rtmp视频

最近在测试ffmpeg推流rtmp视频&#xff0c;单独安装ffmpeg是无法完成推流的&#xff0c;需要一个流媒体服务器&#xff0c;常用nginx&#xff0c;可以直接在ubuntu虚拟机里面测试一下。 测试过程不涉及编译ffmpeg和nginx&#xff0c;仅使用基本功能&#xff1a; 1 安装ffmpeg …...

strongswan测试流程

测试shell脚本文件testing/do-tests&#xff0c;测试配置文件testing/testing.conf。do-tests脚本不加参数&#xff0c;将依次执行testing/tests/目录下的所有测试用例。do-tests脚本有两个参数-v和-t&#xff0c;前者在测试中记录详细信息&#xff0c;后者在输出信息中增加时间…...

[CKS] CIS基准测试,修复kubelet和etcd不安全项

目前的所有题目为2024年10月后更新的最新题库&#xff0c;考试的k8s版本为1.31.1 ​ 专栏其他文章: [CKS] K8S Admission Set Up[CKS] CIS基准测试&#xff0c;修复kubelet和etcd不安全项[CKS] K8S NetworkPolicy Set Up[CKS] 利用Trivy对image进行扫描[CKS] 利用falco进行容器…...

Linux/Windows/OSX 上面应用程序重新启动运行。

1、Linux/OSX 上面重新运行程序&#xff0c;直接使用 execvp 函数就可以了&#xff0c;把main 函数传递来的 argv 二维数组&#xff08;命令行参数&#xff09;传进去就可以&#xff0c;注意不要在 fork 出来的子进程搞。 2、Windows 平台可以通过 CreateProcess 函数来创建新的…...

React拆分组件中的传值问题

在我们实际项目开发中&#xff0c;很多时候为为了项目后期便于维护&#xff0c;都会将相关的组件进行拆分&#xff0c;拆分过后&#xff0c;会将数据方法在父组件中进行编写&#xff0c;然后将一些逻辑拆分为组件&#xff0c;在这个过程中&#xff0c;最重要的就是数据的传递&a…...