ESP32上实现面向对象的C++ OOP——面向对象的点灯
前言——什么是面向对象
面向对象(Object Oriented)是软件开发方法,一种编程范式。与之相对的面向过程,其主要差异如下:
- 面向过程就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就可以了;
- 面向对象是把构成问题事务分解成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描叙某个事物在整个解决问题的步骤中的行为。
面向对象就是高度实物抽象化、面向过程就是自顶向下的编程!
面向过程的点灯方式这里不过多提及了,代码如下,大家自行对比:
void setup() {
Serial.begin(115200);
pinMode(33,OUTPUT);
// on
digitalWrite(33, HIGH);
delay(1000);
// off
digitalWrite(33, LOW);
delay(1000);
}
void loop() {
// toggle(切换)
digitalWrite(33,!digitalRead(33));
delay(100);
}
使用的模拟器为:https://wokwi.com/
面向对象的方式——类
什么是类?
举一个最简单的例子——人类
人类有很多属性,包括身高,体重等等;人类也有很多行为,包括吃饭,走路等等
有属性,有行为,这就是类。
创建一个类
如果用面向对象的方式,首先我们得创建一个类,然后把关于LED的属性呀,一些对LED操作的行为呀全都可以放上去,如下:
class LED{
/*
* 属性:
* pin 引脚
*/
byte pin;
/*
* 行为(方法):
* on(开灯) & off(关灯) & toggle(切换)
*/
void on();
void off();
void toggle();
};
我们刚才其实是把关于LED的一切都放在了类里面,这个过程呢其实也叫做封装,类的封装。
类的实例化——对象
类的话相当于生产手册,生产蓝图,同样以人类为例,
人类有共同的属性(包括身高、体重等),共同的行为(包括吃饭,走路等)
但是每个人都不一样,比如说你身高1.5,他身高1.9,你吃饭用左手,他吃饭用右手,可以看到共同的属性(property)有着不同的值(value),这样的每一个人我们都称之为一个对象。
还是以灯为例,这里我们定义两个LED对象,分别为ledGreen、ledRed:
class LED{
/*
* 属性:
* pin 引脚
*/
byte pin;
/*
* 行为(方法):
* on(开灯) & off(关灯) & toggle(切换)
*/
void on();
void off();
void toggle();
};
// 实例化类的对象
LED ledGreen,ledRed;
调用对象的属性或方法
实例化对象之后我们来调用一下,看看会出现什么情况
详细看图,你会发现报错了,这是因为在类里你如果没有声明的话默认定义的所有属性和方法都是私人的(private),也就是外部访问不了的,这个时候你要做的是把他们公共化,也就是做公共声明(public),如下:
class LED{
// 公共声明
public:
/*
* 属性:
* pin 引脚
*/
byte pin;
/*
* 行为(方法):
* on(开灯) & off(关灯) & toggle(切换)
*/
void on();
void off();
void toggle();
};
// 实例化类的对象
LED ledGreen,ledRed;
void setup() {
Serial.begin(115200);
ledGreen.pin = 33;
pinMode(ledGreen.pin,OUTPUT);
}
void loop() {
}
同理,调用类的方法也是通过”.”的方式,不过具体编写类的函数方法的时候需要注意格式:
// 方法类型 类名::方法名
void LED::on(){
digitalWrite(pin, HIGH);
}
简单来说就是在普通函数的基础上声明一下这个函数属于哪个类,而且在类的函数中可以调用类的属性(或类的方法)
如何访问私有变量(属性)呢?
刚才也说了,如果没有声明公共(public)默认变量是私人的(private),**只能内部类(或者朋友)访问。**这时候对象想要设置变量值怎么办呢?通过类内部方法进行设置就好啦!!!
class LED{
private:
/*
* 属性:
* pin 引脚
*/
byte pin;
public:
/*
* 行为(方法):
* setPin(设置引脚) & getPin(获取引脚)
* on(开灯) & off(关灯) & toggle(切换)
*/
void setPin(byte pin_param);
byte getPin();
void on();
void off();
void toggle();
};
void LED::setPin(byte pin_param){
if ((pin_param < 40) && (pin_param >= 0)){
pin = pin_param;
} else {
pin = 2;
Serial.println("invalid pin number,use default pin 2");
}
pinMode(pin, OUTPUT);
}
byte LED::getPin(){
return pin;
}
那我直接将类里面的属性呀方法呀都设为公共的不就好了吗?**为什么还要多此一举通过公共方法的调用进行类的私有变量的赋值呢?**细心的朋友可能就发现了!!!在调用公共方法进行私有变量赋值的过程中,以setPin为例,函数内部添加了赋值判断,初始化引脚等一系类操作,并且直接操作类中的变量时不规范的,通过函数调用的方式进行变量的操作更加规范,整洁,不易出错,也可以更加灵活,更加高效!!!
ALL CODE 如下:
class LED{
private:
/*
* 属性:
* pin 引脚
*/
byte pin;
public:
/*
* 行为(方法):
* setPin(设置引脚) & getPin(获取引脚)
* on(开灯) & off(关灯) & toggle(切换)
*/
void setPin(byte pin_param);
byte getPin();
void on();
void off();
void toggle();
};
void LED::setPin(byte pin_param){
if ((pin_param < 40) && (pin_param >= 0)){
pin = pin_param;
} else {
pin = 2;
Serial.println("invalid pin number,use default pin 2");
}
pinMode(pin, OUTPUT);
}
byte LED::getPin(){
return pin;
}
// 格式:方法类型 类名::方法名
void LED::on(){
digitalWrite(pin, HIGH);
delay(1000);
}
void LED::off(){
digitalWrite(pin, LOW);
delay(1000);
}
void LED::toggle(){
digitalWrite(pin,!digitalRead(pin));
delay(100);
}
// 实例化类的对象
LED ledGreen,ledRed;
void setup() {
Serial.begin(115200);
ledRed.setPin(33);
ledRed.on();
ledRed.off();
}
void loop() {
ledRed.toggle();
}