C++ 第 25 课:getter / setter + this
上一课标准答案:
- 正确答案是 B
Motor();
因为构造函数:
- 名字必须和类名一样
- 前面没有
void、int、double等返回类型
所以:
void Motor();
不是正确的构造函数写法。
Motor motor(3);
会把:
motor_id = 3
传入构造函数:
Motor(int motor_id)
: id(motor_id)
{
}
所以最终:
id = 3
- 构造函数适合初始化,因为它会在:
对象创建时自动执行
这样可以保证一个对象“刚出生”时,就拥有合理的数据,而不是创建后还要依赖程序员记得逐项设置。
Robot robot("COM3", 115200);
可以解释成:
创建一个
Robot类型的对象robot,并在创建时把"COM3"和115200传给Robot的构造函数,用来初始化这个机器人对象。
比如可能分别表示:
"COM3" → 串口
115200 → 波特率
第 25 课:getter / setter 与 this
这一课解决一个非常实际的问题:
如果类里面的数据设成
private,外面不能直接访问,那我要怎么读取和修改?
例如:
class Joint
{
private:
double angle;
};
外面不能:
Joint joint1;
joint1.angle = 30.0; // 不允许
因为:
angle
是 private。
所以我们通常给它提供专门的“入口”。
1. setter:专门负责修改
例如:
class Joint
{
public:
void setAngle(double new_angle)
{
angle = new_angle;
}
private:
double angle;
};
这里:
setAngle()
就是一个典型的:
setter
可以理解成:
负责设置数据的函数。
于是外面可以:
Joint joint1;
joint1.setAngle(30.0);
而不是直接:
joint1.angle = 30.0;
2. getter:专门负责读取
如果想知道当前角度,可以写:
class Joint
{
public:
double getAngle()
{
return angle;
}
private:
double angle;
};
然后:
double current = joint1.getAngle();
意思:
调用
joint1的getAngle(),把当前角度返回出来。
所以:
setter
↓
写数据
getter
↓
读数据
3. 为什么不直接把成员变量 public?
你可能会想:
那我直接:
public:
double angle;
不就完了?
确实可以。
但这样外部可以随便:
joint.angle = 999999;
甚至:
joint.angle = -123456;
没有任何保护。
但用 setter:
void setAngle(double new_angle)
{
if (new_angle >= -90.0 &&
new_angle <= 90.0)
{
angle = new_angle;
}
}
就可以做限位检查。
这就是封装的价值。
4. 一个机械臂例子
class Joint
{
public:
void setAngle(double new_angle)
{
if (new_angle >= -90.0 &&
new_angle <= 90.0)
{
angle = new_angle;
}
}
double getAngle()
{
return angle;
}
private:
double angle = 0.0;
};
使用:
Joint joint1;
joint1.setAngle(45.0);
double angle = joint1.getAngle();
最后:
angle = 45.0
5. 现在来看 this
你以后经常会看到:
void setAngle(double angle)
{
this->angle = angle;
}
第一次看可能很怪:
this->
到底是什么?
我们慢慢拆。
6. 先制造一个名字冲突
假设类里面有成员变量:
double angle;
然后函数参数也叫:
double angle
于是:
void setAngle(double angle)
{
angle = angle;
}
现在问题来了:
左边
angle和右边angle到底是谁?
这句话实际上非常糟糕。
因为函数参数:
angle
会遮蔽类里的成员变量 angle。
7. 这时 this 就出现了
可以写:
void setAngle(double angle)
{
this->angle = angle;
}
其中右边:
angle
表示:
函数参数
angle
左边:
this->angle
表示:
当前这个对象里面的成员变量
angle
所以整句话:
this->angle = angle;
就是:
把传进来的
angle,存到当前对象自己的angle成员里。
8. this 到底是什么?
你已经学过指针。
所以现在可以稍微正式一点:
this是一个指针,指向当前正在调用成员函数的那个对象。
例如:
Joint joint1;
joint1.setAngle(30.0);
进入 setAngle() 时:
this
大致可以理解成:
指向
joint1
所以:
this->angle
就是:
joint1里面的angle
9. 再创建第二个对象
Joint joint1;
Joint joint2;
joint1.setAngle(30.0);
joint2.setAngle(60.0);
第一次调用:
joint1.setAngle(30.0);
此时:
this → joint1
所以:
this->angle = 30.0;
修改的是 joint1.angle。
第二次:
joint2.setAngle(60.0);
此时:
this → joint2
所以修改的是 joint2 自己的数据。
10. -> 是什么?
你已经学过指针:
Joint* p;
如果 p 指向一个对象,访问成员时通常可以写:
p->angle
所以:
this->angle
之所以用:
->
是因为:
this本身是指针。
你可以先记:
对象访问成员:
object.member
指针访问对象成员:
pointer->member
例如:
Joint joint;
joint.setAngle(30);
而如果:
Joint* p = &joint;
就可以:
p->setAngle(30);
这个我们后面还会专门复习。
11. 那为什么以前可以直接写 angle?
例如:
void setAngle(double new_angle)
{
angle = new_angle;
}
这里没有名字冲突,所以 C++ 知道:
angle
指的是成员变量。
因此实际上可以粗略理解成:
this->angle = new_angle;
所以这两个在这里效果相同:
angle = new_angle;
和:
this->angle = new_angle;
12. 为什么很多程序员喜欢参数和成员同名?
例如:
class Motor
{
public:
void setSpeed(double speed)
{
this->speed = speed;
}
private:
double speed;
};
这样名字非常自然:
成员变量:speed
参数:speed
然后用:
this->speed
明确表示:
当前对象自己的 speed。
13. 构造函数里也会大量看到 this
例如:
class Motor
{
public:
Motor(int id)
{
this->id = id;
}
private:
int id;
};
这里:
this->id
是成员变量。
右边:
id
是构造函数参数。
所以:
this->id = id;
就是:
把传进来的 id 存进对象自己的 id。
不过现代 C++ 更常用初始化列表:
Motor(int id)
: id(id)
{
}
你已经学过这种写法了。
14. 现在看 getter 的另一个常见写法
你以后经常看到:
double getAngle() const
{
return angle;
}
注意:
const
这次跑到:
()
后面去了。
这是什么意思?
15. 成员函数后面的 const
double getAngle() const
表示:
这个成员函数承诺不会修改当前对象的数据。
所以:
double getAngle() const
{
return angle;
}
只是读取:
angle
很合理。
16. 如果它偷偷修改呢?
例如:
double getAngle() const
{
angle = 100.0;
return angle;
}
通常会报错。
因为你已经承诺:
getAngle() const
不会修改对象。
17. 为什么 getter 特别喜欢加 const
因为 getter 的职责通常是:
查看数据,而不是修改数据。
所以:
double getAngle() const
比:
double getAngle()
更明确。
它告诉别人:
你可以放心调用,我只是读,不会乱改对象状态。
18. 注意两个 const 的位置
你已经学过:
void printJoint(const Joint& joint)
这里 const 修饰的是:
参数
joint
表示不能通过这个引用修改对象。
现在又学:
double getAngle() const
这里的 const 是成员函数限定:
这个函数不会修改当前对象。
虽然都叫 const,但位置不同。
19. 一个比较标准的 Joint 类
现在把之前知识串起来:
#include <iostream>
class Joint
{
public:
Joint(double angle)
: angle(angle)
{
}
void setAngle(double angle)
{
if (angle >= -90.0 &&
angle <= 90.0)
{
this->angle = angle;
}
}
double getAngle() const
{
return angle;
}
private:
double angle;
};
20. 使用它
int main()
{
Joint joint1(0.0);
joint1.setAngle(45.0);
std::cout
<< joint1.getAngle()
<< std::endl;
return 0;
}
输出:
45
21. 逐步理解
创建:
Joint joint1(0.0);
构造函数:
Joint(double angle)
: angle(angle)
{
}
初始化:
joint1.angle = 0
然后:
joint1.setAngle(45.0);
进入:
void setAngle(double angle)
参数:
angle = 45
判断合法。
然后:
this->angle = angle;
就是:
joint1 自己的 angle = 45
最后:
joint1.getAngle();
返回:
45
22. 这已经非常接近真实机器人类了
以后一个电机类可能写成:
class Motor
{
public:
Motor(int id)
: id(id),
speed(0.0),
enabled(false)
{
}
void setSpeed(double speed)
{
this->speed = speed;
}
double getSpeed() const
{
return speed;
}
void enable()
{
enabled = true;
}
void disable()
{
enabled = false;
}
private:
int id;
double speed;
bool enabled;
};
你现在已经能读懂很多了。
23. 为什么不用全部 getter / setter?
不是每个成员都必须机械地写:
getXXX
setXXX
真实工程里应该看设计需求。
比如:
setSpeed()
可能需要限幅;
而:
enable()
比:
setEnabled(true)
语义可能更清晰。
所以 getter / setter 是一种常见手段,不是必须把每个成员都套一遍。
24. 本课核心
setter
void setAngle(double angle)
{
this->angle = angle;
}
负责修改对象内部状态。
getter
double getAngle() const
{
return angle;
}
负责读取对象内部状态。
this
this
是:
指向当前对象的指针。
this->angle
表示:
当前这个对象里的
angle成员。
本课小练习
第 1 题
class Motor
{
public:
void setSpeed(double speed)
{
this->speed = speed;
}
private:
double speed;
};
这里左边:
this->speed
和右边:
speed
分别表示什么?
第 2 题
double getSpeed() const
{
return speed;
}
函数后面的:
const
是什么意思?
第 3 题
如果:
Motor m;
Motor* p = &m;
下面哪种调用是指针访问成员?
A. m.setSpeed(10)
B. p->setSpeed(10)
第 4 题
一句话解释:
robot.getState()
是什么意思。
下一课我们继续面向对象,但开始学习一个非常实用的新概念:
第 26 课:对象、指针与 ->
我们会彻底比较:
robot.stop();
Robot* p = &robot;
p->stop();
以及为什么 ROS2、OpenCV、硬件驱动和很多真实机器人源码里会出现大量:
ptr->function()
这会把你前面学过的类 + 对象 + 指针真正连接起来。
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐


所有评论(0)