const,static深度总结——c++穿透式分析
前言;c++类和对象的知识点中除了几种默认函数, 比较重要的还有使用const和static修饰成员相关知识点。const在c++中特性很简单。 但是在使用中, 比较容易疏忽大意出现问题。 static特性也很简单, 但是比起const来要直接的多。 在使用中只要熟练语法以及底层原理。就不容易出错。
本节内容主要是对其进行详细的解析。相信本节内容可以让你对这两种语法有一个更深层次的认识。(注:如果想要进阶const的使用 以及 对类和对象的认识, 建议自己实现vector的stl。 list也可以, 但是list的stl的迭代器比较复杂, 需要对类和对象有一定的理解。)
const
在讨论const修饰类的成员之前。 我们先需要知道const的用法。
c++的const 与c语言const的区别
c++中的const比c语言中的const更加严格。在c语言中, 我们使用const定义一个常量后, 这个常量并不是真正意义上的常量,它还保存在栈区。 我们如果定义一个指向这个空间的指针。 那么我们还是可以对这块空间进行修改的。
但是在c++中。 如果我们使用const定义了一个常量。 那么我们如果再使用一个指针变量保存这块内存的地址。 会报错。编译不通过。 这是因为使用const修饰的变量相当于放在了常量区。(这里是相当于放在了常量区。事实上,当我们进行源代码编译的时候, 变量被编译成对应的常量, 这个常量保存在哪个区, 取决于你在哪里定义的变量。 如果是在栈区, 那就是被存储在了栈区。 所以使用const修饰变量不会改变该数据存储的位置。这个位置是在编译时期就决定的, 不是在运行时期决定的。)我们想要访问这块空间只能通过常量指针来进行访问(只读)。
const的权限平移,放大, 缩小问题
在c++中, 权限只能平移或者缩小, 不能放大。 如图:
int main()
{const int a = 10;int& b = a;//不可以, const修饰a,让a成为一个常量,数据放在了常量区,只读。 int& b是一个可读可写的类型。 相当于权限放大。 int* Pa = &a;//不可以, a是一个常量,数据放在了常量区。a的内容不可被修改, 只读。 使用指针找到这块空间后,也不能修改。 但是pa是一个可读可写的类型。 相当于权限的放大。const int* pa = &a;//可以, 这里pa使用const修饰, 变成只读。 相当于权限的平移。 int c = 10;
//下面这两个都可以, c是变量, 可读可写。而d别名是只读的。 pc也是只读的。都相当于权限的缩小。 const int& d = c;const int* pc = &c;return 0
}
看这张图中的红框框, 红框框是使用const修饰的一个int类型的变量。 然后使用了一个int类型的引用b作为a的别名。
这么写是错误的。 a被const修饰, 具有常性,只读。 而b是一个不加const修饰的引用别名, 只是一个单纯的变量, 可读可写。 想一想,如果这里是对的, a本身都不可以改变自己, 那么如果通过b这个别名可以来对a进行修改, 这不就乱了吗?所以, c++设定了权限只能平移和缩小, 不能放大。
同样的, 我们看一下下面的几个示例。
1.首先, 我们来看一下红框框和绿框框, 这个对不对呢?
答案是对的, 因为a被const修饰, 具有常性。 但是pa也被const在int*前面修饰, 这里相当于指针指向的空间不可被修改, 称为常量指针(常量指针是指向常量的指针, 另一个叫做指针常量, 是不能改变指向的一个指针常量)。所以是权限的平移, 可以被编译器通过。
2.然后, 我们来看一看蓝框框和黄框框是不是对的呢?
答案是对的, c是一个int类型的变量。 而d作为c的别名, pc作为c的指针。 都是被const修饰, 都具有常性。 权限缩小。 编译器可以通过。
const 修饰类中的成员
在C++中,const关键字可以用来修饰类的成员函数。一个被const修饰的成员函数被称为常量成员函数,它不会修改类的内部状态。
常量成员函数的声明和定义格式如下:

常量成员函数可以在常对象上调用,它们也可以在非常对象上调用。但是,常量对象上只能调用常量成员函数,而非常对象上可以调用常量成员函数和非常量成员函数。因为常对象是一个只读的类型。而且类的实例化对象在调用成员函数的时候会把自己的this指针传送过去。 而常量成员函数中的const本质上是修饰的成员this指针。所以常对象在调用常量成员函数的时候, 地址给const修饰的this,是权限的平移。 可以编译通过。 但是如果常对象调用非常量成员函数, this指针是可读可写的, 属于权限的放大。编译不能通过。
const修饰成员函数, 本质上就是修饰的成员函数中的this指针。 让this指针从可读可写变为只读的,也就是常量指针(注意区别常量指针和指针常量的区别)。
const修饰返回值和修饰成员函数
const修饰返回值和const修饰成员函数是不同的。 但是我们通过是否使用const修饰成员函数来区分一个成员函数的返回值是否是const修饰的常量。 就比如迭代器的实现, stl中的迭代器一般都有如下两种类型:
iterator;//迭代器 const_iterator;//只读迭代器
iterator和const_iterator的实现其实就用到了const修饰, 来区分两种迭代器重载。
如下是list中迭代器的实现部分代码:
(只需关注const修饰成员函数来形成重载这种思想。 list迭代器的具体实现不需要关注,后续会有专门一节来实现list的stl)
///迭代器iterator begin() {return iterator(_head->_next);}iterator end() {return iterator(_head);}///只读迭代器。 如果没有这个const修饰, 他和上面的迭代器构不成重载const_iterator begin() const{return const_iterator(_head->_next);}const_iterator end() const{return const_iterator(_head);}
注意红框框。
const比较容易出现问题的地方
如图是vector的标准库中的size()和capacity()的模拟实现
public://………………………………public中的其他成员
size_t size() const{return _finish - _start;}size_t capacity() const{return _end_of_storage - _start;} //……………………………………public中的其他成员private:T* _start;T* _finish;T* _end_of_storage;
这两个成员函数的实现必须使用const修饰。 为什么呢?因为size()和capacity是只读的。 他们不涉及成员变量的修改。 注意, 这里很重要。 也有点难以理解。
我们说如果一个对象是常量。 那么这个常量对象只能调用const修饰的成员函数, 这里没问题吧。
然后, 假如, size()和capacity()没有被const修饰, 那么假如我们想计算常量对象的大小时, 是不是就无法调用这两个函数。 所以这显然是不对的。而且, 这个常量对象, 我们是不是一定不会去修改它?所以也就不需要调用那些涉及修改数值的函数。 那么, 那些涉及修改数值的函数, 就不需要使用const修饰。 因为我们不会让const对象去调用他们。
但是, 如果一些不涉及修改数值的函数, 我们在使用const对象时, 是不是可能去调用这种不修改数值的函数。 这些函数如果没有使用const修饰的话。 const对象就调不动他们。 这不符合我们的需求。所以我们必须给不修改数值的成员函数加const修饰。
由以上分析, 我在这里总结一个结论:设计修改数值的成员函数, 按照需要看是否加const修饰成员函数。 不涉及修改数值的成员函数, 一定要加const修饰成员函数。
这个结论正在随着我代码量的提高逐渐深刻。 当涉及容器的套娃时,可能会出现例外。 但是本人认为可以加深对于成员函数, 成员变量之间关系的理解。
static
static在c++中的作用
static在c++用和在c语言中的应用场景类似。 都是用来修饰变量或者函数。 这里的变量或者函数包括类的成员变量和类的成员函数。
在全局作用域修饰变量或者函数
static在全局作用域修饰变量或者函数时, 这个变量或者函数属于整个源文件。 但是不属于项目中的其他源文件。 其他源文件无法调用static在全局修饰的成员或者函数。


在局部修饰变量或者函数
在局部修饰变量的时候, static修饰的变量生命周期变长,局部作用域销毁后,这个变量不会销毁。 但是使用的范围不变。 这个变量仍然只能在局部使用。也就是说, static修饰的成员的作用域是当前作用域, 但是生命周期变成了整个程序的生命周期。 它在程序运行时创建, 在程序结束时销毁。
static修饰类中成员
以上都是static修饰非类中的成员。
现在来看static修饰类中的成员。
static修饰成员变量
static修饰成员变量的性质
static修饰的成员变量不是属于对象的。 是属于整个类的。 它同样符合上面的性质:作用域属于当前作用域,也就是类域。 生命周期是整个程序的周期。
static成员变量与普通成员变量的区别
static成员变量会在程序开始运行时就被创建出来。 而一般的成员变量是在对象实例化的时候被定义的。 所以成员变量可以属于一个对象, 但是static修饰的成员变量只能属于整个类域。
同时, 一般的成员函数是无法访问static修饰的成员变量的。 为什么?很简单。 这里涉及到了成员函数为什么可以访问成员变量的知识点。
看这一串代码。
public://………………………………public中的其他成员void operator=(const vector<T>& v) {T* tmp = new T[v.size()];for (size_t i = 0; i < v.size(); i++) {tmp[i] = v[i];}_start = tmp;_finish = _start + (v._finish - v._start);_end_of_storage = _start + v.capacity();}//…………………………public中的其他成员private:T* _start;T* _finish;T* _end_of_storage;
看绿框框和红框框。 绿框框中的_finish是调用成员函数的对象的成员变量。 它是this指针找到的。这里this指针隐藏了, 其实应该本质是this->_finish, 或者*this._finish.
红框框中的_finish和_start是v这个对象找到的。
我们可以把this指针和v比作一个采花许可证, 然后成员函数里面比作一个花园。然后成员变量就是花园里的一朵花。 只有我们在花园中, 而且我们有采花许可证的情况下。 我们才可以采到一朵花。
这里同样的也是这么一个问题。 只有我们在成员函数中, 或者说是类域中。 并且我们有this指针或者直接有一个有一个对象。 我们才可以访问thiis指针指向的变量或者对象本身的变量。
但是,static不属于任何一个对象。 没有任何一个对象有他的指针。 他就无法被对象访问到。 即使这个对象到了花园。
那么, 有什么方法可以访问到static成员变量呢?
static修饰成员函数
static修饰的成员函数可以用来访问static修饰的成员变量。 它是专门用来访问成员变量的。
但是,static修饰的成员函数只能访问它的参数、类的静态数据成员和全局变量,而不能访问非静态数据成员。 所以, static也可以用来限制某个函数。
具体看一下实例:
class AA
{public:AA(){}static void SFunc() {cout << count1 << endl;}private:static int count1;
};int AA::count1 = 1;int main()
{AA().SFunc();return 0;
}
图中红框框是我们定义的一个静态成员。然后, static修饰的成员变量要在类外面初始化。 这里蓝框框将它在外面初始化。
绿框框是我们通过静态成员函数访问count1成员。

以上, 就是本节全部内容。
相关文章:
const,static深度总结——c++穿透式分析
前言;c类和对象的知识点中除了几种默认函数, 比较重要的还有使用const和static修饰成员相关知识点。const在c中特性很简单。 但是在使用中, 比较容易疏忽大意出现问题。 static特性也很简单, 但是比起const来要直接的多。 在使用中…...
快速搭建一个一元二次方程flask应用
新建flask_service目录、templates子目录 flask_service —— app.py —— templates —— —— index.html app.py from flask import Flask, request, jsonify, render_template import random import matplotlib.pyplot as plt from io import BytesIO import base64app F…...
O2OA红头文件流转与O2OA版式公文编辑器基本使用
O2OA开发平台在流程管理中,提供了符合国家党政机关公文格式标准(GB/T 9704—2012)的公文编辑组件,可以让用户在包含公文管理的项目实施过程中,轻松地实现标准化公文格式的在线编辑、痕迹保留、手写签批等功能。并且可以…...
软件测试:C++ Google Test单元测试框架GTest
目录 编译和安装框架使用AssertionsGoogle TestingGoogle MockingMatchersActions 运行结果 最近在写项目的时候,学到了许多关于软件测试的知识,也不断的使用新的测试框架和测试工具,每次总是机械式的拼接其他人的代码,代码发生错…...
大数据面试题 —— HBase
目录 什么是HBase简述HBase 的数据模型HBase 的读写流程HBase 在写的过程中的region的split的时机HBase 和 HDFS 各自的使用场景HBase 的存储结构HBase 中的热现象(数据倾斜)是怎么产生的,以及解决办法有哪些HBase rowkey的设计原则HBase 的列…...
SCI一区 | Matlab实现GWO-TCN-BiGRU-Attention灰狼算法优化时间卷积双向门控循环单元融合注意力机制多变量时间序列预测
SCI一区 | Matlab实现GWO-TCN-BiGRU-Attention灰狼算法优化时间卷积双向门控循环单元融合注意力机制多变量时间序列预测 目录 SCI一区 | Matlab实现GWO-TCN-BiGRU-Attention灰狼算法优化时间卷积双向门控循环单元融合注意力机制多变量时间序列预测预测效果基本介绍模型描述程序…...
SpringMVC的执行原理
SpringMVC的执行原理可以简单地概括为以下几个步骤: 客户端发送请求:客户端(一般是浏览器)发送HTTP请求到服务器,请求特定的URL资源。 前端控制器(DispatcherServlet)接收请求:在Sp…...
Qt + HTTP 线程交互类封装
介绍 QT的HTTP模块封装的交互类,线程运行。使用时添加自己的业务逻辑即可 代码 头文件 /*** file httpcontroller.h* brief 云台相机的协议交互类* author xintong-zhou* date 2024-03-13*/#ifndef HTTPCONTROLLER_H #define HTTPCONTROLLER_H#include <QNet…...
GitHub Copilot+ESP开发实战-串口
上篇文章讲了GitHub Copilot在应用中可能遇到的问题,接下来小启就简单介绍下GitHub Copilot在ESP32开发中C语言实现串口功能,感兴趣的可以看看。 一、向Copilot提问: 1. ESP32用C语言实现串口初始化; 2.配置uart为1,…...
C# 使用ffmpeg将图片保存为mp4视频
使用 FFmpeg 这个强大的多媒体处理工具,可以轻松地将一系列图片转换为一个 MP4 视频文件。以下是一个基本的命令行示例来完成这个任务: ffmpeg -framerate 25 -i image-%03d.jpg -c:v libx264 -r 30 -pix_fmt yuv420p output.mp4 命令参数说明…...
Java安全技术及代码审计技巧
概述 Java安全编码和代码审计是确保Java应用程序安全性的重要环节。本文旨在介绍Java中常见的Web漏洞、安全编码示例以及一些常见漏洞函数,并提供一个自动化查找危险函数的Python脚本。 1. XML外部实体 (XXE) 漏洞 介绍 XML文档结构包括XML声明、DTD文档类型定义&…...
C# 使用OpenCvSharp4将Bitmap合成为MP4视频的环境
环境安装步骤: 在VS中选中项目或者解决方案,鼠标右键,选择“管理Nuget包”,在浏览窗口中搜索OpenCVSharp4 1.搜索OpenCvSharp4,选择4.8.0版本,点击安装 2.搜索OpenCvSharp4.runtime.win,选择4.8.0版本,点…...
[游戏开发][Unity] 导出Xcode工程,完成调试与发布
Unity导出Xcode工程(模拟器版本与真机调试) [游戏开发][Unity] 打包Xcode工程模拟器真机调试_unity5 打包xcod-CSDN博客 Unity导出发布版本Xcode工程,上传app到官网,正式发布或创建TestFlight Xcode发布AppStore与TestFlight全流程_xcode 上传到testfit-…...
JSONP 实现跨域请求案例
后端使用 express 搭建,案例代码如下: const express require(express)const app express() const PORT 3000app.get(/data, (req, res) > {const jsonData {name: Alan,age: 666,city: GD}const callback req.query.callback // 获取前端中的回…...
2024年智慧城市、人文发展与区域经济国际会议(ICSCCDRE 2024)
2024年智慧城市、人文发展与区域经济国际会议(ICSCCDRE 2024) 2024 International Conference on Smart Cities, Cultural Development and Regional Economy 会议简介: 城市经济人文发展是一个综合性的过程,它关注城市在经济、…...
目标检测——PP-YOLO算法解读
PP-YOLO系列,均是基于百度自研PaddlePaddle深度学习框架发布的算法,2020年基于YOLOv3改进发布PP-YOLO,2021年发布PP-YOLOv2和移动端检测算法PP-PicoDet,2022年发布PP-YOLOE和PP-YOLOE-R。由于均是一个系列,所以放一起解…...
多特征变量序列预测(11) 基于Pytorch的TCN-GRU预测模型
往期精彩内容: 时序预测:LSTM、ARIMA、Holt-Winters、SARIMA模型的分析与比较-CSDN博客 风速预测(一)数据集介绍和预处理-CSDN博客 风速预测(二)基于Pytorch的EMD-LSTM模型-CSDN博客 风速预测ÿ…...
Lvs+keepalived+nginx搭建高可用负载均衡集群
环境配置 master主机192.168.199.149,虚拟IP192.168.199.148 back备机192.168.199.150 真实服务器1 192.168.199.155 真实服务器2 192.168.199.156 关闭防火墙和selinux master配置(149) 添加虚拟IP ip addr add 192.168.199.148/24 …...
WPF —— 控件模版和数据模版
1:控件模版简介: 自定义控件模版:自己添加的样式、标签,控件模版也是属于资源的一种, 每一个控件模版都有一唯一的 key,在控件上通过template属性进行绑定 什么场景下使用自定义控件模版,当项目里面多个地方…...
如何动态修改spring中定时任务的调度策略(1)
在我们日常开发中经常会调度工具来处理一下需要定时执行的任务,比如定时导出报表数据给业务方发送邮件。你在工作中是如何这种定时调度? 如何实现调度任务 使用java技术栈的老铁来说,现成定时调度的解决方案应该有很多,总结来说…...
React hook之useRef
React useRef 详解 useRef 是 React 提供的一个 Hook,用于在函数组件中创建可变的引用对象。它在 React 开发中有多种重要用途,下面我将全面详细地介绍它的特性和用法。 基本概念 1. 创建 ref const refContainer useRef(initialValue);initialValu…...
测试markdown--肇兴
day1: 1、去程:7:04 --11:32高铁 高铁右转上售票大厅2楼,穿过候车厅下一楼,上大巴车 ¥10/人 **2、到达:**12点多到达寨子,买门票,美团/抖音:¥78人 3、中饭&a…...
Qwen3-Embedding-0.6B深度解析:多语言语义检索的轻量级利器
第一章 引言:语义表示的新时代挑战与Qwen3的破局之路 1.1 文本嵌入的核心价值与技术演进 在人工智能领域,文本嵌入技术如同连接自然语言与机器理解的“神经突触”——它将人类语言转化为计算机可计算的语义向量,支撑着搜索引擎、推荐系统、…...
关于 WASM:1. WASM 基础原理
一、WASM 简介 1.1 WebAssembly 是什么? WebAssembly(WASM) 是一种能在现代浏览器中高效运行的二进制指令格式,它不是传统的编程语言,而是一种 低级字节码格式,可由高级语言(如 C、C、Rust&am…...
Element Plus 表单(el-form)中关于正整数输入的校验规则
目录 1 单个正整数输入1.1 模板1.2 校验规则 2 两个正整数输入(联动)2.1 模板2.2 校验规则2.3 CSS 1 单个正整数输入 1.1 模板 <el-formref"formRef":model"formData":rules"formRules"label-width"150px"…...
大语言模型(LLM)中的KV缓存压缩与动态稀疏注意力机制设计
随着大语言模型(LLM)参数规模的增长,推理阶段的内存占用和计算复杂度成为核心挑战。传统注意力机制的计算复杂度随序列长度呈二次方增长,而KV缓存的内存消耗可能高达数十GB(例如Llama2-7B处理100K token时需50GB内存&a…...
C++使用 new 来创建动态数组
问题: 不能使用变量定义数组大小 原因: 这是因为数组在内存中是连续存储的,编译器需要在编译阶段就确定数组的大小,以便正确地分配内存空间。如果允许使用变量来定义数组的大小,那么编译器就无法在编译时确定数组的大…...
JS设计模式(4):观察者模式
JS设计模式(4):观察者模式 一、引入 在开发中,我们经常会遇到这样的场景:一个对象的状态变化需要自动通知其他对象,比如: 电商平台中,商品库存变化时需要通知所有订阅该商品的用户;新闻网站中࿰…...
【 java 虚拟机知识 第一篇 】
目录 1.内存模型 1.1.JVM内存模型的介绍 1.2.堆和栈的区别 1.3.栈的存储细节 1.4.堆的部分 1.5.程序计数器的作用 1.6.方法区的内容 1.7.字符串池 1.8.引用类型 1.9.内存泄漏与内存溢出 1.10.会出现内存溢出的结构 1.内存模型 1.1.JVM内存模型的介绍 内存模型主要分…...
node.js的初步学习
那什么是node.js呢? 和JavaScript又是什么关系呢? node.js 提供了 JavaScript的运行环境。当JavaScript作为后端开发语言来说, 需要在node.js的环境上进行当JavaScript作为前端开发语言来说,需要在浏览器的环境上进行 Node.js 可…...




