杨 韬
(广州致远电子股份有限公司,广东 广州 510660)
用C语言实现类封装的研究
杨 韬
(广州致远电子股份有限公司,广东 广州 510660)
多年以来,C语言在嵌入式软件开发中被广泛使用,但由于开发人员和应用场景等原因,面向对象、设计模式等优秀的软件开发方法始终没有很好地运用起来。时至今日,物联网等应用的兴起,给嵌入式软件开发带来新的挑战,而传统的面向过程开发已经难以支撑这些复杂的应用。因此,有必要在嵌入式软件开发中引入面向对象、设计模式等优秀的软件开发方法。面向对象是现代软件方法的根基,面向对象体现在类上,而封装为类的第一大特性。文章以类的封装特性为切入点,结合C语言的特性,讨论了C语言实现类封装的方法,并给出了实例。
C语言;面向对象;类;封装
物联网等应用的兴起,给嵌入式软件开发带来新的挑战,而传统的面向过程开发已经难以支撑这些复杂的应用。因此,有必要在嵌入式软件开发中引入面向对象、设计模式等优秀的软件开发方法。本文首先介绍了面向对象必要的基本概念,然后引入了UML类图,通过使用C语言来实现一个Human类,讨论了如何使用C语言来实现类的封装特性,并给出了对应的分析。
1.1 对象[1]
对象是人们要进行研究的任何事物,从最简单的整数到复杂的飞机等均可看作对象,它不仅能表示具体的事物,还能表示抽象的规则、计划或事件。
对象具有状态,一般用数据值来描述它的状态。
对象还有操作,用于改变对象的状态,对象及其操作就是对象的行为。
对象实现了数据和操作的结合,使数据和操作封装于对象的统一体中。
1.2 面向对象
简而言之,面向对象就是把客观存在或主观抽象的事物(即对象)抽象成类。
所谓抽象就是去异求同,从众多的事物(即对象)中抽取出共同的、本质性的特征,舍弃其非本质的特征。比如香蕉、苹果、哈密瓜等,它们共同的特性就是水果。得出水果概念的过程就是一个抽象的过程。在抽象时,同与不同,取决于从什么角度上来抽象。抽象的角度取决于分析问题的目的。
具有相同特性(数据元素)和行为(功能)的对象的抽象就是类。因此,对象的抽象是类,类的具体化就是对象,也可以说类的实例是对象。
1.3 类
面向对象有三大特性:封装、继承、多态,这些特性主要通过类来体现。类就是一个封装了属性以及相关操作的代码的逻辑实体。
类具有属性,它是对象的状态的抽象,用数据结构来描述类的属性。
类具有方法,它是对象的行为的抽象,用方法名和实现该操作的方法来描述。
除了封装属性和操作外,类还具有访问控制的功能,比如,某些属性和方法可以是私有的,不能被外界访问,通过访问控制,能够对内部数据提供不同级别的保护,以防止外界意外地改变或使用了私有部分。不同的编程语言提供的访问控制等级不尽相同,但都有公有、私有两个等级。
类是抽象的数据类型,在内存中并不存在(Python等动态语言除外),只有类的实例存在于内存中。
在面向对象设计开发中,通常使用UML工具来进行分析设计。比如,可以使用UML类图来描述类。
UML类图很简单,用一个矩形框代表一个类,矩形框内部被隔为三部分:上面部分为类的名字,中间部分为类的属性,下面部分为类的方法。对于属性和方法,还可以使用“+”、“-”修饰符来表示访问权限,“+”为公有属性、“-”为私有属性。
如图1所示,该类图描述了一个名为“Human”的类。“Human”类抽象并封装了“人”;属性“name”是对人姓名的抽象,因为人的姓名是公开的,所以被设置为公有属性;属性“money”是对人所拥有的财富的抽象,因为每个人的财富都不是公开的,所以被设置为私有属性;方法“buy”是对购物这一行为的抽象,方法“talk”是对讲话这一行为的抽象,这两个方法都是社会活动,所以被设置为公有属性。
图1 Human类图
设计类的过程就是抽象的过程,抽象的结果取决于抽象时所站的角度,比如,如果是警察来抽象“Human”,他可能会添加一个“isBadGuy”属性。
UML类图主要用于辅助分析和设计阶段,在设计类时应聚焦在与当前问题有关的重要属性和行为,无关的属性和方法统统去掉,确保UML类图是简洁有效的。除非私有属性或方法会影响到问题的理解或者类的实现,否则UML类图中不要出现私有属性和方法,私有属性通常在实现阶段才会去考虑。
UML类图以及其他UML元素都是辅助软件开发的工具,使用UML进行设计时,只要相关人员能够通过UML图看懂你的设计、不妨碍沟通就可以了,即使用草稿纸来作图也是可以的,所以,不用太过纠结那些细节,且一定要避免过度设计。
很多现代编程语言都有原生的面向对象支持,比如C++、JAVA、Python等,这些编程语言提供了class数据类型,在这些编程语言中类实际上就是一种数据类型,因此能够更好地支持面向对象编程。
实际上,面向对象是与编程语言无关的,更像是一种思想,且不局限于软件开发活动,任何需要分析解决问题的场合都可以使用面向对象。
C语言并没有类的概念,但是可以从类的特性出发,利用C语言的某些特性来实现类的用法。关于类,首先要解决的就是封装问题,类的封装特性需要能够封装属性和方法,还要有访问控制。可以使用.h、.c文件和结构体来完成封装。
下面以图1中Human类的C语言实现为例来叙述C语言的类封装问题,本文使用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);
void human_talk (human_t *p_this, const char *p_words);
void human_buy (human_t *p_this, const char *p_something, unsigned price, unsigned count);
void human_deinit (human_t *p_this);
(1)类名
Human类的名称体现在human.c、human.h以及human.h中所有全局符号的命名上,这些命名全部使用关键字human作为前缀。
(2)属性
Human类的属性体现在自定义类型human_t中,human_t实际上为结构体struct human,它有两个成员:name和_money,分别对应类图中的属性+name和-money,特别留意_money成员前的“_”,这是为了警示类的使用者“此成员为私有属性,不可使用”。
(3)方法
Human类的方法体现在human_talk()、human_buy()这两个函数上,分别对应类图中的方法+buy()和+talk()。此外,还可以注意到有human_init()、human_deinit()这两个函数,分别为Human类的构造、析构方法。构造、析构方法分别用于类对象的初始化和解初始化。
构造函数human_init()需要用户提供Human对象的内存,通过第一个参数p_this传递,对象的内存等价于一个human_t变量。
C语言中可以使用C文件中的static函数实现私有方法,假如Human类有私有方法money_pay(),则其C语言实现如下:
// human.c
static int __human_money_pay (human_t *p_this, unsigned cost)
{ … }
UML类图中一般不会显式地出现构造、析构和私有这三种方法,除非需要在类的构造、析构和实现上有特殊说明。
另外需要注意的是,这几个方法函数的第一个参数都是human_t *类型,且名称为p_this,这是C语言面向对象编程与面向过程的最大不同:p_this为指向类实例(即对象)的指针,所有的方法操作都需要“针对”一个对象,p_this指针由类的构造函数返回,比如,human_init()构造一个Human实例,然后返回指向此实例的p_this指针,然后就可以调用human_talk(p_this, …)等方法对实例进行操作。
(4)访问控制
在Human类的C语言实现中,属性被定义为human_t中的两个成员,而 human_t被定义在用户可见的human.h中,所以human_t是暴露给用户的,因此,从语法上讲,Human类的两个属性是暴露给用户的,即都是公有属性。虽然语法上不能支持私有,但可以在编程规范上设定“私有属性以短下划线“_”开头”,比如“_money”,如此从某种意义上实现了属性的访问控制。
在Human类的C语言实现中,方法被定义为human.c中的函数。公共方法对应的函数都没有“static”关键字,且在human.h中有对应的函数声明。而私有方法对应的函数都有“static”关键字,这些私有方法只能在human.c文件内部调用,对用户不可见。由此可知,C语言本身就能支持方法的访问控制。
本文通过使用C语言实现一个Human类,讨论了如何使用C语言来实现类的封装特性。在C++等面向对象语言中,使用class对类做了原生的支持,使用起来非常简单。尽管C语言并不是原生支持类,但通过语言、概念、规范上的处理,也能实现类的封装特性。用C语言实现类的封装相当于解决了C面向对象的关键第一步,在其基础之上可以引入更多现代软件方法。
[1] 百度. 百度百科/面向对象[EB/OL].[2016-08-08].http://baike.baidu.com/link?url=6XlXEOSlrKn87S7SJv4UW SX7EjstoDVm-wJ13OAod-XUrUrnZkVg3ntPFir-Ey5c6mqObZZ OevQI6K3Ungq1Mq.
Research on the implementation of class encapsulation with C-language
Yang Tao
(Guangzhou Zhiyuan Electric Co. Ltd. , Guangzhou 510660, China)
For many years, C-language is widely used in embedded software development, but because of the developers and application scenarios and other reasons, object-oriented, design patterns and other outstanding software development methods have not been well used. Today, the development of Internet of Things and other applications, has brought new challenges to the development of embedded software, and the traditional process-oriented development has been difficult to support these complex applications. Therefore, it is necessary to introduce object-oriented, design patterns and other excellent software development methods in embedded software development. Object oriented method is the foundation of modern software, object-oriented is embodied in the class, encapsulation is the first major characteristic. In this paper, the characteristics of encapsulation as the starting point, combined with the characteristics of C-language, the method of C-language encapsulation is discussed, and an example is given.
C-language; object-oriented; class; encapsulation
TP312
A
10.19358/j.issn.1674- 7720.2016.21.007
杨韬. 用C语言实现类封装的研究[J].微型机与应用,2016,35(21):24-25,29.
2016-09-01)
杨韬(1986-),男,学士,工程师,主要研究方向:嵌入式系统、软件工程、软件方法。