ESP32上的面向对象(1)

初识OOP

OOP (Object Oriented Programming)是面向对象编程。其具有三大特性:

  1. 封装
    隐藏对象的属性和实现细节,仅对外提供公共访问方式,将变化隔离,便于使用,提高复用性和安全性。
  2. 继承
    子类可继承其父级类中的属性和方法,并可以添加新的属性和方法或者对部分属性和方法进行重写。继承增加了代码的可重用性。
  3. 多态
    子类继承了来自父级类中的属性和方法,并对其中部分方法进行重写。于是多个子类中虽然都具有同一个方法,但是这些子类实例化的对象调用这些相同的方法后却可以获得完全不同的结果,这种性质就是多态。多态性增强了软件的灵活性。

类的定义

C++中使用关键字 class 来定义类,其基本形式如下:

1
2
3
4
5
6
7
class 类名
{
public:
//公共的行为或属性
private:
//私有的行为或属性
};

private 表示该部分内容是私密的, 不能被外部所访问或调用, 只能被本类内部访问; 而 public 表示公开的属性和方法, 外界可以直接访问或者调用。一般来说类的属性成员都应设置为private, public只留给那些被外界用来调用的函数接口, 但这并非是强制规定, 可以根据需要进行调整。const 修饰的成员数据定义以后不能被修改,这样可以保护该数据。

ESP32点灯示例

以ESP32点亮LED灯为例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
class Led
{
private:
byte _pin;
public:
void setpin(byte pin_param);
byte getpin() const;
void on() const;
void off() const;
};

void Led::setpin(byte pin_param)
{
_pin = pin_param;
pinMode(_pin, OUTPUT);
}

void Led::getpin() const
{
return _pin;
}

void Led::on() const
{
digitalWrite(_pin, HIGH);
}

void Led::off() const
{
digitalWrite(_pin, LOW);
}

Led ledGreen;

void setup()
{
ledGreen.setpin(33);
ledGreen.on();
delay(1000);
ledGreen.off();
delay(1000);
}

void loop()
{
ledGreen.on();
}

构造函数

  1. 构造函数概念
    一个类的对象被创建的时候,编译系统对象分配内存空间,并自动调用该构造函数,由构造函数完成成员的初始化工作。因此,构造函数的核心作用就是,初始化对象的数据成员。
  2. 构造函数特点
    • 名字与类名相同,可以有参数,但是不能有返回值(void也不行)。
    • 构造函数是在实例化对象时自动执行的,不需要手动调用。
    • 作用是对对象进行初始化工作,如给成员变量赋值等。
    • 如果定义类时没有写构造函数,系统会生成一个默认的无参构造函数,默认构造函数没有参数,不做任何工作。
    • 如果定义了构造函数,系统不再生成默认的无参构造函数。
    • 对象生成时构造函数自动调用,对象一旦生成,不能在其上再次执行构造函数。一个类可以有多个构造函数,为重载关系。
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      class Led()
      {
      private:
      byte _pin;
      public:
      Led(); // 构造函数
      };

      Led::Led()
      {
      _pin = 0;
      }
  3. 构造函数的重载
    在一个类中可以定义多个构造函数,以便对类对象提供不同的初始化的方法,供用户选用。这些构造函数具有相同的名字,而参数的个数或参数的类型不相同。这称为构造函数的重载。所以,在一个类中定义多个构造函数,构造函数的名称都是相同,只有构造函数的参数不同,那么,就称为构造函数的重载。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    class Led()
    {
    private:
    byte _pin;
    public:
    Led(); // 构造函数
    Led(byte pin_param); // 重载构造函数
    };

    Led::Led() // 默认构造函数
    {
    _pin = 0;
    }

    Led::Led(byte pin_param) // 重载构造函数
    {
    setpin(pin_param);
    }

    Led ledGreen(33),ledRed;

析构函数

  1. 析构函数定义
    析构函数 (destructor) 与构造函数相反,当对象结束其生命周期,如对象所在的函数已调用完毕时,系统自动执行析构函数。析构函数往往用来做“清理善后” 的工作(例如在建立对象时用new开辟了一片内存空间,delete会自动先调用析构函数后释放内存)。
  2. 析构函数特点
    • 名字与类名相同
    • 在前面需要加上”~”
    • 无参数,无返回值
    • 一个类最多只有一个析构函数
  3. 示例
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    class Led()
    {
    private:
    byte _pin;
    public:
    Led(); // 构造函数
    Led(byte pin_param); // 重载构造函数
    ~Led(); // 析构函数
    };

    Led::~Led()
    {
    // 对象的生命周期结束的时候,就会自动执行析构函数
    }