杨韬
(广州致远电子股份有限公司,广东 广州 510660)
摘要:多年以来,C语言在嵌入式软件开发中被广泛使用,但由于开发人员和应用场景等原因,面向对象、设计模式等优秀的软件开发方法始终没有很好地运用起来。时至今日,物联网等应用的兴起,给嵌入式软件开发带来新的挑战,而传统的面向过程开发已经难以支撑这些复杂的应用。因此,有必要在嵌入式软件开发中引入面向对象、设计模式等优秀的软件开发方法。面向对象是现代软件方法的根基,面向对象体现在类上,使用类来创建对象的过程就是实例化。文章结合C语言的特性,对使用C语言实现类实例化进行了讨论。
关键词:C语言;面向对象;类;实例化
中图分类号:TP312文献标识码:ADOI:10.19358/j.issn.16747720.2016.23.004
引用格式:杨韬. 用C语言实现类实例化的研究[J].微型机与应用,2016,35(23):15-17.
0引言
物联网等应用的兴起,给嵌入式软件开发带来新的挑战,而传统的面向过程开发已经难以支撑这些复杂的应用。因此,有必要在嵌入式软件开发中引入面向对象、设计模式等优秀的软件开发方法。本文讨论了如何使用C语言来实现类的实例化。在C++等面向对象语言中对类做了原生的支持,使用new这类关键字即可实例化一个对象。尽管C语言并不支持new,但是通过对实例化过程的分析和拆分,也能实现实例化。
1基本概念[1]
1.1类
面向对象有封装、继承、多态三大特性,这些特性主要通过类来体现。类就是一个封装了属性以及相关操作的代码的逻辑实体。
类具有属性,它是对象的状态的抽象,用数据结构来描述类的属性。
类具有方法,它是对象的行为的抽象,用方法名和实现该操作的方法来描述。
除了封装属性和操作外,类还具有访问控制的能力,比如,某些属性和方法可以是私有的,不能被外界访问。通过访问控制,能够对内部数据提供不同级别的保护,以防止外界意外地改变或使用了私有部分。不同的编程语言提供的访问控制等级不尽相同,但都有公有、私有两个等级。
类是抽象的数据类型,在内存中并不存在(Python等动态语言除外),只有类的实例存在于内存中。
1.2对象
对象是人们要进行研究的任何事物,从最简单的整数到复杂的飞机等均可看作为对象,它不仅能表示具体的事物,还能表示抽象的规则、计划或事件。
对象具有状态,一个对象用数据值来描述它的状态。
对象还有操作,用于改变对象的状态,对象及其操作就是对象的行为。
对象实现了数据和操作的结合,使数据和操作封装于对象的统一体中。
1.3实例化
用类创建对象的过程就是实例化,创建的对象被称为类的实例。实例化包含两个步骤,第一步是分配对象的内存,第二步是初始化对象的内存。
2类封装的C语言实现
类的第一大特性为封装,封装即将对象的属性和方法封装在一起,在C语言中可以使用.C、.H和结构体实现类的封装特性。
以图1中Human类为例,可以使用human.h、human.c、struct human三个元素来完成封装,human.c为human.h中函数声明的实现,本文不讨论这些细节,所以只给出如下human.h的关键代码片段:
typedef struct human {
const char *name;
int_money;
} human_t;
human_t *human_init (human_t *p_this, const char *name, int money);
voidhuman_talk (human_t *p_this, const char *p_words);
voidhuman_buy (human_t *p_this, const char *p_something, unsigned price, unsigned count);
voidhuman_deinit (human_t *p_this);
3类实例化的C语言实现
实例化包含两个步骤:分配对象的内存和初始化对象的内存。接下来本文以图1中Human类的实例化为例,讨论C语言如何实现类的实例化。
3.1对象的内存
如果把类看做类型,那么类的实例就是变量,既然是变量,那么就有动态变量、静态变量和栈变量之分。在C语言中,使用malloc()这类动态内存分配函数得到的变量就是动态变量;全局变量和加了static关键字的变量就是静态变量;在函数内创建的局部变量就是栈变量。下面的代码展示了C语言中的这几类变量:
#include "human.h"
struct humang_john;/* 静态变量 */
static struct human __g_john;/* 静态变量 */
void foo (void)
{
static struct human s_john;/* 静态变量 */
struct human john;/* 栈变量 */
struct human*p_john = malloc(sizeof(*p_john));
/* 动态变量 */
}
站在内存的角度,可以把类看做结构体类型,类的实例就是结构体变量,因此,对象也就有动态对象、静态对象和栈对象之分,它们之间的区别如表1所示。
free()
释放内存内存分配可能失败,花费的时间可能不确定;需要处理内存分配失败的情况,增加程序的复杂性可以在需要时创建和销毁对象静态对象位于.data、
.bss内存段需要编译时确定对象的数量;一直占用内存;对象数量太多太大时会影响程序启动时间确定性好,只要程序能够运行起来,就一定能够创建成功栈对象位于系统
栈、对象栈对象太大会导致栈溢出自动完成对象内存的分配和回收
对于嵌入式软件中的C面向对象编程,充分理解表1中的这三类对象是非常有必要的。大多数情况下,一个类都要能够被实例化为静态对象。
3.2对象的初始化
初始化对象就是初始化对象的内存,在初始化之前,必然要先得到对象的内存(上一小节已讨论),但无论对象的内存是何种类型,初始化的操作都是相同的。在JAVA等编程语言中,完成此操作的函数被称作构造函数,使用C语言来实现就是一个名为xxxx_init()的初始化函数,也可称之为构造函数。
以Human类为例,它的初始化函数human_init()如下面的代码所示,可留意到对象的内存需要显式传递给它。
human_t *human_init (human_t *p_this, const char *name, int money)
{
p_this->name = name;
p_this->_money = money;
return p_this;
}
3.3实例化
前面两小节分别讨论了对象的内存和对象的初始化,这两步组成了实例化。下面的代码展示了不同类型对象的实例化:
#include "human.h"
human_tg_john;/* 静态对象 */
statichuman_t__g_jen;/* 静态对象 */
void foo (void)
{
static human_ts_jack;/* 静态对象 */
human_t tom;/* 栈对象 */
human_t*p_lee_mem= malloc(sizeof(*p_lee_mem));
/* 动态对象 */
// 实例化上面定义的静态对象、动态对象和栈对象
human_t *p_john= human_init(&g_john, "john", 100);
human_t *p_jen = human_init(&__g_jen, "jen", 100);
human_t *p_jack = human_init(&s_jack, "jack", 100);
human_t *p_tom = human_init(&tom, "tom", 100);
human_t *p_lee = human_init(p_lee_mem, "lee", 100);
3.4访问对象
对象实例化后便存于内存中,此时可以访问对象的属性和方法,下面的代码展示了对象的访问:
#include "human.h"
void foo (void)
{
human_t john;/* 定义对象内存 */
p_john = human_init(&jhon, "John", 100);
/* 初始化对象 */
printf("Human %s is born!", p_john->name);
/* 访问对象的属性 */
human_talk(p_john, "I am hungry");
/* 访问对象的方法 */
human_deinit(&john)/* 对象解初始化 */
}
3.5销毁对象
当对象不再使用时,便可销毁之。销毁对象与创建对象(实例化)的操作相反,首先对对象进行解初始化操作,然后再释放对象的内存。
以Human类为例,首先调用human_deinit()完成对象的解初始化,接下来,如果是静态对象或栈对象就不用显式释放对象的内存,因为静态对象或栈对象有确定的生命周期;如果是调用malloc()等函数得到了动态对象,则必须调用free()等对应的函数释放对象的内存。下面的代码展示了各种对象的销毁:
#include "human.h"
human_tg_john;/* 静态对象 */
statichuman_t__g_jen;/* 静态对象 */
void foo (void)
{
static human_ts_jack;/* 静态对象 */
human_t tom;/* 栈对象 */
human_t*p_lee_mem= malloc(sizeof(*p_lee_mem));
/* 动态对象 */
// 实例化上面定义的静态对象、动态对象和栈对象
human_t *p_john = human_init(&g_john, "john", 100);
human_t *p_jen = human_init(&__g_jen, "jen", 100);
human_t *p_jack = human_init(&s_jack, "jack", 100);
human_t *p_tom = human_init(&tom, "tom", 100);
human_t *p_lee = human_init(p_lee_mem, "lee", 100);
/* 销毁对象 */
human_deinit(p_john);
human_deinit(p_jen);
human_deinit(p_jack);
human_deinit(p_tom);
human_deinit(p_lee);
free(p_lee_mem);
/* 注意:需要用户释放动态申请的对象内存 */
}
4结论
本文通过使用C语言实现Human类的实例化,讨论了如何使用C语言来实现类的实例化。在C++等面向对象语言中对类做了原生的支持,使用new这类关键字即可实例化一个对象。尽管C语言并不支持new,但是通过对实例化过程的分析和拆分,也能实现实例化。
参考文献
[1] 百度. 百度百科/面向对象[EB/OL].(2016-08-08).http://baike.baidu.com/link?url=6XlXEOSlrKn87S7SJv4 UWSX7EjstoDVm wJ13OAod XUrUrnZkVg3ntPFir Ey5c6mqOb ZZOevQI6K3Ungq1Mq.