编程语言应用

首页 » 常识 » 常识 » C语言陷阱与技巧第29节,很多程序员不知
TUhjnbcbe - 2023/7/22 21:42:00
贵阳治疗白癜风的医院 http://pf.39.net/bdfyy/bdfal/171105/5817680.html

之前两节探讨了C语言进行“面向对象”编程的可能性。现在已经了解,结合C语言的指针和结构体语法,基本能够实现对象语法最核心的部分,即成员函数和成员变量。另外,上一节讨论了如何利用指针,将公开的成员变量,封装成private(私有)变量,由此也可以看出C语言指针语法的强大。

共同功能

上一节已经讨论,将不同的模块封装成独立的类是方便的,不过在实际的C语言项目开发中,即使是独立的类之间也是极有可能存在通用功能的。例如各个类都用得到时间,所以在定义类时,需要为各个类都添加获取时间的成员函数:

structclass1{//...long(*get_time)();};structclass2{//...long(*get_time)();};上面这段C语言代码定义了class1和class2两个类作为示例,如果class1和class2对时间的要求并没有什么不同,那我们可以让二者的get_time函数指针指向同一个函数,例如:

longget_time(){//...}structclass1c1={...,get_time};structclass1c2={...,get_time};这么做无可厚非,反正实现了class1和class2的共同功能。不过,在实际的C语言项目开发中,更常见的情况是,有些类拥有的共同功能不止一个。

例如class1和class2不仅都需要获取时间,也都需要打印功能,这样一来,在定义class1和class2时,就需要再新增一个成员函数,相关C语言代码如下:

structclass1{//...long(*get_time)();void(*print)(void*data);};structclass2{//...long(*get_time)();void(*print)(void*data);};如果class1和class2需要的打印功能没有差异,那么在初始化对象时,就可以像上面的get_time一样,让print指向已经实现的打印函数就可以了。

longget_time(){//...}voidmyprint(void*data){//...}structclass1c1={...,get_time,myprint};structclass1c2={...,get_time,myprint};

C语言“类”的继承

乍一看,上面这种操作方法没有什么毛病,相同功能实际由一个函数完成,没有造成资源浪费。但是对于类class1和class2本身来说,将自己的独有特性和与其他类共同特性封装在一起,就不太明智了。另外,各个类中有重复的函数指针也是在实际C语言项目开发中应该尽力避免的。

那该怎么办呢?

既然决定进行“面向对象”编程,要解决上述问题,自然应该参考其他具有原生对象语法的高级编程语言。在开发C++程序封装类时,遇到各个类的相同特性,常常将这些相同特性提取出来,作为一个新的类。这个新的类常被称作“父类”,并且通过C++的继承语法,将“父类”的成员函数和成员变量共享给需要的子类。

C语言没有提供原生的对象语法,也没有提供继承语法。但是我们仍然可以使用C语言的指针和结构体语法模拟“父类”概念和“继承”特性。

首先,将各个类的相同特性提取出来,并将这些特性封装为“父类”是简单的。还是以class1和class2为例,它们有两个相同功能:获取时间和打印功能。

structfather{long(*get_time)();void(*print)(void*data);};上述C语言代码将class1和class2的共同功能封装成一个新的类father,也即所谓的“父类”。接下来,只要让class1和class2继承father就可以了,可是C语言没有原生的“继承”语法,该怎样实现这一过程呢?

应明白,继承的目的是为了让子类能够访问父类提供的成员函数和成员变量,虽然C语言没有像C++那样完善的继承语法,但是像提供子类访问父类这种需求还是比较容易实现的:

structclass1{//...structfatherfather;};structclass2{//...structfatherfather;};正如上述C语言代码,直接将father塞入class1和class2其实就可以了。访问父类的成员函数是简单的:

structclass1c1;c1.father.print(data);

一个值得说明的小技巧是,如果father类比较大,占用资源比较多,而C语言程序又没有必要建立多个father副本,则可以将class1和class2中的父类修改为指针:

structclass1{//...structfather*father;};structclass2{//...structfather*father;};这样一来,无论father有多大,class1和class2都能使用一个指针大小的内存空间去索引它。访问父类的成员函数与之前有些许差异:

structclass1c1;c1.father-print(data);到这里,相信读者应该能够发现,结合C语言的结构体和指针,模拟“面向对象”编程的父类继承语法也是轻而易举的,这也从侧面说明了C语言指针的强大。

小结

本节主要讨论了在使用C语言“面向对象”编程中,遇到不同类拥有相同功能的情况。在这种情况下,C语言程序员可以为各个类添加共同功能函数指针。不过更推荐的做法是再封装一次,将相同功能提取出来封装为父类,通过“继承”的方式,让各个类共享父类。当然了,本文讨论的方法与技巧仍属抛砖引玉。

欢迎在评论区一起讨论,质疑。文章都是手打原创,每天最浅显的介绍C语言、linux等嵌入式开发,喜欢我的文章就

1
查看完整版本: C语言陷阱与技巧第29节,很多程序员不知