【C++】const和static的用法

目录

  • 🚀前言
  • 💻const:“只读”的守护者
    • 💯修饰普通变量
    • 💯修饰指针
    • 💯修饰函数
    • 💯修饰类成员
    • 💯修饰对象
  • 🌟static:“静态存储”与“作用域控制”
    • 💯修饰全局变量
    • 💯修饰局部变量
    • 💯修饰类成员
      • 🎯static 成员变量
      • 🎯static成员函数
  • 💧const 与 static 结合应用
    • 💯关键用法:类内静态常量的初始化
  • 🎋避坑指南
  • ☘️结尾总结

🚀前言

在这里插入图片描述

大家好!我是 EnigmaCoder

  • 本文将分别介绍const与static的用法,最后介绍两者的结合应用和常见坑点。

💻const:“只读”的守护者

const 的核心作用是限制变量/对象的“可修改性”,强制编译器检查“意外修改”,本质是给代码加“安全锁”。它的用法围绕“修饰谁”展开,不同修饰对象的含义完全不同,也是初学者最易踩坑的点。

💯修饰普通变量

  • 作用:变量初始化后不可修改,编译期会检查赋值操作。
  • 注意:必须在定义时初始化(局部/全局 const 均需)。
  • 示例:
    const int max_len = 10; // 正确:定义时初始化
    max_len = 20; // 错误:编译器直接报错,禁止修改
    

💯修饰指针

const修饰指针关键看 const* 的位置:

  • const int* pconst* 左边):限制“指针指向的内容”不可改,指针本身可以换指向。
    int a = 5, b = 10;
    const int* p = &a;
    *p = 6; // 错误:指向的内容(a的值)不能改
    p = &b;  // 正确:指针可以指向新地址(b)
    
  • int* const pconst* 右边):限制“指针本身”不可改,指向的内容可以改。
    int a = 5, b = 10;
    int* const p = &a;
    *p = 6; // 正确:指向的内容(a的值)可以改
    p = &b;  // 错误:指针不能换指向
    

💯修饰函数

  • 修饰函数参数:保证函数内部不修改参数(尤其针对引用/指针参数,避免意外篡改外部变量)。
    // 传入字符串,仅读取不修改,用 const 保护
    void printStr(const string& s) {s += "test"; // 错误:禁止修改 const 参数cout << s << endl; // 正确:仅读取
    }
    
  • 修饰函数返回值:限制返回值不可被修改(常见于返回指针/引用的场景,避免外部篡改内部数据)。
    // 返回数组首地址,禁止外部修改数组内容
    const int* getArr() {static int arr[3] = {1,2,3};return arr;
    }
    int main() {const int* p = getArr();*p = 4; // 错误:返回值是 const,禁止修改
    }
    

💯修饰类成员

  • const 成员变量:属于对象的“常量”,必须在构造函数初始化列表中初始化(不能在定义时直接赋值)。
    class Person {
    private:const int age; // const 成员变量
    public:// 正确:在初始化列表中初始化Person(int a) : age(a) {}// 错误:不能在构造函数体内赋值// Person(int a) { age = a; }
    };
    
  • const 成员函数:保证函数内部不修改任何非 mutable 成员变量,函数声明和定义都要加 const
    class Person {
    private:int age;
    public:// 声明时加 constvoid showAge() const;      //语法:返回值类型 函数名() const;
    };
    // 定义时也要加 const(位置不能错)
    void Person::showAge() const {age = 20; // 错误:const 函数禁止修改成员变量cout << age << endl; // 正确:仅读取
    }
    

💯修饰对象

const 修饰对象,本质是把对象变成 “只读对象”—— 一旦定义,这个对象的成员变量就不能被修改,能有效保证数据安全(比如防止误改关键数据)。

  • 格式很简单:在对象定义前加const,和定义const变量(比如 const int a=10)的逻辑一致。
#include <iostream>
#include <string>
using namespace std;// 定义一个学生类
class Student {
public:string name;  // 成员变量:姓名int score;    // 成员变量:成绩// 构造函数(初始化姓名和成绩)Student(string n, int s) : name(n), score(s) {}// 普通成员函数:修改成绩(可能改成员变量)void setScore(int s) {score = s;}// const 成员函数:只打印信息(不修改成员变量)void showInfo() const {cout << "姓名:" << name << ",成绩:" << score << endl;}
};
int main() {// 1. 普通对象(可以修改成员,调用任意函数)Student s1("张三", 90); s1.score = 85;          // 允许:普通对象能改成员变量s1.setScore(88);        // 允许:普通对象能调用非const函数s1.showInfo();          // 允许:普通对象也能调用const函数// 2. const对象(只读,核心限制:不能改成员,只能调const函数)const Student s2("李四", 85); // s2.score = 90;       // 错误!const对象不能直接修改成员变量// s2.setScore(92);     // 错误!const对象不能调用非const函数s2.showInfo();          // 允许!const对象只能调用const成员函数return 0;
}

遵循两个规则:

  • const对象的成员变量绝对不能修改。
  • const对象只能调用const成员函数。

🌟static:“静态存储”与“作用域控制”

static 的核心是改变变量/函数的“存储周期”或“作用域”,本质是管理“数据的生命周期”和“访问范围”,常见于“共享数据”“全局唯一”场景。

💯修饰全局变量

  • 作用:全局 static 变量的作用域仅限当前 .cpp 文件,避免不同文件中“同名全局变量”的命名冲突。
  • 对比普通全局变量:普通全局变量默认“跨文件可见”(用 extern 可引用),static 全局变量则“文件私有”。
  • 示例:
    // a.cpp
    static int global_val = 5; // 仅 a.cpp 可见// b.cpp
    extern int global_val; // 错误:无法引用 a.cpp 的 static 全局变量
    

💯修饰局部变量

  • 作用:局部 static 变量的“作用域”仍在函数内,但“存储周期”是整个程序(仅初始化一次,函数调用结束后不销毁)。
  • 典型场景:函数内的计数器、全局唯一的临时数据。
  • 示例:
    void countCall() {static int cnt = 0; // 仅初始化一次(第一次调用时)cnt++;cout << "调用次数:" << cnt << endl;
    }
    int main() {countCall(); // 输出 1countCall(); // 输出 2(cnt 未被销毁)
    }
    

💯修饰类成员

static 类成员是“所有对象共享的数据/方法”,不依赖具体对象存在。

🎯static 成员变量

  • 特点:属于整个类,所有对象共用同一内存,必须在类外单独初始化(不能在构造函数中初始化)。由于static成员变量存储在类的外部,计算类的大小时不包含在内。
  • 示例:统计类的对象创建个数
    class Student {
    private:static int total; // 声明:属于 Student 类
    public:Student() { total++; } // 创建对象时计数+1~Student() { total--; } // 销毁对象时计数-1// 必须用 static 函数访问 static 变量(见下文)static int getTotal() { return total; }
    };// 类外初始化:不加 static,需指定类名
    int Student::total = 0;int main() {Student s1, s2;cout << Student::getTotal(); // 输出 2(两个对象)
    }
    

🎯static成员函数

  • 特点:没有 this 指针(因为不依赖对象),只能访问 static 成员变量/函数,不能访问非 static 成员。
  • 调用方式:直接用“类名::函数名”调用(无需创建对象)。
  • 示例:上文 Student::getTotal(),直接通过类名调用。

💧const 与 static 结合应用

两者结合的核心场景是“类的静态常量”,即 static const(或 const static,两者在类中等价),用于定义“类级别的常量”(所有对象共用,且不可修改),既实现了数据共享又达到了数据不可被改变的目的。

💯关键用法:类内静态常量的初始化

  • C++11 及以后:static const 成员变量可在类内直接初始化(仅限字面量类型,如 int、char 等)。

  • 示例:

    class Config {
    public:// C++11+ 支持:类内直接初始化静态常量static const int MAX_NUM = 100;static const string DEFAULT_NAME; // 非字面量类型,需类外初始化
    };// 非字面量类型的 static const 成员,仍需类外初始化
    const string Config::DEFAULT_NAME = "unknown";
    
  • 注意:C++11 前,static const 成员变量必须在类外初始化,即使是字面量类型。

🎋避坑指南

  1. 坑 1:const 变量能“强制修改”?
    用指针强制转换可以修改 const 变量,但这是“未定义行为”(编译器不报错,但运行结果不可控,可能触发崩溃),绝对禁止!

    const int a = 5;
    int* p = (int*)&a; // 强制转换(危险!)
    *p = 10; // 运行时可能修改成功,但属于未定义行为
    
  2. 坑 2:static 局部变量的线程安全?

    • C++11 及以后:static 局部变量的初始化是“线程安全”的(编译器会加锁,避免多线程同时初始化)。
    • C++11 前:非线程安全,多线程同时调用可能导致重复初始化。
  3. 坑 3:类 static 成员忘记类外初始化?
    仅在类内声明 static 成员变量,未在类外初始化,会导致链接错误(编译器找不到变量的定义)。记住:static 类成员“声明在类内,定义在类外”。

☘️结尾总结

conststatic 虽基础,但用法灵活,核心记住两点:

  • const:围绕“只读”,为代码加安全锁,避免意外修改(重点分清修饰指针的两种场景、类 const 成员的初始化)。
  • static:围绕“静态存储/作用域”,管理数据生命周期(重点掌握类 static 成员的“类外初始化”和“共享特性”)。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/100454.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/100454.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

F019 vue+flask海外购商品推荐可视化分析系统一带一路【三种推荐算法】

文章结尾部分有CSDN官方提供的学长 联系方式名片 B站up&#xff1a; 麦麦大数据 关注B站&#xff0c;有好处&#xff01; 编号: F019 关键词&#xff1a;海外购 推荐系统 一带一路 python 视频 VueFlask 海外购电商大数据推荐系统源码 &#xff08;三种推荐算法 全新界面布局…

【大数据专栏】流式处理框架-Apache Fink

Apache Fink 1 前言 1.1 功能 1.2 用户 国际 国内 1.3 特点 ◆ 结合Java、Scala两种语言 ◆ 从基础到实战 ◆ 系统学习Flink的核心知识 ◆ 快速完成从入门到上手企业开发的能力提升 1.4 安排 ◆ 初识Flink ◆ 编程模型及核心概念 ◆ DataSet API编程 ◆ Data…

向内核社区提交补丁

一、背景 内核的版本一直以来一直在持续迭代&#xff0c;离不开众多开发者的贡献。有时候我们会根据项目要求基于现有的内核版本开发一些新的功能或者修复掉一些特定场下的问题&#xff0c;我们是可以将其提交给社区的。 一般提交社区有两个基本原则&#xff0c;一是提交的补…

TENGJUN-USB TYPE-C 24PIN测插双贴连接器(H14.3,4脚插板带柱):USB4.0高速传输时代的精密连接方案解析

在高速数据传输与多设备互联需求日益增长的当下&#xff0c;USB TYPE-C接口凭借其可逆插拔、高兼容性的优势成为主流&#xff0c;而TENGJUN推出的USB TYPE-C 24PIN测插双贴连接器&#xff08;规格&#xff1a;H14.3&#xff0c;4脚插板带柱&#xff09; &#xff0c;以对USB4.0…

企业级 Docker 应用:部署、仓库与安全加固

1 Docker简介及部署方法 1.1 Docker简介 Docker之父Solomon Hykes&#xff1a;Docker就好比传统的货运集装箱 Note 2008 年LXC(LinuX Contiainer)发布&#xff0c;但是没有行业标准&#xff0c;兼容性非常差 docker2013年首次发布&#xff0c;由Docker, Inc开发1.1.1 什么是do…

rust语言 (1.88) 学习笔记:客户端和服务器端同在一个项目中

同一项目下多个可执行文件&#xff0c;多个子项目参照以下&#xff1a; 一、项目目录 项目/|-- client/|-- main.rs|-- Cargo.toml|-- server/|-- main.rs|-- Cargo.toml|-- Cargo.toml二、项目公共 Cargo.toml [workspace] # 定义Rust工作区配置 members …

mac本地安装mysql

本人环境 macOs 14.5 1.下载安装mysql https://dev.mysql.com/downloads/mysql/ 配置环境变量&#xff0c;打开terminal vim ~/.bash_profile 添加MYSQL_HOME/usr/local/mysql 在PATH中添加 通过mysql --version命令查看版本 2.开启mysql 打开终端teminal,输入命令 sudo…

面试前端遇到的问题

面试官让我写一个delay函数然后这是我写的代码async function delay(){setTimeout(function() {}, 3000); }面试官就和我说不是这个&#xff0c;用promise当时就蒙了&#xff0c;什么东西&#xff0c;为什么要用promise然后问豆包说Promise 是 JavaScript 中用于处理异步操作的…

Ubuntu Desktop 22.04.5 LTS 使用默认的 VNC 远程桌面

1. 打开 VNC 打开设置 - 分享 - 远程桌面2. 配置 VNC 打开远程桌面 启用vnc 选择vnc密码访问 配置密码3. 固定密码 远程桌面的访问密码在每次开机后会刷新一次&#xff0c;可以通过以下方式固定 打开【应用程序】&#xff0d;【附件】&#xff0d;密码和加密密钥&#xff08;或…

【无线安全实验4】基于伪随机数的WPS PIN码逆向(精灵尘埃/仙尘攻击)

文章目录1 原理分析1.1 WPS连接过程1.1.1 初始阶段1.1.2 注册阶段1.2 WPS攻击原理1.2.1 在线攻击1.2.2 离线攻击1.2.2.1 Ralink模式1.2.2.2 eCos模式2 实验过程3 参考资料在2011年 Stefan Viehbck 演示过WPS的在线暴力攻击&#xff0c;由于PIN码猜测最多只需11000种组合&#x…

IDEA开发过程中经常使用到的快捷键

IntelliJ IDEA 开发 Java 时常用的快捷键列表 代码编辑与行操作快捷键功能描述Ctrl Y删除当前行。Ctrl D复制当前行到下一行。Shift Alt ↑将当前行&#xff08;或选中块&#xff09;向上移动。Shift Alt ↓将当前行&#xff08;或选中块&#xff09;向下移动。Ctrl /注…

ubuntu使用webrtc库开发一个webrtc推拉流程序

目录 一. 前言 二. 整体交互流程 三. 类实现说明 1. WebRtcClient 2. SignalPeerClient 3. WebRTCStream 4. 视频源类 5. 拉流渲染 四. 使用示例 1. 推流代码示例 2. 拉流代码示例 一. 前言 在 《ubuntu编译webrtc库》我们介绍了如何在 ubuntu 上使用 webrtc 源代码…

【Block总结】ConverseNet:神经网络中的反向卷积算子

1. 论文信息 标题:Reverse Convolution and Its Applications to Image Restoration 发布平台:arXiv 论文链接:https://arxiv.org/pdf/2508.09824 代码仓库:https://github.com/cszn/converseNet 任务领域:图像恢复(去噪、超分辨率、去模糊) 核心贡献:提出了一种新的反…

优化浏览体验:4个设置让Google Chrome更好用!

想要更流畅、更快速的浏览体验吗&#xff1f;本文章将向大家展示Google Chrome中你应该立即更改的4个重要设置&#xff0c;设置调整将帮助您提升性能&#xff0c;让你的浏览更高效。1、打开浏览器&#xff0c;在地址栏输入“chrome://flags"确定&#xff0c;在搜索标志中输…

【Git】一篇文章带你入门Git

1. 初识 Git 1.1 Git 是什么&#xff1f; Git 是一个开源的分布式版本控制系统&#xff0c;用于高效地跟踪和管理项目代码的变更历史&#xff08;不仅仅是代码&#xff0c;还有其它格式也是可以的~&#xff09; 1.2 为什么要有 Git 在学习或者是工作的时候&#xff0c;比如…

8 基于机器学习进行遥感影像的地物分类-以随机森林为例

目录 1 读取数据 2 数据预处理 3 模型训练 4 精度分析 5 模型预测 1 读取数据 1.右键数据所在文件夹,用pycharm打开为项目 2.在settings中设置python环境为先前配置的带GDAL和sklearn的环境 3.新建一个文件夹命名为code来存放代码,在code文件夹中新建一个rfc.py

极简版 Nginx 反向代理实验步骤

以下是最核心的反向代理实现步骤&#xff0c;专注于 “客户端→Nginx 代理→后端服务” 的基础转发功能&#xff1a;一、准备 2 台服务器角色IP 示例需安装软件代理服务器192.168.1.10Nginx后端服务器192.168.1.11Nginx/Apache二、后端服务器配置&#xff08;192.168.1.11&…

Windsurf 插件正式登陆 JetBrains IDE:让 AI 直接在你的 IDE 里“打工”

那天你说,我们可以永远在一起——成了我听到的最高兴的,而后知后觉的谎言。 而今天,AI 说:“我可以帮你写完这段代码。” —— 这才是真正的“永远在一起”。 最近,AI 编程工具赛道迎来一场“潜行式革命”:Windsurf Wave 7 正式发布 JetBrains IDE 插件版本,彻底打破“A…

188. Java 异常 - Java 异常处理规范

文章目录188. Java 异常 - Java 异常处理规范&#x1f4dc; 什么是“Catch or Specify Requirement”&#xff1f;✅ 两种满足方式方法一&#xff1a;使用 try-catch 捕获异常方法二&#xff1a;使用 throws 声明异常❌ 不遵守规则会怎样&#xff1f;&#x1f4a1; 哪些异常必须…

泛型通配符 T、E、K、V、?

在Java后端开发中&#xff0c;你一定在写集合类或工具类时&#xff0c;见过 T、E、K、V、? 这样的泛型通配符。但你是否有过以下疑惑&#xff1a; T、E、K、V 到底有什么区别&#xff1f;为什么大家都用这些字母&#xff1f;List<?> 和 List 有什么不同&#xff1f;什么…