当前正运用C开展项目,先前习惯使用C++,再回过头使用C着实有些不太适应。C++语言里自带面向对象支持,像封装、继承、多态等这类面向对象的基本特征。C原本是面向过程的语言,自身不存在内建这些特性,不过我们依旧能够借助C语言本身已有的特性来达成面向对象的一些基本特征。接下来我们会逐一详细讲述封装、继承、多态、纯虚类等面向对象特性在C语言里怎样实现,并且给出实例。
这篇文章中我们先说封装和继承。
先来看封装。
所谓封装,通俗来讲,是指一个姑娘化了妆,仅让你瞧见她愿让你看的那一面,至于内里是否刮了骨、垫了别的,并不给你看。提及封装便要说隐藏,这是与兄弟相关的概念;实际上我觉得隐藏是更深层次的封装,全然不让你看到,而封装或许犹如犹抱琵琶半遮面。封装在C++语言里有protected、private关键字在语言层面予以支持,而C语言中不存在这些。C有结构体(struct),实际上能够达成封装与隐藏。
在QT当中,为了能够将一个类的具体实现更好地进行隐藏,通常情况是,存在一个公开头文件,还存在一个私有头文件,在私有头文件里对实现的内部细节予以定义,在公开头文件里对开放给客户程序员的接口以及公共数据进行定义。去瞧瞧QObject(qobject.h),与之对应的有一个QObjectPrivate(qobject_p.h),其他的状况也是相似的。并且代码框架如下:
QObject{ public: xxx xxx private: QObjectPrivate * priv; };完全能够在C语言里,运用同样的方式去达成封装以及隐藏,仅仅是放置于结构体当中罢了。代码框架如下:
struct st_abc_private; struct st_abc { int a; xxx; void (*xyz_func)(struct st_abc*); struct st_abc_private * priv; };前面的代码之中,我们仅仅是进行了结构体 struct st_abc_private 的前向声明,并没有人清楚明确晓得它内部确切究竟是什么样子的事物。假设,struct st_abc所对应的头文件为abc.h,那么,将st_abc_private的声明放置于abc_p.h里,abc.c文件包含abc_p.h,那么,在实现struct st_abc的函数指针xyz_func时,怎样去使用struct st_abc_private,客户程序员根本不需要知道。
这般去做所具备的好处是明显能够看见的,除开预先定义好的接口之外,客户程序员根本完全不需要晓得涉及的实现细节,就算实现经历了重构且完全重新再来一遍,客户程序员也无需去予以关注,甚至与之相应的模块连贯重新编译都不需要,因为abc.h从开始到结束都未曾有过改变。
上面写的代码存在着一个方面的问题,客户程序员要怎样才能够获取到struct st_abc的一个实例呢,他并不清楚struct st_abc_private是怎样去进行实现的呀。C这个编程语言里面是没有构造函数那种东西存在的,所以只能是我们自己来提供了:我们能够在abc.h这个文件里面去声明一个跟构造函数较为相似的函数从而生成struct st_abc的实例,它的名字就被称作新的abc(new_abc),函数的原型情况如下:
struct st_abc * new_abc();提及实现,我们将其放置于abc.c里,客户程序员不存在知晓的必要。与之相对的,存在一个好似析构函数这般的函数,其原型如下:
void delete_abc(struct st_abc *);到现在为止,封装和隐藏就实现了,而且很彻底。接下来看继承。
何为继承呢?于面向对象层面不再阐述,仅讲语法层面。在语法层面谈起,继承乃是派生类具备父类的数据、方法,还增添了些许自身的内容,即所谓子承父业并予以发扬光大。于C语言里能够借助结构体的包含去达成继承关系。代码框架为如下这般:
struct st_base{ xxx; }; struct st_derived{ struct sb_base base; yyy; };代码方面呈现出的就是这般简易,然而存在一点需要予以留意,其一便是在派生类(结构体)当中务必将父类类型的成员放置于首位。
承接从语法层面去考究,存在数据成员、函数,数据成员借助上面的方式会自行“承继”,至于函数,于结构体里体现为函数指针,实际上同样是一个数据成员,仅是个指针罢了,也会自动“承继”。之所以仍要在此处罗列予以说明,是由于C++之中存有一个相当关键的概念:重载。要在C里完整达成会有些繁杂。
重载,我们常说的重载大概有三种含义:
平常我们在进行交流的时候,通常不会去明确地区分上面那三种类型的重载,在这里呢,出于习惯,同样也不会作区分。
好了,第一篇就到这里,有时间会往下续。