C++面向对象编程(基础了解和应用)
管理复杂代码:有效组织,复用代码
C的语法格式总结:
- 函数声明和使用要在小括号后加;
1.1void LED_Init(void);
//声明
1.2LED_Init();
// 使用 - 函数定义要在{}内,没有;
2. 1void LED_Init(void){}
//定义 - 数据类型在定义后要加;
3. 1typedef enum{ }BitAction;
- 类也是一种数据类型所以在{}定义后要加;
4.class main{ };
- 结构体,枚举,类都加了;
Arduino头文件library
Arduino头文件:链接
位于3个不同位置存放有libraries文件夹:(1)Arduino IDE安装的文件夹(2)Arduino的核文件夹(3)项目文件夹。
C:\Program Files (x86)\Arduino\hardware\arduino\ AVR 官方核心
C:\Users\oooomy\AppData\Local\Arduino15 第三方核心
c:\Users\oooomy\Documents\Arduino\libraries 项目文件夹
建议库只安装于项目文件夹(第3种方式)中,因为Arduino IDE在自动升级过程中,Arduino(或安装IDE的文件夹)中的所有文件被删除
目录:
头文件
防止头文件重复定义
#ifndef _xxx_h_ #define _xxx_h_ ······ #endif #program once
class类
类的使用
- 定义类,编写类中成员函数,和成员变量。定义类语法格式:
1.1class Xxx{};
1.2class Xxx{}???,???;
//直接创建类的实例 - 创建类实例(对象)
- 通过类名.成员来初始化/使用方法
- 如果使用new关键字创建的指针对象,要使用类名->成员
创建类语法格式:
class main
{
private:
/* data */
public:
main(/* args */);
~main();
};
//上部分在类体中定义: 是内联函数,创建实例的时候会加载到内存
//创建实例的时候只是一个地址
//下部分是类体中声明函数,在类体外定义函数
//类名::函数名()
main::main(/* args */)
{
}
main::~main()
{
}
上部分在类体中定义: 是内联函数,创建实例的时候会加载到内存
不创建内联实例的时候只是创建一个地址,但是节省内存。
可以在类体内写成员和声明方法,类体外写方法具体的实现。(inline:内联关键字)
下部分是类体中声明函数,在类体外定义函数
类名::函数名() 作用域(”::“)
构造函数和析构函数:
构造函数名和类名一致,在类初始化时自动执行
析构函数在类销毁前调用,在函数名前加~
类中公有成员和私有成员,get和set方法
外部类访问不到私有成员:
所以需要在公有成员中使用get方法访问(无参有返回值)
在公有成员中使用set方法来设置成员变量(有参无返回值)
类中成员种类
public/protected/private
- public:无访问限制
- protected:自己类体和子类的类体中可以访问
- private:仅类体中可以访问
在私有成员中定义变量类型,在公有成员中赋值。(因为私有成员只有在类体中可以访问)
或者使用get,set方法来改变成员变量
class Device
{
private:
int _pin;
public:
Device(int p)
{
_pin=p;
pinMode(_pin,OUTPUT);
}
};
继承方式
父类\继承方式 | public | protected | private |
---|---|---|---|
public | public | protected | private |
protected | protected | protected | private |
private | 不可访问 | 不可访问 | 不可访问 |
类中函数的隐藏
子类和父类中有同名函数:
会调用子类的函数,父类的重名函数全部被隐藏,重载只有本类中重载
调用子类时,父类和子类构造函数和析构调用顺序父类构造,子类构造,子类析构,父类析构 :先入后出顺序
抽象类和纯虚函数
纯虚函数关键字:virtual
virtual void on()=0;
含有纯虚函数的类是抽象类,不能直接使用,要在继承父类的子类中完成函数的功能才能调用子类
显式调用父类带参构造函数
父类构造函数带有参数,那么子类的构造函数也要有参数并且显示调用的方式调用父类的构造函数,把参数传递过去
class Device
{
private:
int _pin;
public:
Device(int p)
{
_pin=p;
pinMode(_pin,OUTPUT);
}
};
class Led
{
public:
Led(int p):Device(p)//显示调用,将led传过来的p传递到device参数中
{
Serical.println("hello");
}
//或者下面方法
Led():Device(13)
{
}
};
Led led(10);//实际上led构造方法用不到参数,只是将参数传递到device中
类中成员变量初始化
显示调用可将成员变量初始化,也可通过下面的方法初始化(初始化成员列表)
class Device
{
private:
int _pin;
int _pin1;
public:
Device(int p,int p1):_pin(p),_pin1(p1)//多个成员变量使用逗号分隔
{
//_pin=p;
pinMode(_pin,OUTPUT);
pinMode(_pin1,OUTPUT);
}
};
新版C++类中成员变量也可赋初值
类创建实例的两种方式
Device led
Device *led1
//声明一个指针地址,不调用构造函数 并且使用->来调用成员函数
Device *led2 = new Device
//会调用构造函数
引用对象的两种方式
将led初始化的内存复制给led一份,调用析构函数的时候会调用两次,因为是复制过去的所以有两片相同的内存需要清除。
Device led;
Device led1 = led;
led.on();
析构只调用一次
Device led;
Device *led1 = &led;
led->on();
多态
静态多态和动态多态:
静态:复用函数名(改变参数),运算符等来达到重载的目的,在编译前已经确定内存位置
动态:
首先父类成员内容是小于子类的,在父类调用子类成员的时候报错,这时可以使用虚函数/纯虚函数,(接口)。让子类完成函数编写,父类就可以调用子类的成员了。父类是虚函数,子类也就成了虚函数。 这时父类的内存时动态的,动态内存。
还要考虑到动态绑定的问题,系统没有给虚函数分配固定的内存空间
动态绑定:父类创建本类型的指针,指针指向子类创建的对象–>子类动态的绑定了父类的数据类型(前提是父类是抽象类)(有一个纯虚函数就是抽象类了,一颗老鼠屎坏了一锅粥的意味)
静态变量static关键字,全局变量。也可修饰函数
静态变量只有一份(全局)内存从创建到销毁只有一份
静态变量可以使用类名::静态变量成员调用
静态函数可以使用类名::静态函数直接调用
静态成员函数只能访问静态成员变量,不能访问普通变量。