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

上一课标准答案:

  1. 不能再写:

    JOINT_COUNT = 7;

因为:

复制代码
const int JOINT_COUNT = 6;

表示 JOINT_COUNT 是常量,创建后不允许修改。

  1. 不能。

    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 Robot

class Motor

class Controller

class Camera

class 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
└── enabled

2. 但真实"关节"不只有数据

一个真实关节除了有:

复制代码
angle
speed
enabled

它还应该能做事情。

例如:

复制代码
设置角度
停止
使能
打印状态

也就是说,一个"关节"应该同时拥有:

数据 + 功能

于是我们开始进入:

复制代码
class

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

输出:

复制代码
60

9. 为什么是 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;
}

输出:

复制代码
30

11. 新东西: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;
}

输出:

复制代码
45

20. 一层一层拆

复制代码
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_angles

23. 那么外面可能写

复制代码
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 Robot

class Motor

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

以及为什么创建对象时,它可以自动完成初始化。

相关推荐
Evand J2 小时前
【MATLAB例程】三维RRT+APF避障路径规划与到达角(AOA)定位算法|三维路径优化与定位仿真例程
算法·matlab·路径规划·代码·定位·rrt·aoa
小师兄吃牛肉2 小时前
C语言篇:宏
c语言·开发语言
郑同学的笔记2 小时前
【c++随笔28】strcmp 和 memcmp对比
开发语言·c++
随意起个昵称3 小时前
【背包dp】输出方案路径
c++·动态规划
言乐63 小时前
Python根据无法识别搜索词找出可能输入内容模型
开发语言·python·django·virtualenv·pygame
weixin_307779133 小时前
有限产能智能排产与动态重排智能体:从需求解构到技术实现
开发语言·人工智能·算法·架构
kakakahahahaha3 小时前
Windows C盘临时文件清理:%temp%、Windows Temp、Prefetch、Windows.old与hiberfil.sys处理指南
c语言·开发语言·windows
朝朝辞暮i3 小时前
C++ 第 27 课:智能指针 shared_ptr
开发语言·c++·算法
by209993 小时前
学会使用std::string类,并理解其内部是如何管理字符串的详细阐述(上)
c++·笔记·字符串·类和对象·string