C语言实现面向对象编程
version : v1.0 「2022.8.31」 最后补充
author: Y.Z.T.
摘要: 简单记录用C语言实现面向对象编程
(自留记录用🌟 , 写的比较混乱)
0️⃣ 前言
在设计复杂系统的时候,面向对象的程序设计具有 拓展性好、维护性好、复用性好等优点。
面向对象编程,它是一种设计方法、设计思想 ,具备三个基本特征:
因为平时进行嵌入式开发主要还是应用C语言进行开发,所以通过C语言来实现面向对象
1️⃣ 封装
一个类中主要包含两种基本成员: 属性和方法
在C语言中:
- 一个结构体就相当于一个类,结构体实例化之后就是一个对象。
- 结构体中的成员类似类中的成员;
- 结构体中的函数指针类似类方法。
![image-20220829085728552](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASwAAAEsCAMAAABOo35HAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAC9UExURVlZWdPT07KysmRkZIWFhfT09JmZmWZmZm9vb39/fxkZGUxMTDMzM3p6epCQkKamppubm729venp6cjIyN7e3tbW1s/Pz8LCwnx8fLS0tFZWVoiIiI+Pj6GhoeTk5Glpabu7u93d3evr66CgoJSUlKqqqsnJyeDg4Hd3d8PDw+Xl5bi4uNHR0dvb26Ojo6urq+fn51hYWDg4OCgoKHBwcK2traenp0FBQe7u7vHx8U5OTre3t8zMzHV1df///7GrnpQAAAA/dFJOU///////////////////////////////////////////////////////////////////////////////////AI4mfBcAAAUGSURBVHja7NoJb6M4GMZxY0NCD64kve/pMZ2d3Z297+X7f6zFNmBAMUXa6URl/q9UJSWPUPzrizFWRUlNLgEBWGCBBRZYYEEAFlhggQUWWBCABRZYYIEFFgRggQUWWGCBBQFYYIEFFlhgQQAWWGCBBRZYEIAFFlhggQUWBGCBBRZYYIEFAVhggQUWWGBBABZYYIEFFlgQgAUWWGCBBRYEYIEFFlhggQUBWGCBBRZYYEEAFlhggQUWWBCABRZYYIEFFgRggQUWWGCBBQFYYIEFFlhgQQAWWGCBBRZYEIAFFlhggQUWBGCBBRZYn6cCIcRXgvX/h9qcIVBqDdbEM8RCxGCB9QqXYRwHYDHBgwXWl8eKZKiESHI3Ba1kWs3fKixcaJUl1YyeBm7Ocq+yLItUiVBGnXxenSHJolIKEcwHq6ikbOX1YGVzQCTN8LPmSLreghUl9sN4Uw7yajMrLC0TZ1ImzqY6FEop0+pIaEN5HaoOxVuwEqFyc4I46uSlzOLqgxlh6UaR9l3VYWl9Fdoxb1Q90KJtu41pwwFW/WHhTtW8i7TafLCqRsk6bsGw63L9qurXRmuIlbT9lDQnlXU+nBFW1Q2qnZbDprWa2tjR90LZFqx1/+Td/HpGWLlrLDvIwTcx6dQ1Vrntbig68cDms3JwbA5Y1azs1ger6sNV/bbIw1jU81MvNAGrl58RVn8ozW+btF08iGFoAlYvP3csfVur1gJBEIA1uBmue5dhZDOyO2epbmgCVi8/I6x0MMHH9pjsTfBhNzQBq5uPZoQlB0uH3DZG4EZqQ26fL3sZq5uf09Ih6qw3i/pm6BZO0qZX7rrUS68Xsbr5ZE4rePMk08pk9aUZugfqppvs6AM1Acvlo/StP+6EbW06z8hJqxbYp2BZPQUnFsLsKuhQdaHqn5ewbF7KXIn0jWO5MqOQ7RaNLPtbNMmmhimj0GUmYLl8Gs0Lq4wyPbTu1l2QKqHSouzs3OlDIslW5SQsnY/NXmFplyNvEuuLV/Tau9BzwiraDUSwXmysztYWWNtL1psXeumgIrDGaqXvBfUuvtqUYI3V2t1wk1e2msFluJJm6zDJXv/fIfjPP7DAAgsssCiwwAILLLDAosACCyywwAKLAgsssMACC6zt9fDz/v75tyOB+98PD2+ORgKffjw4OP1uJPDxl+Xy8v1I4MPF3t7VNyOB4/vF4uzdzrG+39f1kz/w66Guv/yBvw90KX/gZKkr8Qf+2dOV+gNHC12/7RxrabD2/a31bLAO/a11YbAO/K21MFhLf2s9Gqw9f2vdGqzFu11jnVusE2/gxmI9eQOnFuvYG7i0WH7uK4t15w2cWazrXWP9a7H8f/bQYvm/6IPF+sF/pVssf19Ii/WH/0K2WH/uGuvEWC39gSdj9Twy+Rqri5EZx1gt/IE7Y/XoD1wbq9vd3w1PlufnD2OBp+ebm/uxwPHF6emnscDR4vLy41jg7vHq6sNY4Pr27OyYdRaLUrDAAosCCyywwAILLAossMACCyywKLDAAgsssMCiwAILLLDAAosCCyywwAILLAossMACCyywKLDAAgsssMCiwAILLLDAAosCCyywwAILLAossMACCyywKLDAAgsssMCiwAILLLDAAosCCyywwAILLAossMACCyywKLDAAgsssMCiwAILLLDAAosCCyywwAILLAossMACCyywKLDAAgsssL6u+k+AAQCR9eHtLKvLfwAAAABJRU5ErkJggg==)
【良好的封装可以有效减少耦合性,封装内部实现可以自由修改,对系统的其它部分没有影响】
1.1内存模型:
在栈区中储存着Gr
对象 , 在程序代码区 储存着Gr
对象的实现方法
2️⃣ 继承
- 在面向对象编程中,封装和继承其实是不分开的 ; 封装就是为了更好地继承。
- 我们将几个类共同的一些属性和方法抽取出来,封装成一个类
- 通过继承最大化地实现代码复用。
- 通过继承,子类可以直接使用父类中的属性和方法。
2.1 继承方法
- 可以通过内嵌结构体或结构体指针来模拟继承
- 也可以把使用结构体类型定义各个不同的结构体变量也看作是继承.
- 这种继承一般用在子类和父类差别不大的场合;
- 各个结构体变量就是子类,然后各个子类拓展各自的方法和属性
2.2内存模型:
以上面Gr_t
结构体为例:
- 如图所示,子类
Gr_t
与第一个继承而来的Motor_t
共用一个地址 ;
- 在栈区中有一处空间储存着
Gr_t
类实例后的对象 , 而Gr_t
结构体中的第一个成员是Motor_t
对象 , 所以包含了父类中定义的属性
- 因此对于一个子类对象 ,它可以像访问自己的成员一样访问父类的成员
2.3代码:
以底盘结构体为例:
结构体定义:
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 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
| typedef __packed struct { C_t C; REMOTE_t *RC; FSM_t *Fsm; void (*Fsm_Init)(void); void (*Wheel_Init)(C_t *C); void (*Rescue_Init)(C_t *C); void (*Indepen)(C_t*,float ,float ,float ,int16_t); .... }Chassis_t;
typedef __packed struct { Motor_t WheelMotor[4]; Motor_t RescueMotor; PYR_t *gyro; PID_t Yaw_Pid; void (*Can_Send_Wheel)(int16_t,int16_t,int16_t,int16_t); void (*Can_Send_Rescue)(int16_t,int16_t,int16_t,int16_t); PYR_t* (*Get_PYR_t)(void); }C_t;
typedef __packed struct { uint8_t ID; uint8_t Pos_Lock; ... }Motor_t;
typedef __packed struct { u8 data[128]; float Roll; float Pitch; ... }PYR_t;
typedef __packed struct { fp32 Set; fp32 Ref; fp32 LastRef; ... }PID_t;
typedef struct _fsm { unsigned char (*State_Change)(State_t *L_Sta,State_t *C_Sta); State_t *Last_State; State_t *Current_State; State_t (*State_Table)[State_Column]; }FSM_t;
typedef struct _state { void (*State_Prepare)(void); void (*State_Process)(void); void (*Behavior_Process)(void); }State_t;
typedef __packed struct { RC_ctrl_t *RC_ctrl; First_Order_t RC_X; First_Order_t KM_Z; KeyBoard_State_t state; }REMOTE_t;
typedef __packed struct { fp32 Input; fp32 LastOuput; ... }First_Order_t;
typedef __packed struct { unsigned char Electromagnet : 1; unsigned char RFID : 1; unsigned char Magazine : 1; unsigned char Auto_Clamp : 5; }KeyBoard_State_t;
typedef __packed struct { int16_t ch0; int16_t ch1; ... }RC_ctrl_t;
|
2.4底盘继承关系图:
![](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASwAAAEsCAMAAABOo35HAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAC9UExURVlZWdPT07KysmRkZIWFhfT09JmZmWZmZm9vb39/fxkZGUxMTDMzM3p6epCQkKamppubm729venp6cjIyN7e3tbW1s/Pz8LCwnx8fLS0tFZWVoiIiI+Pj6GhoeTk5Glpabu7u93d3evr66CgoJSUlKqqqsnJyeDg4Hd3d8PDw+Xl5bi4uNHR0dvb26Ojo6urq+fn51hYWDg4OCgoKHBwcK2traenp0FBQe7u7vHx8U5OTre3t8zMzHV1df///7GrnpQAAAA/dFJOU///////////////////////////////////////////////////////////////////////////////////AI4mfBcAAAUGSURBVHja7NoJb6M4GMZxY0NCD64kve/pMZ2d3Z297+X7f6zFNmBAMUXa6URl/q9UJSWPUPzrizFWRUlNLgEBWGCBBRZYYEEAFlhggQUWWBCABRZYYIEFFgRggQUWWGCBBQFYYIEFFlhgQQAWWGCBBRZYEIAFFlhggQUWBGCBBRZYYIEFAVhggQUWWGBBABZYYIEFFlgQgAUWWGCBBRYEYIEFFlhggQUBWGCBBRZYYEEAFlhggQUWWBCABRZYYIEFFgRggQUWWGCBBQFYYIEFFlhgQQAWWGCBBRZYEIAFFlhggQUWBGCBBRZYn6cCIcRXgvX/h9qcIVBqDdbEM8RCxGCB9QqXYRwHYDHBgwXWl8eKZKiESHI3Ba1kWs3fKixcaJUl1YyeBm7Ocq+yLItUiVBGnXxenSHJolIKEcwHq6ikbOX1YGVzQCTN8LPmSLreghUl9sN4Uw7yajMrLC0TZ1ImzqY6FEop0+pIaEN5HaoOxVuwEqFyc4I46uSlzOLqgxlh6UaR9l3VYWl9Fdoxb1Q90KJtu41pwwFW/WHhTtW8i7TafLCqRsk6bsGw63L9qurXRmuIlbT9lDQnlXU+nBFW1Q2qnZbDprWa2tjR90LZFqx1/+Td/HpGWLlrLDvIwTcx6dQ1Vrntbig68cDms3JwbA5Y1azs1ger6sNV/bbIw1jU81MvNAGrl58RVn8ozW+btF08iGFoAlYvP3csfVur1gJBEIA1uBmue5dhZDOyO2epbmgCVi8/I6x0MMHH9pjsTfBhNzQBq5uPZoQlB0uH3DZG4EZqQ26fL3sZq5uf09Ih6qw3i/pm6BZO0qZX7rrUS68Xsbr5ZE4rePMk08pk9aUZugfqppvs6AM1Acvlo/StP+6EbW06z8hJqxbYp2BZPQUnFsLsKuhQdaHqn5ewbF7KXIn0jWO5MqOQ7RaNLPtbNMmmhimj0GUmYLl8Gs0Lq4wyPbTu1l2QKqHSouzs3OlDIslW5SQsnY/NXmFplyNvEuuLV/Tau9BzwiraDUSwXmysztYWWNtL1psXeumgIrDGaqXvBfUuvtqUYI3V2t1wk1e2msFluJJm6zDJXv/fIfjPP7DAAgsssCiwwAILLLDAosACCyywwAKLAgsssMACC6zt9fDz/v75tyOB+98PD2+ORgKffjw4OP1uJPDxl+Xy8v1I4MPF3t7VNyOB4/vF4uzdzrG+39f1kz/w66Guv/yBvw90KX/gZKkr8Qf+2dOV+gNHC12/7RxrabD2/a31bLAO/a11YbAO/K21MFhLf2s9Gqw9f2vdGqzFu11jnVusE2/gxmI9eQOnFuvYG7i0WH7uK4t15w2cWazrXWP9a7H8f/bQYvm/6IPF+sF/pVssf19Ii/WH/0K2WH/uGuvEWC39gSdj9Twy+Rqri5EZx1gt/IE7Y/XoD1wbq9vd3w1PlufnD2OBp+ebm/uxwPHF6emnscDR4vLy41jg7vHq6sNY4Pr27OyYdRaLUrDAAosCCyywwAILLAossMACCyywKLDAAgsssMCiwAILLLDAAosCCyywwAILLAossMACCyywKLDAAgsssMCiwAILLLDAAosCCyywwAILLAossMACCyywKLDAAgsssMCiwAILLLDAAosCCyywwAILLAossMACCyywKLDAAgsssMCiwAILLLDAAosCCyywwAILLAossMACCyywKLDAAgsssL6u+k+AAQCR9eHtLKvLfwAAAABJRU5ErkJggg==)
- 以上就是在多任务操作系统中 ,底盘任务中比较重要的一些结构体和对应的函数操作集
- 底盘各个状态切换和正常运行都是通过这些函数接口来进行维护的
- 最后封装成一个底盘任务的运行结构体 , 并实例化用于储存任务运行中的属性和方法
- 其他任务也是如此(如云台任务等) , 不同的是不同任务对象各自对应实现方法有些不同
- 像这样子类继承父类的过程中,一个接口在不同的子类中有不同的实现 ,就是接下来要介绍的多态
3️⃣ 多态
- 在C++里面实现多态使用的是虚函数 , 子类在继承父类之后,在内存中又会开辟一块空间来放置子类自己的虚表
- C中对于多态的实现可以借助函数指针(即函数映射)来实现。
- 因为对于不同的子类对象 , 一个方法在内存中只有一个变量,就是那个函数指针;
- 当p->pfun指向不同的传入实参的函数地址 , 子类中的实现方法也自然会不同.
3.1 构造函数与this
指针
在实例化一个对象时,C++通过构造函数来进行初始化,而C语言没有,所以我们需要创建一个自己的构造函数。
![image-20220831182345598](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASwAAAEsCAMAAABOo35HAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAC9UExURVlZWdPT07KysmRkZIWFhfT09JmZmWZmZm9vb39/fxkZGUxMTDMzM3p6epCQkKamppubm729venp6cjIyN7e3tbW1s/Pz8LCwnx8fLS0tFZWVoiIiI+Pj6GhoeTk5Glpabu7u93d3evr66CgoJSUlKqqqsnJyeDg4Hd3d8PDw+Xl5bi4uNHR0dvb26Ojo6urq+fn51hYWDg4OCgoKHBwcK2traenp0FBQe7u7vHx8U5OTre3t8zMzHV1df///7GrnpQAAAA/dFJOU///////////////////////////////////////////////////////////////////////////////////AI4mfBcAAAUGSURBVHja7NoJb6M4GMZxY0NCD64kve/pMZ2d3Z297+X7f6zFNmBAMUXa6URl/q9UJSWPUPzrizFWRUlNLgEBWGCBBRZYYEEAFlhggQUWWBCABRZYYIEFFgRggQUWWGCBBQFYYIEFFlhgQQAWWGCBBRZYEIAFFlhggQUWBGCBBRZYYIEFAVhggQUWWGBBABZYYIEFFlgQgAUWWGCBBRYEYIEFFlhggQUBWGCBBRZYYEEAFlhggQUWWBCABRZYYIEFFgRggQUWWGCBBQFYYIEFFlhgQQAWWGCBBRZYEIAFFlhggQUWBGCBBRZYn6cCIcRXgvX/h9qcIVBqDdbEM8RCxGCB9QqXYRwHYDHBgwXWl8eKZKiESHI3Ba1kWs3fKixcaJUl1YyeBm7Ocq+yLItUiVBGnXxenSHJolIKEcwHq6ikbOX1YGVzQCTN8LPmSLreghUl9sN4Uw7yajMrLC0TZ1ImzqY6FEop0+pIaEN5HaoOxVuwEqFyc4I46uSlzOLqgxlh6UaR9l3VYWl9Fdoxb1Q90KJtu41pwwFW/WHhTtW8i7TafLCqRsk6bsGw63L9qurXRmuIlbT9lDQnlXU+nBFW1Q2qnZbDprWa2tjR90LZFqx1/+Td/HpGWLlrLDvIwTcx6dQ1Vrntbig68cDms3JwbA5Y1azs1ger6sNV/bbIw1jU81MvNAGrl58RVn8ozW+btF08iGFoAlYvP3csfVur1gJBEIA1uBmue5dhZDOyO2epbmgCVi8/I6x0MMHH9pjsTfBhNzQBq5uPZoQlB0uH3DZG4EZqQ26fL3sZq5uf09Ih6qw3i/pm6BZO0qZX7rrUS68Xsbr5ZE4rePMk08pk9aUZugfqppvs6AM1Acvlo/StP+6EbW06z8hJqxbYp2BZPQUnFsLsKuhQdaHqn5ewbF7KXIn0jWO5MqOQ7RaNLPtbNMmmhimj0GUmYLl8Gs0Lq4wyPbTu1l2QKqHSouzs3OlDIslW5SQsnY/NXmFplyNvEuuLV/Tau9BzwiraDUSwXmysztYWWNtL1psXeumgIrDGaqXvBfUuvtqUYI3V2t1wk1e2msFluJJm6zDJXv/fIfjPP7DAAgsssCiwwAILLLDAosACCyywwAKLAgsssMACC6zt9fDz/v75tyOB+98PD2+ORgKffjw4OP1uJPDxl+Xy8v1I4MPF3t7VNyOB4/vF4uzdzrG+39f1kz/w66Guv/yBvw90KX/gZKkr8Qf+2dOV+gNHC12/7RxrabD2/a31bLAO/a11YbAO/K21MFhLf2s9Gqw9f2vdGqzFu11jnVusE2/gxmI9eQOnFuvYG7i0WH7uK4t15w2cWazrXWP9a7H8f/bQYvm/6IPF+sF/pVssf19Ii/WH/0K2WH/uGuvEWC39gSdj9Twy+Rqri5EZx1gt/IE7Y/XoD1wbq9vd3w1PlufnD2OBp+ebm/uxwPHF6emnscDR4vLy41jg7vHq6sNY4Pr27OyYdRaLUrDAAosCCyywwAILLAossMACCyywKLDAAgsssMCiwAILLLDAAosCCyywwAILLAossMACCyywKLDAAgsssMCiwAILLLDAAosCCyywwAILLAossMACCyywKLDAAgsssMCiwAILLLDAAosCCyywwAILLAossMACCyywKLDAAgsssMCiwAILLLDAAosCCyywwAILLAossMACCyywKLDAAgsssL6u+k+AAQCR9eHtLKvLfwAAAABJRU5ErkJggg==)
注意:
C 语言中不存在像 C++ 中那样的 this 指针,如果我们不显式地通过参数提供,那么在函数内部就无法访问结构体实例的其它成员。
![image-20220901113321988](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASwAAAEsCAMAAABOo35HAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAC9UExURVlZWdPT07KysmRkZIWFhfT09JmZmWZmZm9vb39/fxkZGUxMTDMzM3p6epCQkKamppubm729venp6cjIyN7e3tbW1s/Pz8LCwnx8fLS0tFZWVoiIiI+Pj6GhoeTk5Glpabu7u93d3evr66CgoJSUlKqqqsnJyeDg4Hd3d8PDw+Xl5bi4uNHR0dvb26Ojo6urq+fn51hYWDg4OCgoKHBwcK2traenp0FBQe7u7vHx8U5OTre3t8zMzHV1df///7GrnpQAAAA/dFJOU///////////////////////////////////////////////////////////////////////////////////AI4mfBcAAAUGSURBVHja7NoJb6M4GMZxY0NCD64kve/pMZ2d3Z297+X7f6zFNmBAMUXa6URl/q9UJSWPUPzrizFWRUlNLgEBWGCBBRZYYEEAFlhggQUWWBCABRZYYIEFFgRggQUWWGCBBQFYYIEFFlhgQQAWWGCBBRZYEIAFFlhggQUWBGCBBRZYYIEFAVhggQUWWGBBABZYYIEFFlgQgAUWWGCBBRYEYIEFFlhggQUBWGCBBRZYYEEAFlhggQUWWBCABRZYYIEFFgRggQUWWGCBBQFYYIEFFlhgQQAWWGCBBRZYEIAFFlhggQUWBGCBBRZYn6cCIcRXgvX/h9qcIVBqDdbEM8RCxGCB9QqXYRwHYDHBgwXWl8eKZKiESHI3Ba1kWs3fKixcaJUl1YyeBm7Ocq+yLItUiVBGnXxenSHJolIKEcwHq6ikbOX1YGVzQCTN8LPmSLreghUl9sN4Uw7yajMrLC0TZ1ImzqY6FEop0+pIaEN5HaoOxVuwEqFyc4I46uSlzOLqgxlh6UaR9l3VYWl9Fdoxb1Q90KJtu41pwwFW/WHhTtW8i7TafLCqRsk6bsGw63L9qurXRmuIlbT9lDQnlXU+nBFW1Q2qnZbDprWa2tjR90LZFqx1/+Td/HpGWLlrLDvIwTcx6dQ1Vrntbig68cDms3JwbA5Y1azs1ger6sNV/bbIw1jU81MvNAGrl58RVn8ozW+btF08iGFoAlYvP3csfVur1gJBEIA1uBmue5dhZDOyO2epbmgCVi8/I6x0MMHH9pjsTfBhNzQBq5uPZoQlB0uH3DZG4EZqQ26fL3sZq5uf09Ih6qw3i/pm6BZO0qZX7rrUS68Xsbr5ZE4rePMk08pk9aUZugfqppvs6AM1Acvlo/StP+6EbW06z8hJqxbYp2BZPQUnFsLsKuhQdaHqn5ewbF7KXIn0jWO5MqOQ7RaNLPtbNMmmhimj0GUmYLl8Gs0Lq4wyPbTu1l2QKqHSouzs3OlDIslW5SQsnY/NXmFplyNvEuuLV/Tau9BzwiraDUSwXmysztYWWNtL1psXeumgIrDGaqXvBfUuvtqUYI3V2t1wk1e2msFluJJm6zDJXv/fIfjPP7DAAgsssCiwwAILLLDAosACCyywwAKLAgsssMACC6zt9fDz/v75tyOB+98PD2+ORgKffjw4OP1uJPDxl+Xy8v1I4MPF3t7VNyOB4/vF4uzdzrG+39f1kz/w66Guv/yBvw90KX/gZKkr8Qf+2dOV+gNHC12/7RxrabD2/a31bLAO/a11YbAO/K21MFhLf2s9Gqw9f2vdGqzFu11jnVusE2/gxmI9eQOnFuvYG7i0WH7uK4t15w2cWazrXWP9a7H8f/bQYvm/6IPF+sF/pVssf19Ii/WH/0K2WH/uGuvEWC39gSdj9Twy+Rqri5EZx1gt/IE7Y/XoD1wbq9vd3w1PlufnD2OBp+ebm/uxwPHF6emnscDR4vLy41jg7vHq6sNY4Pr27OyYdRaLUrDAAosCCyywwAILLAossMACCyywKLDAAgsssMCiwAILLLDAAosCCyywwAILLAossMACCyywKLDAAgsssMCiwAILLLDAAosCCyywwAILLAossMACCyywKLDAAgsssMCiwAILLLDAAosCCyywwAILLAossMACCyywKLDAAgsssMCiwAILLLDAAosCCyywwAILLAossMACCyywKLDAAgsssL6u+k+AAQCR9eHtLKvLfwAAAABJRU5ErkJggg==)
3.2 测试代码
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 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
| #include <stdio.h>
typedef struct { int test1 ; void (*test_printf)(void); }base_t;
typedef struct { base_t test_base; void (*base_init)(base_t* ba); }derive_t;
void derive2_printf(void) { printf("derive2\n"); }
void Fbase2_init(base_t* base) { base->test1 = 0; base->test_printf = derive2_printf; }
void derive2_init(derive_t* der) { der->base_init = Fbase2_init; der->base_init(&der->test_base); }
void derive1_printf(void) { printf("derive1\n"); }
void Fbase1_init(base_t* base) { base->test1 = 0; base->test_printf = derive1_printf; }
void derive1_init(derive_t* der) { der->base_init = Fbase1_init; der->base_init(&der->test_base); }
int main(void) { derive_t der1,der2; derive1_init(&der1); derive2_init(&der2);
derive_t* der_point; der_point = &der2; der_point->test_base.test_printf(); der_point = &der1; der_point->test_base.test_printf();
return 0; }
|
运行结果:
![image-20220831224350162](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASwAAAEsCAMAAABOo35HAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAC9UExURVlZWdPT07KysmRkZIWFhfT09JmZmWZmZm9vb39/fxkZGUxMTDMzM3p6epCQkKamppubm729venp6cjIyN7e3tbW1s/Pz8LCwnx8fLS0tFZWVoiIiI+Pj6GhoeTk5Glpabu7u93d3evr66CgoJSUlKqqqsnJyeDg4Hd3d8PDw+Xl5bi4uNHR0dvb26Ojo6urq+fn51hYWDg4OCgoKHBwcK2traenp0FBQe7u7vHx8U5OTre3t8zMzHV1df///7GrnpQAAAA/dFJOU///////////////////////////////////////////////////////////////////////////////////AI4mfBcAAAUGSURBVHja7NoJb6M4GMZxY0NCD64kve/pMZ2d3Z297+X7f6zFNmBAMUXa6URl/q9UJSWPUPzrizFWRUlNLgEBWGCBBRZYYEEAFlhggQUWWBCABRZYYIEFFgRggQUWWGCBBQFYYIEFFlhgQQAWWGCBBRZYEIAFFlhggQUWBGCBBRZYYIEFAVhggQUWWGBBABZYYIEFFlgQgAUWWGCBBRYEYIEFFlhggQUBWGCBBRZYYEEAFlhggQUWWBCABRZYYIEFFgRggQUWWGCBBQFYYIEFFlhgQQAWWGCBBRZYEIAFFlhggQUWBGCBBRZYn6cCIcRXgvX/h9qcIVBqDdbEM8RCxGCB9QqXYRwHYDHBgwXWl8eKZKiESHI3Ba1kWs3fKixcaJUl1YyeBm7Ocq+yLItUiVBGnXxenSHJolIKEcwHq6ikbOX1YGVzQCTN8LPmSLreghUl9sN4Uw7yajMrLC0TZ1ImzqY6FEop0+pIaEN5HaoOxVuwEqFyc4I46uSlzOLqgxlh6UaR9l3VYWl9Fdoxb1Q90KJtu41pwwFW/WHhTtW8i7TafLCqRsk6bsGw63L9qurXRmuIlbT9lDQnlXU+nBFW1Q2qnZbDprWa2tjR90LZFqx1/+Td/HpGWLlrLDvIwTcx6dQ1Vrntbig68cDms3JwbA5Y1azs1ger6sNV/bbIw1jU81MvNAGrl58RVn8ozW+btF08iGFoAlYvP3csfVur1gJBEIA1uBmue5dhZDOyO2epbmgCVi8/I6x0MMHH9pjsTfBhNzQBq5uPZoQlB0uH3DZG4EZqQ26fL3sZq5uf09Ih6qw3i/pm6BZO0qZX7rrUS68Xsbr5ZE4rePMk08pk9aUZugfqppvs6AM1Acvlo/StP+6EbW06z8hJqxbYp2BZPQUnFsLsKuhQdaHqn5ewbF7KXIn0jWO5MqOQ7RaNLPtbNMmmhimj0GUmYLl8Gs0Lq4wyPbTu1l2QKqHSouzs3OlDIslW5SQsnY/NXmFplyNvEuuLV/Tau9BzwiraDUSwXmysztYWWNtL1psXeumgIrDGaqXvBfUuvtqUYI3V2t1wk1e2msFluJJm6zDJXv/fIfjPP7DAAgsssCiwwAILLLDAosACCyywwAKLAgsssMACC6zt9fDz/v75tyOB+98PD2+ORgKffjw4OP1uJPDxl+Xy8v1I4MPF3t7VNyOB4/vF4uzdzrG+39f1kz/w66Guv/yBvw90KX/gZKkr8Qf+2dOV+gNHC12/7RxrabD2/a31bLAO/a11YbAO/K21MFhLf2s9Gqw9f2vdGqzFu11jnVusE2/gxmI9eQOnFuvYG7i0WH7uK4t15w2cWazrXWP9a7H8f/bQYvm/6IPF+sF/pVssf19Ii/WH/0K2WH/uGuvEWC39gSdj9Twy+Rqri5EZx1gt/IE7Y/XoD1wbq9vd3w1PlufnD2OBp+ebm/uxwPHF6emnscDR4vLy41jg7vHq6sNY4Pr27OyYdRaLUrDAAosCCyywwAILLAossMACCyywKLDAAgsssMCiwAILLLDAAosCCyywwAILLAossMACCyywKLDAAgsssMCiwAILLLDAAosCCyywwAILLAossMACCyywKLDAAgsssMCiwAILLLDAAosCCyywwAILLAossMACCyywKLDAAgsssMCiwAILLLDAAosCCyywwAILLAossMACCyywKLDAAgsssL6u+k+AAQCR9eHtLKvLfwAAAABJRU5ErkJggg==)
- 通过der->printf指向不同的传入实参的函数地址 , 实现子类中不同的实现方法;
- 通过这种方法在C语言中模拟"多态"
❗️ 应用实例
以底盘驱动任务为例 , 说明C语言面向对象思想在项目中的使用
4.1 基本框架文件介绍
-
Chassis_Task.c/h
[ 应用层 ] : 是进程运行的主要文件(相当于main文件) , 同时提供了整个 底盘总的控制结构体(类)
-
Chassis_Fsm.c/h
[ 应用接口层 ] :主要统一汇总下层API接口 , 并提供底盘控制状态行为函数的 方法;
-
RemoteDeal.c/h
[ 功能模块层 ] : 主要 封装遥控接收模块功能 为上层提供API接口 , 并提供遥控数据处理的 方法和类
-
ChassisMotor.c/h
[ 业务逻辑层 ] :主要封装了各底盘行为模式功能 , 并提供了底盘电机驱动和控制的 方法和类
-
fsm.c/h
[ 应用层 ] :主要提供了底盘控制的状态机状态切换的 方法和类
软件框架:
应用层 |
底盘控制任务 |
状态机状态转换任务 |
业务逻辑层 |
底盘模式1 |
底盘模式2 |
底盘模式3.. |
功能模块层 |
电机驱动模块 |
遥控接收处理模块 |
算法库模块 |
硬件驱动层 |
各外设驱动... |
4.1.1 fsm.c/h
[ 应用层 ] :主要提供了底盘控制的状态机状态切换的 方法和类
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 48 49 50 51 52 53 54
| #include "fsm.h"
void FSM_Deal(FSM_t *fsm, unsigned char s1, unsigned char s2) { if(s1 <= 0 || s1 > State_Line || s2 <= 0 || s2 > State_Column) { return; }
fsm->Current_State = &fsm->State_Table[s1-1][s2-1];
if( fsm->State_Change(fsm->Last_State,fsm->Current_State) == 1) { fsm->Current_State->State_Prepare(); }
fsm->Last_State = fsm->Current_State;
fsm->Current_State->State_Process(); fsm->Current_State->Behavior_Process(); }
typedef struct _state { void (*State_Prepare)(void); void (*State_Process)(void); void (*Behavior_Process)(void); }State_t;
typedef struct _fsm { unsigned char (*State_Change)(State_t *L_Sta,State_t *C_Sta); State_t *Last_State; State_t *Current_State; State_t (*State_Table)[State_Column]; }FSM_t;
void FSM_Deal(FSM_t *fsm, unsigned char s1, unsigned char s2);
|
4.1.2 Chassis_Task.c/h
[ 应用层 ] : 是进程运行的主要文件(相当于main文件) , 同时提供了整个 底盘总的控制结构体(类)
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 48 49 50 51 52 53 54 55 56 57 58
| #include "Chassis_Task.h"
extern Chassis_t Chassis; Chassis_t Chassis;
static void Chassis_Init(void) { Chassis.Fsm_Init = Chassis_FSM_Init; Chassis.Wheel_Init = Wheel_Motor_Init; Chassis.Rescue_Init = Rescue_Motor_Init; Chassis.Indepen = Chassis_Indepen_Drive; Chassis.Wiggle = Chassis_Wiggle_Drive; Chassis.Poweroff = Chassis_Poweroff_Drive; Chassis.RC = Return_RemoteDeal_Point(); Chassis.Wheel_Init(&Chassis.C); Chassis.Rescue_Init(&Chassis.C); Chassis.Fsm = Return_Chassis_FSM(); Chassis.Fsm_Init(); }
void Chassis_Task(void *pvParameters) { vTaskDelay(500); Chassis_Init();
while(1) { FSM_Deal(Chassis.Fsm,Chassis.RC->RC_ctrl->s1,Chassis.RC->RC_ctrl->s2); vTaskDelay(2); } }
typedef __packed struct { C_t C; REMOTE_t *RC; FSM_t *Fsm; void (*Fsm_Init)(void); void (*Wheel_Init)(C_t *C); void (*Rescue_Init)(C_t *C); void (*Indepen)(C_t*,float ,float ,float ,int16_t); .... }Chassis_t;
void Chassis_Task(void *pvParameters);
|
4.1.3 ChassisMotor.c/h
[ 业务逻辑层 ] :主要封装了各底盘行为模式功能 , 并提供了底盘电机驱动和控制的 方法和类
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 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
| #include "ChassisMotor.h"
void Wheel_Motor_Init(C_t *C) { u8 CMi = 0; float Spid[4][3] = { {WHEEL_MOTOR1_P,WHEEL_MOTOR1_I,WHEEL_MOTOR1_D}, {WHEEL_MOTOR2_P,WHEEL_MOTOR2_I,WHEEL_MOTOR2_D}, {WHEEL_MOTOR3_P,WHEEL_MOTOR3_I,WHEEL_MOTOR3_D}, {WHEEL_MOTOR4_P,WHEEL_MOTOR4_I,WHEEL_MOTOR4_D}, }; C->Can_Send_Rescue = CAN1_205_To_208_SEND; .... MotorValZero(&C->WheelMotor[0]); .... for(CMi = 0;CMi < 4;CMi ++) { C->WheelMotor[CMi].ID = CMi + 1; C->WheelMotor[CMi].Encoder = C->Get_Encoder(CMi+1); PID_INIT(&C->WheelMotor[CMi].SPID,Spid[CMi][0],Spid[CMi][1],Spid[CMi][2],15000,16000); C->WheelMotor[CMi].MotorType = CHASSIS_M; C->WheelMotor[CMi].Radio = 19; } C->gyro = C->Get_PYR_t(); }
void Chassis_Indepen_Drive(C_t *C,float X_IN,float Y_IN,float Z_IN,int16_t ExpRescue) { ... }
void Chassis_Wiggle_Drive(C_t *C,float X_IN,float Y_IN,float Z_IN) { ... }
....
typedef __packed struct { Motor_t WheelMotor[4]; .... }C_t;
|
4.1.4 Chassis_Fsm.c/h
[ 应用接口层 ] :主要统一汇总下层API接口 , 并提供底盘控制状态行为函数的 方法;
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 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
| #include "Chassis_Fsm.h" #include "Chassis_Task.h"
FSM_t Chassis_FSM; State_t OFFLINE; State_t INDEPEN; State_t WIGGLE; ...
State_t Chassis_State_Table[RC_SW1_lift][RC_SW2_right] = { {CHASSIS_REMOTECONTROL, CHASSIS_STANDBY, CHASSIS_REMOTECONTROL}, {CHASSIS_REMOTECONTROL, CHASSIS_STANDBY, CHASSIS_REMOTECONTROL}, {CHASSIS_REMOTECONTROL, CHASSIS_STANDBY, CHASSIS_REMOTECONTROL} };
void Chassis_FSM_Init(void) { Chassis_FSM.State_Table = Chassis_State_Table; Chassis_FSM.Last_State = NULL; Chassis_FSM.Current_State = NULL; OFFLINE.Behavior_Process = NULL; OFFLINE.State_Process = Offline_State; OFFLINE.State_Prepare = Offline_Prepare; INDEPEN.Behavior_Process = NULL; INDEPEN.State_Process = Indepen_State; INDEPEN.State_Prepare = Indepen_Prepare; WIGGLE.Behavior_Process = NULL; WIGGLE.State_Process = Wiggle_State; WIGGLE.State_Prepare = Wiggle_Prepare; }
static void Offline_State(void) { Chassis_FSM.Current_State->Behavior_Process = PowerOff_bhv; }
static void Offline_Prepare(void) { Chassis.Poweroff(&Chassis.C); }
static void PowerOff_bhv(void) { Chassis.Poweroff(&Chassis.C); }
...
...
|
- 各个状态模式 (即
State_t
实例化的对象) 可以当成继承自同一父类的不同子类
- 其对各自API接口在不同子类中有不同的实现 , 即是函数多态的一种应用
4.1.5 RemoteDeal.c/h
[ 功能模块层 ] : 主要 封装遥控接收模块功能 为上层提供API接口 , 并提供遥控数据处理的 方法和类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
|
#include "RemoteDeal.h"
REMOTE_t REMOTE;
REMOTE_t *Return_RemoteDeal_Point(void) { return &REMOTE; }
...
|
通过指针传递方式 , 传递父类信息
4.2 控制流程图
4.2.1 底盘进程总流程:
4.2.2 底盘进程 - 函数调用图
-------------已经到底啦! -------------
0%