当前位置: 首页 > 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;去除了…...

FlowState Lab模型架构解析:深入理解时空生成网络原理

FlowState Lab模型架构解析&#xff1a;深入理解时空生成网络原理 1. 引言&#xff1a;为什么需要时空生成网络 视频生成一直是AI领域最具挑战性的任务之一。与静态图像不同&#xff0c;视频不仅需要保持单帧质量&#xff0c;还要确保帧间连贯性和时间一致性。传统方法往往难…...

Qwen3.5-2B效果展示:对含中英混排、公式符号的PDF截图进行精准语义还原

Qwen3.5-2B效果展示&#xff1a;对含中英混排、公式符号的PDF截图进行精准语义还原 1. 模型概览 Qwen3.5-2B是通义千问团队推出的轻量化多模态基础模型&#xff0c;属于Qwen3.5系列的小参数版本&#xff08;20亿参数&#xff09;。这个模型主打低功耗、低门槛部署特性&#x…...

Qwen2.5-VL视觉定位模型支持多目标检测:一句话同时定位‘人和汽车’,效果惊艳

Qwen2.5-VL视觉定位模型支持多目标检测&#xff1a;一句话同时定位"人和汽车"&#xff0c;效果惊艳 1. 视觉定位技术的新突破 在计算机视觉领域&#xff0c;视觉定位&#xff08;Visual Grounding&#xff09;技术正经历着革命性的进步。传统的目标检测方法需要预先…...

Psins实战:从零解析SINS/GPS松组合导航中的Kalman滤波器初始化与调参

1. 初识SINS/GPS松组合导航与Kalman滤波 刚接触导航算法的朋友可能会被"SINS/GPS松组合"这个术语吓到&#xff0c;其实拆开看很简单。SINS&#xff08;捷联惯性导航系统&#xff09;就像是个不知疲倦的计步器&#xff0c;通过IMU&#xff08;惯性测量单元&#xff09…...

GLM-OCR实操手册:Web界面上传PNG/JPG/WEBP三格式兼容性验证与建议

GLM-OCR实操手册&#xff1a;Web界面上传PNG/JPG/WEBP三格式兼容性验证与建议 1. 项目概述与测试背景 GLM-OCR是一个基于先进多模态架构的OCR识别模型&#xff0c;专门为处理复杂文档而设计。它不仅能识别普通文字&#xff0c;还能准确识别表格结构和数学公式&#xff0c;在实…...

陶哲轩:AI让数学进入「工业化」时代,数学家也可以是「包工头」

来源&#xff1a;机器之心编辑&#xff1a;张倩、陈陈很多人提到数学研究&#xff0c;脑子里浮现的还是那个画面&#xff1a;一个人&#xff0c;一块白板&#xff0c;来回踱步&#xff0c;等灵感突然降临。但当今世界最伟大的数学家之一、菲尔兹奖得主陶哲轩却告诉我们&#xf…...

Kali Linux 2026.1 重磅发布,内核升至6.18

作为全球最受欢迎的渗透测试与安全审计Linux发行版,Kali Linux在2026年迎来了年度首发版本——Kali Linux 2026.1。这次更新不仅延续了每年“.1”版本的视觉刷新传统,更特别致敬BackTrack Linux 20周年,引入“BackTrack模式”,同时升级内核至6.18,并新增8款实用工具。无论…...

【esp-idf调试问题-代码为提前配置工程,配网wedsocket服务】

esp-idf调试问题-配网wedsocket服务一、提示分区表错误&#xff0c;没有配置自己的编写的分区表。menuconfig 配置分区表步骤 1&#xff1a;打开配置菜单 在项目根目录执行&#xff1a;步骤 2&#xff1a;选择分区表类型 在 Partition Table → Partition Table 中可选&#xf…...

HarmonyOS6 半年磨一剑 - RcCheckbox 实战下篇:问卷调查表单与参数使用指南

文章目录前言一、场景&#xff1a;问卷调查表单1.1 需求分析1.2 数据结构设计1.3 表单校验联动1.4 第三题&#xff1a;计数器与数量限制的配合1.5 结果页与状态重置1.6 三道题的样式差异化对比1.7 完整代码二、参数使用频率参考2.1 高频参数&#xff08;必须掌握&#xff09;2.…...

数据科学入门指南:10周掌握数据分析核心技能 [特殊字符]

数据科学入门指南&#xff1a;10周掌握数据分析核心技能 &#x1f680; 【免费下载链接】Data-Science-For-Beginners 10 Weeks, 20 Lessons, Data Science for All! 项目地址: https://gitcode.com/GitHub_Trending/da/Data-Science-For-Beginners 想要在数据驱动的时代…...