设计与实现C/C++young library的方法
设计与实现C/C++young library的方法
本篇着重介绍我在开发young程序库时使用的一些抽象概念,由于程序库的思想衍生自C++ STL,了解C++ STL的读者应该会比较容易理解,而对于仅有C语言使用经历的读者来说,可能读起来就不那
么舒服了。因为我写程序库的主要一个用途就是嵌入式系统编程,而在嵌入式程序设计中大部分都使
用的是C语言和结构式编程的思想,而我在程序库中使用的更多的是Object Oriented Programming和
Generic Programming,所以,我写作本篇的假定对象就是一些在嵌入式系统上从事程序设计而又不
了解STL设计思想的读者,希望他们在阅读完了本篇之后,能够更容易的阅读源码、了解一些不同的
设计思想。
1、Object Oriented Programming
“Object Oriented Programming”通常被翻译为“面向对象的程序设计”,就我个人的意见,
这是一个很让人作呕的翻译!信、达、雅是一个也没有!
“Object Oriented Programming”的中心词是“Object”,“Object”有“物体”的意思,
“物”在汉语是对自然界实体的统称。《说文》云:“物,万物也;牛为大物,天地之数起于牵牛,
故从牛。”而“对象”者,是为何物啊?是BF啊还是GF啊?
“物”的自然特征我们可以称之为该“物”的“属性”,而“物”操纵“属性”的行为我们可
以称之为“物”使用“属性”的“方法”。譬如:人用脚走路。这里,“人”是“物”;“脚”是
“人”所呈现出来的自然特征的一部分,既是“人”的“属性”;“走路”是“人”操纵“属性”
“脚”的行为,既是“人”使用“脚”的“方法”。
为了方便,我们将具有近似“属性”和“行为”的“物”称为一“类”。“物”为实,“类”
为虚。譬如说,你家有一只名叫“蠢一郎”的小犬,你不会说你的小犬蠢一郎是个“狗类”。
Object Oriented Programming其实是一种编程的方法,是程序员将计算机程序设计和自然哲学
相融合后所展现出的一种能力。它要求程序员在编程时从人更容易理解的自然物体这个方向上去进行
思考,而不是把自己想像成一台计算机般去进行思考,这样,可以更好的避免程序设计中出所出现的
错误,写出的程序也更容易让其他人理解。
虽然说,C++、JAVA、C#等编程语言在语言层级就提供了对OOP的支持,但是并不等于说我们在
汇编、C这些在语言层级不提供OOP支持的语言就不能做到,后面我将向各位展示如何在C语言上进行
OOP!
2、Generic Programming
“Generic”是通用化的意思,Generic Programming就是希望能够将一些复杂而又重复性很高
的工作模板化,即只需定义一次即可任意匹配运行。Generic Programming仅仅只是一种设计思想,
理论上和程序设计语言没有什么关系,当然,现实并非如此。
以印刷术为例的话,我们以前针对不同类型实现的具有同样功能的函数,就象最初的雕版印刷
术;而Generic Programming就象技术发展后的活字印刷术。虽然有这样和那样的责难,但是无疑,
Generic Programming是历史的进步!
3、容器(Container)
顾名思义,容器就是一个充满数据的集合。STL中将容器分为序列容器和关联容器,序列容器中
的元素在逻辑上是以序列的方式存储的;而关联容器则不然,存储的数据的逻辑关系依容器的不同而
不同。所有的容器都提供添加、删除、替换三个基本功能,依容器类型的不同还可能提供其他功能,
例如关联式容器可能还提供查找等功能。从某种意义上来说,容器更像一个微型数据库。
4、迭代器(Iterator)
迭代器是能够对容器进行迭代的一种数据类型。每种容器都有与之对应的迭代器。
C++ STL依容器的功能定义了五类迭代器:输入迭代器、输出迭代器、正向迭代器、双向迭代器、
随机访问迭代器。在young程序库中,我只取用了后三类迭代器,即:正向迭代器、双向迭代器和随
机访问迭代器。
按功能由强自弱排序依次为:1、随机访问迭代器;2、双向迭代器;3、正向迭代器。
随机访问迭代器理论上可以对容器的任一元素进行访问,并可对容器进行正向和反
向迭代。指针实际上就是随机访问迭代器中的一种。
双向迭代器可以对前一个和后一个元素进行访问,并可对容器进行正向和反向迭代。
正向迭代器理论上可以在常数时间内对后一个元素进行访问,但是它只可对容器进行正向迭代。
5、memory 和 resource 数据类型
可直接在存储器中进行复制、删除而不会产生副作用的数据类型,我简单的称之为memory类型。
例如C/C++所有内建的数据类型:int、float;以及诸如:
struct coordinate
{
int x;
int y;
};
这样的简单数据结构。这些类型的特点是,在C/C++语言中可以直接使用赋值操作符进行赋值,返还
存储空间的时候也不用对存储的数据进行特殊的处理。
假如我们将“可直接在存储器中进行复制、删除而不会产生副作用的数据类型”定义为一个真命
题的话,那么我简单的它的非真命题称之为resource类型。例如:指向动态分配的存储空间的指针;
文件指针;控制串口的handle等。这些类型的特点是在C/C++语言中要么不能使用语言预定义的赋值
操作符进行赋值,要么返还存储空间的时候必须对存储的数据进行特殊的处理,要么必须进行特殊的
初始化。
以上是我为了在C语言中更好的实现GP而简单定义的,实际上,以C++的眼光来看的话,memory这
类数据类型就是所谓的POD(plain of old)类型;而resource类型是需要自定义构造函数、复制构造
函数、重载的赋值操作符、析构函数至少其中一个的数据类型。
针对数据类型的操作,用OOP的术语称为method。所有的类型都具有这些通用的操作:(1)初始化;
(2)未初始化复制;(3)已初始化复制;(4)释放;熟悉C++的读者应该很容易就明白这些函数,它们相
当于C++中的构造函数、复制构造函数、重载的赋值操作符、析构函数。为了提高容器的执行效率,我
又额外“追加”了两个操作:(5)未初始化移动;(6)已初始化移动,关于移动操作,我会在后面进行
讨论。
6、异常安全的函数
在程序库中容器对元素的操作,都是靠传递给容器的函数指针(也被叫做回调函数)来实现的,
对于这些函数指针,我在每个容器的数据结构定义处都有这样一行注释“/* safe function */”!
关于这个,其实所说的不多,就是一条,该函数在运行的过程中不能抛出任何异常,换句话说,该函
数必须能正确、安全地处理任何异常情况,并正常返回调用处。
这是程序库对使用者的强制约定,使用者必须遵守这个约定才能够得到容器的安全保证!