用C语言实现继承的研究
2017-01-09杨韬
杨 韬
(广州致远电子股份有限公司,广东 广州 510660)
用C语言实现继承的研究
杨 韬
(广州致远电子股份有限公司,广东 广州 510660)
C语言在嵌入式软件开发中被广泛使用,但由于开发人员和应用场景等原因,面向对象、设计模式等优秀的软件开发方法始终没有很好地运用起来。时至今日,物联网等应用的兴起给嵌入式软件开发带来新的挑战,而传统的面向过程开发方法已经难以支撑这些复杂的应用。因此,有必要在嵌入式软件开发中引入面向对象、设计模式等优秀的软件开发方法。面向对象是现在软件方法的根基,继承是面向对象的三大特性之一,本文结合C语言的特性,对使用C语言实现继承进行了讨论。
C语言;面向对象;类;继承
0 引言
物联网等应用的兴起,给嵌入式软件开发带来新的挑战,而传统的面向过程开发方法已经难以支撑这些复杂的应用。因此,有必要在嵌入式软件开发中引入面向对象、设计模式等优秀的软件开发方法。在C++等面向对象语言中对类做了原生的支持,提供了class这一数据类型,能够很自然地支持继承这一面向对象特性。尽管C语言并不支持class,但是能够通过一些特殊的处理来模拟继承,本文将讨论如何使用C语言来实现继承这一面向对象特性。
1 基本概念[1]
1.1 类
面向对象有三大特性:封装、继承、多态,这些特性主要通过类来体现。类就是一个封装了属性以及相关操作的代码的逻辑实体。
类具有属性,它是对象状态的抽象,用数据结构来描述类的属性。
类具有方法,它是对象行为的抽象,用方法名和实现该操作的方法来描述。
除了封装属性和操作外,类还具有访问控制的能力,比如,某些属性和方法可以是私有的,不能被外界访问。通过访问控制,能够对内部数据提供不同级别的保护,以防止外界意外地改变或使用了私有部分。不同的编程语言提供的访问控制等级不尽相同,但都有公有、私有两个等级。
类是抽象的数据类型,在内存中并不存在(Python等动态语言除外),只有类的实例存在于内存中。
1.2 继承
在定义一个类的时候,可以在一个已经存在的类的基础上进行,新的类自动继承已存在类的公有属性和方法,在此基础上可以添加新的属性或方法,这种特性就是继承。被继承的类称作父类或基类,继承而得到的新类称作子类或派生类。通过继承可以使开发的软件具有扩展性,简化了类的创建工作量,提高了代码复用性。
图1 继承
图1为类继承的UML图,图中定义了两个类,两个类用空心三角箭头连接,箭头指向的就是父类Human,箭尾就是子类Chinese。Chinese类继承了Human类,Chinese类自动拥有Human的公有属性和方法(即name、buy()和talk()),此外,Chinese类新添加了方法play_mahjong()。通俗点描述就是:中国人是人类,有名字,能够讲话和购物,除此之外,还能打麻将。
继承分为单重继承和多重继承:子类只继承一个父类,称为单重继承,如图1所示;子类继承多个父类,称为多重继承,如图2所示。为了避免二义性,不推荐使用多重继承,本文只讨论单重继承。
图2 多重继承
2 类的C语言实现
在C语言中可以使用.c、.h和结构体来实现类,以图1中Human类为例,可以使用human.h、human.c、struct human三个元素来完成封装,human.c为human.h中函数声明的实现,本文不讨论这些细节,只给出human.h的关键代码片段:
程序清单1 Human类C语言实现
// 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);
3 继承的C语言实现
3.1 C语言不能实现严格的继承
一种常见的用C语言实现继承的方法如下面的代码所示:
/* 父类 /基类*/
struct parent {
int a;
};
/* 子类/派生类 */
struct child {
struct parent base; /* 第一个成员为基类 */
int b;
};
void foo (void)
{
struct child foo;
struct child *p_child;
struct parent *p_parent;
p_child = &foo;
p_parent = (struct parent *)p_child;
/* 将子类转换为父类 */
p_parent->a = 100; /* 访问父类成员 */
}
上面的代码中定义了一个父类和子类,foo()函数中实例化了一个子类对象,使用强制类型转换将子类对象的指针p_child转换为父类指针p_parent,如此达到了访问其父类成员的效果。此方法有明显的缺陷——使用了强制类型转换,而在C语言编程中是要避免使用强制类型转换的。如果要得到子类的父类,推荐下面这种更安全的方法:
p_parent = &p_child->base;
对于很多面向对象编程语言来说,子类对象调用父类的属性方法不需要显式转型,而C语言做不到这一点,比如,不能通过p_child->a直接访问父类的属性,因此,严格意义上说“C语言不能实现严格的继承”。
3.2 用C语言实现继承
在前面一节中指出“C语言不能实现严格的继承”,尽管如此,由于继承在软件设计中时有使用,因此用C语言实现继承仍是必要的。尽管继承实现的效果不如C++等面向对象语言那么完美,但还是可以达到实用程度的。
以图1为例,Human为父类,Chinese为基类。Human类的实现请参考程序清单1,Chinese类的实现(chinese.h)请参考程序清单2,chinese.c为chinese.h中函数声明的实现,本文不讨论这些细节。
程序清单2 Chinese类C语言实现
#include "human.h"
typedef struct chinese {
human_t super;
const char *city;
} chinese_t;
#define CHINESE_TO_HUMAN(p_chinese)
chinese_t *chinese_init (chinese_t *p_this, const char *name, int money, const char *city);
chinese_t *chinese_create(const char *name, unsigned int money, const char *city);
void chinese_play_mahjong (chinese_t *p_this);
void chinese_deinit (chinese_t *p_this);
void chinese_delete (chinese_t **pp_this);
Chinese类继承Human类体现在struct chinese 结构体中嵌入了其父类struct human成员,但这并不是完美的继承,如果要访问父类的属性和方法,需要先调用CHINESE_TO_HUMAN()将子类指针转型为父类指针。需要注意的是CHINESE_TO_HUMAN()并没有使用强制类型转换,这意味着struct chinese的成员super可以放在任意位置,大大提高了使用的安全性和灵活性。程序清单3展示了继承相关特性的使用。
程序清单3 继承的使用
chinese_t xiaoming, *p_xiaoming;
human_t *p_human;
p_ xiaoming = chinese_create(
"XiaoMing", 100, "Beijing"); // 实例化子类
p_human = CHINESE_TO_HUMAN(p_ xiaoming);
// 向上转型,得到父类引用
human_talk(p_human, "Ni Hao! "); // 调用父类方法
chinese_play_mahjong(p_laowang); // 调用子类方法
4 结论
本文通过使用C语言实现Chinese类对Human类的继承,讨论了如何使用C语言来实现继承。在C++等面向对象语言中对类做了原生的支持,能够很容易地实现。尽管C语言不能实现严格意义上的继承,但是通过在一个结构体中嵌入另一个结构体的方式,也能达到继承的效果,与其他面向对象语言不同的是,调用父类方法时需要显式转型。
[1] 百度百科. 面向对象[EB/OL].(2012-12-12)[2016-08-08]http://baike.baidu.com/link?url=6XlXEOSlrKn87S7SJv4U WSX7EjstoDVm-wJ13OAod-XUrUrnZkVg3ntPFir-Ey5c6mqObZZ OevQI6K3Ungq1Mq.
Research on the implementation of inheritance with C-language
Yang Tao
(Guangzhou Zhiyuan Electric Co., Ltd., Guangzhou 510660, China)
C-language is widely used in embedded software development. But because of some reasons of developers and application scenarios, object-oriented software development methods, design patterns and other outstanding have not made good use. Today, the rising of Internet of Things and other applications, brings 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, and inheritance is one of the three characteristics of object-oriented. Combining with the characteristics of C-language, using C language to achieve inheritance is discussed in this paper.
C-language; object-oriented; class; inheritance
TP312
A
10.19358/j.issn.1674- 7720.2016.24.005
杨韬. 用C语言实现继承的研究[J].微型机与应用,2016,35(24):16-18.
2016-09-15)
杨韬(1986-),男,学士,工程师,主要研究方向:嵌入式系统、软件工程、软件方法。