C++ 第 23 课:class —— 开始真正进入面向对象

发布时间:2026/10/4 21:06:24
C++ 第 23 课:class —— 开始真正进入面向对象 上一课标准答案不能再写JOINT_COUNT 7;因为const int JOINT_COUNT 6;表示JOINT_COUNT是常量创建后不允许修改。不能。void printJoint(const Joint joint)里的joint是只读引用所以joint.angle 100.0;会报错。const Joint joint可以理解成joint引用外面的Joint对象不复制它但也不允许通过这个引用修改它。也就是只读引用。void printJoint(const Joint joint)更适合只读取、查看、打印关节信息不修改原对象。而void resetJoint(Joint joint)更适合需要直接修改原关节对象。比如joint.angle 0.0;第 23 课class—— 开始真正进入面向对象这一课很重要。因为真实机器人 C 项目里你以后会大量看到class Robotclass Motorclass Controllerclass Cameraclass SerialPort甚至 ROS2 代码里也经常会看到class MyNode先不要把“面向对象”想得特别玄学。我们先从你已经会的struct出发。1. 先复习struct我们之前写过struct Joint { double angle; double speed; bool enabled; };然后Joint joint1; joint1.angle 30.0; joint1.speed 5.0; joint1.enabled true;Joint主要是在做把相关数据打包在一起。比如Joint ├── angle ├── speed └── enabled2. 但真实“关节”不只有数据一个真实关节除了有angle speed enabled它还应该能做事情。例如设置角度 停止 使能 打印状态也就是说一个“关节”应该同时拥有数据 功能于是我们开始进入class3.class最直觉的理解你可以先把class理解成设计一种对象规定它有哪些数据以及它会做什么。例如class Joint { public: double angle; void printAngle() { std::cout angle std::endl; } };这里一个Joint里面不仅有angle还有printAngle()也就是一个函数。4.class里面可以放函数这就是和我们前面单纯struct最大的学习重点。以前struct Joint { double angle; };主要关注数据。现在class Joint { public: double angle; void printAngle() { std::cout angle std::endl; } };一个Joint同时拥有数据 angle 功能 printAngle()5. 怎么创建对象定义class Joint { public: double angle; void printAngle() { std::cout angle std::endl; } };然后Joint joint1;这和之前Joint joint1;看起来一样。这里的joint1叫对象 object你可以先理解成按照Joint这个设计图纸制造出来的一个具体东西。6.class是图纸对象是实物可以这样理解class Joint ↓ 设计图纸而Joint joint1; Joint joint2;相当于按照图纸制造joint1 joint2两个实际对象。这和机械设计非常像。你画了一个关节模组设计图然后可以生产第1个关节 第2个关节 第3个关节每个结构相同但数据可以不同。7. 对象自己的数据例如Joint joint1; Joint joint2; joint1.angle 30.0; joint2.angle 60.0;那么joint1 angle 30 joint2 angle 60它们互不影响。8. 对象自己的函数如果类里有void printAngle() { std::cout angle std::endl; }那么joint1.printAngle();输出30而joint2.printAngle();输出609. 为什么是joint1.printAngle()之前你已经见过点号joint1.angle意思joint1里面的angle现在joint1.printAngle()意思调用joint1里面的printAngle()函数。所以.依然可以理解成“这个对象里面的……”10. 完整程序#include iostream class Joint { public: double angle; void printAngle() { std::cout angle std::endl; } }; int main() { Joint joint1; joint1.angle 30.0; joint1.printAngle(); return 0; }输出3011. 新东西public现在出现public:这是面向对象里非常重要的东西。你现在先简单理解public下面的内容外部可以访问。例如class Joint { public: double angle; };所以外面可以joint1.angle 30.0;12. 如果没有public呢这里出现一个重要区别。在class里面成员默认通常是private也就是外部不能直接访问。所以class Joint { double angle; };然后Joint joint1; joint1.angle 30.0;通常会报错。因为angle是私有的。13.private是什么例如class Joint { private: double angle; };意思angle是这个对象内部的数据外部不允许直接随便改。这其实很符合真实工程思维。比如真实机械臂关节角度不应该允许任何代码随便joint.angle 999999;否则很危险。14. 那外部怎么改通过函数。例如class Joint { public: void setAngle(double new_angle) { angle new_angle; } private: double angle; };外面Joint joint1; joint1.setAngle(30.0);这样不是直接修改angle而是通过setAngle()去修改。15. 为什么这样更好因为函数里可以先检查。例如void setAngle(double new_angle) { if (new_angle -90.0 new_angle 90.0) { angle new_angle; } }这就非常像真实机械臂限位。如果外部传joint1.setAngle(45.0);合法45 在 -90 ~ 90所以修改。但如果joint1.setAngle(500.0);不合法。函数可以拒绝。16. 这叫“封装”你以后会经常听到Encapsulation封装先不用背复杂定义。你可以理解成不允许别人随便碰内部数据而是规定必须通过合适的接口操作。生活里很像汽车。你开车时不会直接用手修改发动机喷油器内部状态。你通过油门 刹车 方向盘这些接口控制汽车。class也是类似思想。17. 机器人类的雏形我们可以写class Robot { public: void start() { running true; } void stop() { running false; } private: bool running false; };那么外面Robot robot; robot.start(); robot.stop();你现在已经可以读懂创建一个 Robot 对象 robot 调用 robot 的 start() 调用 robot 的 stop()18.running为什么放private因为我们希望机器人运行状态由类自己管理。而不是外面随便robot.running true;所以private: bool running;让外部不能直接乱改。这会让程序结构更可靠。19. 一个完整机械臂关节类先做一个简单版本#include iostream class Joint { public: void setAngle(double new_angle) { if (new_angle -90.0 new_angle 90.0) { angle new_angle; } } void printAngle() { std::cout angle std::endl; } private: double angle 0.0; };然后int main() { Joint joint1; joint1.setAngle(45.0); joint1.printAngle(); return 0; }输出4520. 一层一层拆Joint joint1;创建一个Joint对象。joint1.setAngle(45.0);调用joint1的setAngle()把45传进去。函数里面if (new_angle -90.0 new_angle 90.0)检查是否合法。合法后angle new_angle;修改类内部私有变量。最后joint1.printAngle();输出内部角度。21. 类里的函数叫什么像void setAngle()放在类里面时通常叫成员函数 member function而double angle;这种放在类里的变量叫成员变量 member variable所以class Joint 成员变量 angle 成员函数 setAngle() printAngle()22. 这对真实机器人代码非常关键以后你可能看到class RobotArm { public: void connect(); void enable(); void moveJoint(int joint, double angle); void stop(); private: bool connected; bool enabled; double joint_angles[6]; };你现在已经能大致读懂。这个类叫RobotArm外部可以调用connect enable moveJoint stop内部自己保存connected enabled joint_angles23. 那么外面可能写RobotArm robot; robot.connect(); robot.enable(); robot.moveJoint(1, 30.0); robot.stop();以前你第一次看到这种代码可能会觉得robot.xxx()是什么现在你应该知道robot ↓ RobotArm 类型的对象 . ↓ 访问对象里面的成员 connect() ↓ 成员函数24.struct和class到底什么区别在 C 里它们其实非常接近。两者都可以有变量 函数 public private一个最明显的默认区别是struct 默认 public class 默认 private例如struct A { int x; };x默认可以从外面访问。但class A { int x; };x默认是 private。25. 初学阶段怎么区分使用你可以先这样理解struct更常用于主要打包一组数据。例如struct Point { double x; double y; double z; };class更常用于表达一个有状态、有行为的对象。例如class Robotclass Motorclass Camera但这不是绝对规则。26. 机器人例子一个位姿数据struct Pose { double x; double y; double z; };很自然。因为它主要是一组数据。而机械臂控制器class RobotController { public: void update(); void stop(); private: double error; };用class就很自然。因为它不仅保存数据还负责执行控制功能。27. 本课先别急着学构造函数真正的class后面还有构造函数 析构函数 this getter/setter 继承 多态 虚函数但我们不能一次全塞进来。这一课只要真正理解class 数据 操作这些数据的函数并可以通过 public/private 控制谁能访问。就够了。本课小练习第 1 题class Motor { public: double speed; };外面Motor m; m.speed 100.0;能不能这样写第 2 题class Motor { private: double speed; };外面能不能直接m.speed 100.0;为什么第 3 题下面robot.stop();你现在怎么解释第 4 题下面这个类class Joint { public: void setAngle(double angle); private: double current_angle; };哪些东西是成员函数哪些是成员变量下一课我们继续class讲一个非常核心的新概念第 24 课构造函数 Constructor你会明白为什么以后经常看到Robot robot(COM3, 115200);或者Motor motor(1);以及为什么创建对象时它可以自动完成初始化。