C++ 第 22 课:const —— 不允许随便修改的数据
上一课标准答案m.speed 100.0Joint是我们自己通过struct定义出来的新类型Joint joints[6];表示创建一个长度为 6 的Joint数组也就是可以保存 6 个关节结构体。4.joints[2].angle 45.0;表示把数组中第 3 个关节的angle成员设置为45.0。注意还是那个规则joints[0] → 第1个关节 joints[1] → 第2个关节 joints[2] → 第3个关节第 22 课const—— 不允许随便修改的数据这一课非常重要。以后你看真实 C 工程代码会大量看到const尤其是const double const int const std::string const Joint先不急着背。我们从最简单的问题开始有些变量我创建以后根本不希望别人修改怎么办1. 普通变量可以修改例如double pi 3.14159; pi 5.0;这是合法的。因为pi是普通变量。最开始pi 3.14159后来pi 5.0C 不会阻止你。但问题是圆周率本来就不应该随便改。这时候可以使用const2. 第一个const写const double PI 3.14159;可以理解成创建一个double数据PI但以后不允许修改它。所以PI 5.0;会报错。因为你已经告诉 CPI是只读的。3.const怎么理解英文constant有常量、不变的意思。所以现阶段可以把const理解成这个东西不允许被修改。例如const int joint_count 6;表示joint_count是 6并且程序后面不应该再改变它。4. 为什么这很有用假设你的机械臂永远是 6 自由度。可以写const int JOINT_COUNT 6;以后for (int i 0; i JOINT_COUNT; i) { }比直接到处写6更容易理解。因为你一看JOINT_COUNT就知道这是关节数量。5. 为什么很多常量名字写成大写例如const int JOINT_COUNT 6;或者const double MAX_ANGLE 90.0;全大写并不是 C 强制要求。这是很多工程中的命名习惯一看到大写就知道这个东西可能是常量。比如const double PI 3.14159; const double MAX_SPEED 100.0; const int JOINT_COUNT 6;不过以后你也会看到不同团队采用不同命名风格。6. 机械臂限位例子例如const double MAX_ANGLE 90.0; const double MIN_ANGLE -90.0; double angle 45.0; if (angle MIN_ANGLE angle MAX_ANGLE) { std::cout Valid std::endl; }这样比if (angle -90.0 angle 90.0)更容易看懂。因为MIN_ANGLE MAX_ANGLE直接说明了这些数字的意义。7. 常量也有类型例如const int a 5;这是不允许修改的int而const double angle 30.5;是不允许修改的double所以const并不是一种新的数据类型。更准确地说它是在告诉 C对这个变量增加“不可修改”的限制。8.const和函数参数有什么关系现在进入一个非常重要的地方。假设我们有struct Joint { double angle; double speed; };然后写函数void printJoint(Joint joint) { std::cout joint.angle std::endl; }这里Joint joint是值传递。也就是说复制一份 Joint 进去。如果Joint很大这样每次调用都复制可能有点浪费。所以我们之前学过引用void printJoint(Joint joint)这就不会复制。9. 但是引用有一个风险看void printJoint(Joint joint) { joint.angle 999.0; }因为Joint joint是原对象的引用。所以函数可以直接修改外面的关节。例如Joint j; j.angle 30.0; printJoint(j);函数执行后j.angle 999但这个函数明明叫printJoint我们本意只是打印数据。根本不希望它修改。怎么办10.const Joint这时候就可以写void printJoint(const Joint joint) { std::cout joint.angle std::endl; }这句非常重要。我们一点点拆。11. 先看Joint joint你已经学过Joint joint表示joint是外部 Joint 对象的引用。没有复制。12. 再加上constconst Joint joint表示引用外面的 Joint但不允许通过这个joint去修改它。你可以理解成只读引用。这四个字非常重要。13. 所以这句怎么读void printJoint(const Joint joint)可以翻译成printJoint接收一个Joint的只读引用。它有两个优点不复制对象 不允许函数乱改对象这就是为什么真实 C 工程里非常喜欢这种写法。14. 对比三种方式第一种值传递void printJoint(Joint joint)意思复制一份。优点不会改到外面。缺点需要复制。第二种普通引用void printJoint(Joint joint)意思不复制直接引用原对象。优点高效而且可以修改。缺点函数可能改坏外部数据。第三种const 引用void printJoint(const Joint joint)意思不复制但只允许读取。这通常特别适合函数只需要看数据不需要修改数据。15. 用文件类比假设你有一份机器人参数文件。值传递像复印一份文件给别人。他改复印件不影响原件。引用像把原件直接交给别人。他可以直接涂改原件。const引用像把原件放进透明保护套只允许看不允许修改。这个类比非常好记。16. 完整例子#include iostream struct Joint { double angle; double speed; }; void printJoint(const Joint joint) { std::cout joint.angle std::endl; std::cout joint.speed std::endl; } int main() { Joint j; j.angle 30.0; j.speed 5.0; printJoint(j); return 0; }这里调用printJoint(j);不会复制完整j。函数只是通过引用查看它。但是函数里面不能写joint.angle 100;因为joint是const。17. 如果硬要修改会怎样例如void printJoint(const Joint joint) { joint.angle 100.0; }编译器会报错。因为你前面已经承诺const Joint joint是只读的。这其实是在帮你防止 Bug。18. 普通基础类型还需要const吗例如void printNumber(const int number)理论上可以。但对于int double bool char这类很小的数据复制成本很低。很多时候直接void printNumber(int number)就够了。所以你以后经常会看到void setAngle(double angle)而不是void setAngle(const double angle)19. 但string、vector、struct、class 很常见例如void printName(const std::string name)或者void processData(const std::vectordouble data)或者void printJoint(const Joint joint)因为这些对象可能比一个普通double大得多。所以不复制 不修改是非常常见的工程需求。20. 你以后会大量见到这种函数例如void printAngles(const std::vectordouble angles)拆开std::vectordouble ↓ 一个 double vector ↓ 引用不复制 const ↓ 只读不能修改整句函数接收一个只读的double vector引用。21. 一个机器人轨迹例子假设std::vectordouble trajectory { 10.0, 20.0, 30.0 };函数void printTrajectory(const std::vectordouble trajectory) { for (int i 0; i trajectory.size(); i) { std::cout trajectory[i] std::endl; } }它只负责看数据、打印数据。所以很适合const std::vectordouble因为我们根本不需要改它。22. 那如果函数就是需要修改呢那就不要加const。例如void setZero(Joint joint) { joint.angle 0.0; }因为我们的目的就是修改原来的joint所以这里必须允许修改。不能写void setZero(const Joint joint)否则joint.angle 0.0;会被禁止。23. 所以怎么选现在可以先这样判断。如果函数需要修改外部对象用Joint例如void resetJoint(Joint joint)如果函数只需要读取外部对象不需要修改优先考虑const Joint例如void printJoint(const Joint joint)如果参数只是一个简单数字int double bool通常直接值传递即可void setSpeed(double speed)24. 再看一个非常典型的机器人函数bool isJointSafe(const Joint joint) { return joint.angle -90.0 joint.angle 90.0; }这句现在你已经可以完整拆出来bool ↓ 函数最后返回 true/false isJointSafe ↓ 函数名 const Joint joint ↓ 接收一个 Joint只读引用不复制 return ... ↓ 判断关节角度是否合法这已经很像真实工程 C 代码了。25.const还能和指针结合以后你会见到const int* p以及int* const p甚至const int* const p但现在先不学。因为const 指针的位置不同含义会变化很容易一下绕晕。我们后面会专门开一课讲。26. 本课最核心的三个写法普通变量double angle 30.0;可以修改。常量const double MAX_ANGLE 90.0;不允许修改。只读引用const Joint joint不复制外部 Joint而且不允许通过这个引用修改它。本课小练习第 1 题const int JOINT_COUNT 6;后面能不能写JOINT_COUNT 7;为什么第 2 题下面函数void printJoint(const Joint joint)里面能不能写joint.angle 100.0;第 3 题一句话解释const Joint joint是什么意思。第 4 题下面两个函数分别更适合哪种场景void printJoint(const Joint joint)void resetJoint(Joint joint)下一课我们进入第 23 课class—— 从 struct 走向真正的面向对象你会开始理解为什么真实机器人程序里会出现class Robot { public: void connect(); void moveJoint(); void stop(); private: double joint_angle; };也会第一次真正理解robot.connect(); robot.stop();到底是什么。

相关新闻

OpenShell经典开始菜单配置指南:让Win10/11操作效率翻倍

OpenShell经典开始菜单配置指南:让Win10/11操作效率翻倍

如果手头那台 Windows 7 老电脑没有彻底退休,我现在大概率不会跟 OpenShell 打上交道。换到 Windows 10 后我几乎适应了一个多月,磁贴式开始菜单总让我干着急:控制面板要先敲搜索框,关机要一层层展开,常用程序被推荐内…

2026/10/4 20:10:00 阅读更多 →
S3 Mini与C3 Mini怎么选?PSRAM/USB差异解析

S3 Mini与C3 Mini怎么选?PSRAM/USB差异解析

ESP32-S3 Mini 和 C3 Mini 这两块小板子,算是我这两年经手最多的开发板之一了。体积小、Type-C 单口供电下载、引脚直接怼面包板,十几到三十块的价格区间几乎覆盖了所有量产原型验证场景。但也正因为版本太多,我几乎每周都能在群里看到同样的…

2026/10/4 20:10:00 阅读更多 →
基于STM32的仓库环境监测与远程控制系统设计

基于STM32的仓库环境监测与远程控制系统设计

1. 项目概述与需求拆解1.1 这个系统到底是干嘛的先把这个项目说透。仓库环境控制系统,核心任务就是三件事:监测、决策、执行。监测说的是温湿度、粉尘浓度这些环境参数要能实时看到;决策指的是系统要根据这些参数自动判断“现在该不该通风”“…

2026/10/4 20:10:00 阅读更多 →

最新新闻

香港条形码注册全流程解析:帮码国际详解GS1 Hong Kong申请要点与489前缀规则

香港条形码注册全流程解析:帮码国际详解GS1 Hong Kong申请要点与489前缀规则

香港条形码注册全流程解析:帮码国际详解GS1 Hong Kong申请要点与489前缀规则 【快讯】随着跨境电商与国际贸易持续升温,越来越多的企业开始关注商品条形码的合规注册问题。近日,围绕香港条形码注册流程与申请要求的咨询量显著上升&#xff0c…

2026/10/4 20:45:16 阅读更多 →
Claude Code 自主记忆系统深度解析:短期记忆 + 长期记忆的工程化落地

Claude Code 自主记忆系统深度解析:短期记忆 + 长期记忆的工程化落地

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 20:45:15 阅读更多 →
Cursor插件激活失败的根源:plugin.json契约与harness沙箱机制

Cursor插件激活失败的根源:plugin.json契约与harness沙箱机制

1. “plugins”不是功能菜单,而是Cursor生态的神经中枢很多人第一次在Cursor里点开Settings → Extensions,看到满屏“Install Plugin”按钮时,下意识觉得——这不就是VS Code的插件市场翻版吗?点几下、装几个、重启一下&#xff…

2026/10/4 20:45:14 阅读更多 →
Cursor插件加载失败根因解析:plugin.json与TypeScript SDK契约机制

Cursor插件加载失败根因解析:plugin.json与TypeScript SDK契约机制

1. “plugins”不是功能菜单,而是现代AI编程工具的神经突触你点开Cursor、Codex或Zcode的设置界面,在“Extensions”或“Plugins”标签页里翻来翻去,装了又卸、卸了又重试,最后卡在一行红色报错上:harness failed to l…

2026/10/4 20:45:14 阅读更多 →
技术博客创作中如何准备项目素材?标题、正文与关键词指南

技术博客创作中如何准备项目素材?标题、正文与关键词指南

收到您的输入了。不过这次传来的四个关键字段——项目标题、项目正文、关键词、摘要描述——都是空的,连带热搜词和网络热词也是空白,我现在手里没有任何可依据的素材,不能凭空编出一篇博文来。我的创作原则是"忠于原料,合理…

2026/10/4 20:45:12 阅读更多 →
应急取证网络层深潜:基于 tcpdump 快速定位内网异常横向横移流量

应急取证网络层深潜:基于 tcpdump 快速定位内网异常横向横移流量

应急取证网络层深潜:基于 tcpdump 快速定位内网异常横向横移流量在主机失陷与企业级应急响应中,安全团队面临的最险峻挑战,往往是在确认“某台机器已经被黑客攻陷”之后的那几个小时。攻击者绝对不会满足于困在某一台边缘的 Web 服务器或测试…

2026/10/4 20:44:02 阅读更多 →

日新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 1:00:58 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 1:00:58 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 1:00:58 阅读更多 →

周新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 1:00:58 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 1:00:58 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 1:00:58 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 11:40:45 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 9:43:54 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 20:14:29 阅读更多 →