• 正文
  • 推荐器件
  • 相关推荐
申请入驻 产业图谱

嵌入式 C 语言面向对象编程 --- 封装

2024/07/08
494
加入交流群
扫码加入
获取工程师必备礼包
参与热点资讯讨论
我是老温,一名热爱学习的嵌入式工程师,关注我,一起变得更加优秀!

大部分使用 C 语言进行开发的工程师,在接触更高级的编程语言之前,都认为 C 语言是面向过程的。

事实也是如此,对于一些小规模的单片机应用程序,一般都是使用“面向过程”的思维进行单片机C语言编程开发。

但是,如果是需要用C语言开发一些规模比较大的软件的时候,比如操作系统内核,文件系统底层,数据库底层,等等,这个时候,就需要用面向对象的思想去考虑和设计整个软件框架了。

嵌入式Linux的内核,虽然是使用 C 语言编写的,但里面的设计大部分都使用了面向对象的编程思想。

很多单片机工程师或者嵌入式Linux驱动初学者,有时候会觉得驱动入门特别困难,很大一部分原因是,他们会用“过程式思维”去尝试学习驱动框架和内核框架,而非从“整体对象”的思维方向出发,这样容易导致水土不服。

任何编程语言只是一种工具,而编程思想是指导我们用好这个工具的关键。

C 语言只是工具,而面向对象是一种编程思想,用来指导我们如何用从另一种思维模式去使用 C 语言。

值得注意的是,并不是所有使用C语言开发的项目,都必须以“面向对象”作为指导,有时候“面向过程”也不一定是坏事,需要根据实际项目情况,具体问题具体分析。

接下来,我们将尝试使用 C 语言进行面向对象程序开发,务求使用 C 语言实现面向对象的一些基本特性,先来说说封装

封装就是把一个抽象事物的属性和属性的操作函数打包在一起,外界的模块只能通过这个抽象事物对外提供的函数接口,对其属性进行访问。

在C++或其他高级语言中,封装通常被称作“类”。而 C 语言一般使用结构体对事物进行封装。

说人话就是,封装,即“封闭包装起来”,俗称“打包”。把事物里面一些相近类似的特征进行打包(打包的过程一般称作“抽象”),这样就是封装了。

举个例子:大多数动物,都有眼睛耳朵嘴巴鼻子,把“五官”提取出来进行封装,这个封装就成为了大多数动物共有的东西。

头文件 coordinate.h

#ifndef __COORDINATE_H_
#define __COORDINATE_H_

//声明一个位置类,属性为坐标x,y
typedef struct coordinate{
    short int x;
    short int y;
}COORDINATE_T,*P_COORDINATE_T;

extern P_COORDINATE_T coordinate_create(short int x,short int y);
extern void coordinate_destroy(P_COORDINATE_T p_coordinate);
extern void coordinate_moveby(P_COORDINATE_T p_coordinate,short int dx,short int dy);
extern short int coordinate_get_x(P_COORDINATE_T p_coordinate);
extern short int coordinate_get_y(P_COORDINATE_T p_coordinate);
extern void coordinate_test_function(void);
#endif // !__COORDINATE_H_

源文件 coordinate.c

#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "inc/coordinate.h"

//创建一个coordinate对象
P_COORDINATE_T coordinate_create(short int x,short int y)
{
    if((x < 0) || (y < 0)){
        printf("coordinate creat error! x or y can not be less than zero n");
        return NULL;
    }

    P_COORDINATE_T p_coordiante = NULL;
    p_coordiante = (P_COORDINATE_T)malloc(sizeof(COORDINATE_T));

    if(NULL != p_coordiante){
        p_coordiante->x = x;
        p_coordiante->y = y;        
    }
    else printf("coordinate malloc error! n");
         
    return p_coordiante;
}

//销毁一个coordinate对象
void coordinate_destroy(P_COORDINATE_T p_coordiante)
{
    if(NULL != p_coordiante){
        free(p_coordiante);
        p_coordiante = NULL;
    }
}

//修改coordinate的属性值
void coordinate_moveby(P_COORDINATE_T p_coordiante,short int dx,short int dy)
{
    if(NULL != p_coordiante){
        p_coordiante->x += dx;
        p_coordiante->y += dy;
    }
}

//获取coordinate的属性值x
short int coordinate_get_x(P_COORDINATE_T p_coordiante)
{  
    return (NULL != p_coordiante) ? p_coordiante->x : -1;
}

//获取coordinate的属性值y
short int coordinate_get_y(P_COORDINATE_T p_coordiante)
{
    return (NULL != p_coordiante) ? p_coordiante->y : -1;
}

代码比较简单,在头文件 coordinate.h里面,通过结构体封装了一个coordinate类,里面有两个坐标属性 x 和 y 。

coordinate_create 函数主要用于创建一个 P_COORDINATE_T 类型的对象,并为其分配内存空间,内存分配成功后,设置两个坐标属性的初始值,最后返回申请成功的对象指针。

coordinate_destroy 主要是释放对象之前申请的内存空间,然后把对象指针重置为NULL。

其他的操作函数,主要是对类对象的属性进行操作,比如获取 x 和 y 的属性值,重置坐标的属性值。

以下是测试函数,在主函数中调用,即可测试类coordinate对外提供的接口。

void coordinate_test_function(void)
{
    P_COORDINATE_T p_coordiante_1 = NULL;
    P_COORDINATE_T p_coordiante_2 = NULL;

    p_coordiante_1 = (P_COORDINATE_T)coordinate_create(100,200);
    p_coordiante_2 = (P_COORDINATE_T)coordinate_create(10,20);

    if((NULL == p_coordiante_1) || (NULL == p_coordiante_2)){
        printf("p_coordiante_1 or p_coordiante_2 create error! n");
        return;
    }

    printf("p_coordiante_1 x = %d, y = %d n",coordinate_get_x(p_coordiante_1), coordinate_get_y(p_coordiante_1));
    printf("p_coordiante_2 x = %d, y = %d n",coordinate_get_x(p_coordiante_2), coordinate_get_y(p_coordiante_2));

    coordinate_moveby(p_coordiante_1,50,50);
    coordinate_moveby(p_coordiante_2,50,50);

    printf("after moveby p_coordiante_1 x = %d, y = %d n",coordinate_get_x(p_coordiante_1), coordinate_get_y(p_coordiante_1));
    printf("after moveby p_coordiante_2 x = %d, y = %d n",coordinate_get_x(p_coordiante_2), coordinate_get_y(p_coordiante_2));

    coordinate_destroy(p_coordiante_1);
    coordinate_destroy(p_coordiante_2);
}

测试代码比较简单,主要是创建了两个 P_COORDINATE_T 类型的对象,然后打印其坐标初始值,再通过对外提供的函数修改其坐标值,然后再打印出来,最后销毁之前创建的对象。测试函数运行后,结果如下所示:

p_coordiante_1 x = 100, y = 200 
p_coordiante_2 x = 10, y = 20 
after moveby p_coordiante_1 x = 150, y = 250 
after moveby p_coordiante_2 x = 60, y = 70

从上述代码可以看出,使用结构体可以很好地对数据进行封装,并且需要通过指定的操作函数对结构体内的数据进行访问。

每个操作函数的第一个参数是对象本身的指针,通过这个指针去访问具体对象里面的属性。这是因为在 C 语言中不存在像 C++ 语言那样的 this 指针,所以我们只能显式地通过函数传参的方式,让函数内部可以访问对象实例的其他成员。

对于对象属性的各种操作函数,还可以使用函数指针的方式,放入结构体内进行封装。但为了便于理解,本文并没有采用这种方法。

源码下载地址:https://github.com/embediot/my_program_test

感谢阅读!

推荐器件

更多器件
器件型号 数量 器件厂商 器件描述 数据手册 ECAD模型 风险等级 参考价格 更多信息
NX3225SA-40.000M-STD-CRS-2 1 Nihon Dempa Kogyo Co Ltd Parallel - Fundamental Quartz Crystal, 40MHz Nom, ROHS COMPLIANT PACKAGE-4
暂无数据 查看
FOD4208SD 1 Fairchild Semiconductor Corporation Triac Output Optocoupler, 1-Element, 5000V Isolation, LEAD FREE, SURFACE MOUNT PACKAGE-6
$4.14 查看
APV1122A 1 Panasonic Electronic Components Optoelectronic Device, DIP-6

ECAD模型

下载ECAD模型
$3.7 查看
点赞
收藏
评论
分享
加入交流群
举报

相关推荐

登录即可解锁
  • 海量技术文章
  • 设计资源下载
  • 产业链客户资源
  • 写文章/发需求
立即登录