C语言面向对象编程 - 继承

使用C语言基于面向对象的编程思想进行编程

上一篇文章主要讲述了 C 语言面向对象编程 – 封装的简单概念和实现。上一篇文章的具体内容,可以查看以下链接:


C 语言面向对象编程 - 封装 


本篇文章继续来讨论一下,如何使用 C 语言实现面向对象编程的一个重要特性:继承。


继承就是基于一个已有的类(一般称作父类或基类),再去重新声明或创建一个新的类,这个类可以称为子类或派生类。子类或派生类可以访问父类的数据和函数,然后子类里面又添加了自己的属性和数据。在 C 语言里面,可以通过结构体嵌套的方式去实现类的单继承(暂不考虑多重继承),但有一点注意事项,就是在结构体嵌套时,父类对象需要放在结构体成员的第一个位置。


现在,我们基于已有的 coordinate 类作为父类,再重新定义一个 rectangle 派生类。在上一篇文章代码的基础上,我们修改一下父类 coordinate,把操作函数通过函数指针的方式封装在结构体内,让对象的封装程度进一步提高。修改后的父类coordinate代码,如下所示:


头文件 coordinate.h 

attachments-2020-05-b1Suu4Oo5ec09e78143d9.png在头文件 coordinate.h 里,声明一个位置类,类里面提供了坐标属性 x 和 y,还提供了属性的操作函数指针。头文件对外提供 coordinate_init  和  coordinate_uninit  两个函数,用来初始化对象和解除初始化。


源文件 coordinate.c 

attachments-2020-05-cQ4BdLK85ec09e8d59fc8.png

在源文件 coordinate.c 里,属性的操作函数都使用 static 进行声明,只能在该源文件调用函数,不允许外部调用。在函数 coordinate_init 中,主要进行了属性赋值,并注册操作函数指针,后面可以直接通过函数指针对操作函数进行调用。在函数coordinate_uninit 中,主要是清除各个属性的赋值。


至此,整个父类 coordinate 修改完成,父类把属性和属性的操作函数都封装在结构体内,其封装程度已经比较高,外部不能直接调用父类的属性操作函数,必须通过函数指针的方式进行调用。


接下来,我们基于父类 coordinate ,重新声明一个子类 rectangle ,子类在头文件中的声明,如下所示:


头文件 rectangle.h 

attachments-2020-05-VzePO1s25ec09e9c0835f.png


源文件 rectangle.c

attachments-2020-05-VsZrXTQU5ec09f1edc193.png


在头文件 rectangle.h 里面,通过include包含了父类coordinate的接口,并创建了一个新的结构体,用于声明一个 rectangle 类,这个结构体把父类 coordinate 放在了第一个成员的位置,同时新增了自己的两个属性,宽度width和高度height。


rectangle_create 函数用于创建一个 P_RECTANGLE_T 类型的对象,并为其分配内存空间。分配成功后,对调用父类 coordinate_init函数,对父类的各种属性进行初始化,并同时对自身的属性 width 和 height 进行初始化,最后返回创建成功后的对象指针。


rectangle_destroy 用于父类对象属性的解除初始化,并为对象属性重新分配默认值,释放之前申请的内存空间,销毁 rectangle 对象。


从头文件 rectangle.h 和源文件 rectangle.c 可以看出,子类 rectangle 是基于其父类 coordinate 进行声明和构建的,因为矩形rectangle除了 width 和 height 属性外,还包含了坐标 x 和 y 属性。


把父类放在结构体成员的第一个位置,是由于结构体内存的连续性,可以很安全地进行强制类型转换。举个例子:假如一个函数要求传入的参数是 COORDINATE_T 类型,但可以通过强制类型转换,传入 RECTANGLE_T 类型的参数,具体的使用方法,可以查看以下测试函数。

attachments-2020-05-mzUCoZ9f5ec09f34df327.png

测试函数的运行效果,如下图所示:

attachments-2020-05-UbnYoYrn5ec09f3bc055d.png
通过上述代码的测试,可以总结出以下几点内容:

1、外部函数可以通过子类直接使用父类的各个成员,但只能通过子类结构体的第一个成员来访问。

2、父类放在子类结构体的第一个位置,由于结构体内存的连续性,因此可以通过强制类型转换来直接访问。

3、由于C语言结构体的特性,即使子类存在与父类同名的函数,父类的函数不会被子类的函数覆盖和重写,因此,子类与父类之间不存在函数重载。


源码下载地址:https://github.com/embediot/my_program_test



感谢阅读!

attachments-2020-05-Ve2pNPlz5ec09e1c3a2ad.jpg



  • 发表于 2020-05-17 10:21
  • 阅读 ( 198 )
  • 分类:经验分享

你可能感兴趣的文章

相关问题

0 条评论&回复

请先 登录 后评论
helloworld
helloworld

嵌入式物联网技术开发者

8 篇文章

作家榜 »

  1. 百问网-周老师 18 文章
  2. st_ashang 14 文章
  3. 渐进 12 文章
  4. zxq 11 文章
  5. helloworld 8 文章
  6. 谢工 5 文章
  7. Litchi_Zheng 5 文章
  8. 星星之火 5 文章