☰
C++ 第 22 课:const —— 不允许随便修改的数据
2026/10/4 20:09:43 网站建设 项目流程

上一课标准答案:

  1. m.speed = 100.0
  2. Joint是我们自己通过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.0

C++ 不会阻止你。

但问题是:

圆周率本来就不应该随便改。

这时候可以使用:

const

2. 第一个const

写:

const double PI = 3.14159;

可以理解成:

创建一个double数据PI,但以后不允许修改它。

所以:

PI = 5.0;

会报错。

因为你已经告诉 C++:

PI是只读的。


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. 再加上const

const 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::vector<double>& data)

或者:

void printJoint(const Joint& joint)

因为这些对象可能比一个普通double大得多。

所以:

不复制 + 不修改

是非常常见的工程需求。


20. 你以后会大量见到这种函数

例如:

void printAngles(const std::vector<double>& angles)

拆开:

std::vector<double> ↓ 一个 double vector & ↓ 引用,不复制 const ↓ 只读,不能修改

整句:

函数接收一个只读的double vector引用。


21. 一个机器人轨迹例子

假设:

std::vector<double> trajectory = { 10.0, 20.0, 30.0 };

函数:

void printTrajectory(const std::vector<double>& trajectory) { for (int i = 0; i < trajectory.size(); i++) { std::cout << trajectory[i] << std::endl; } }

它只负责看数据、打印数据。

所以很适合:

const std::vector<double>&

因为我们根本不需要改它。


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();

到底是什么。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询