如何使用C语言的面向对象

我们都知道,C++才是面向对象的语言,但是C语言是否能使用面向对象的功能?

(1)继承性

1 typedef struct _parent
2 {
3 int data_parent;
4 }Parent;
5 typedef struct _Child
6 {
7 struct _parent parent;
8 int data_child;
9 }Child;

 在设计C语言继承性的时候,我们需要做的就是把基础数据放在继承的结构的首位置即可。这样,不管是数据的访问、数据的强转、数据的访问都不会有什么问题。

(2)封装性

class的类成员默认情况下都是private,而struct的成员都是public(不能改变),所以如何让C语言实现封装的功能呢?答案就是函数指针;这在内核中得到了广泛的应用;

1 struct _Data;
2 typedef  void (*process)(struct _Data* pData);
3 typedef struct _Data
4 {
5     int value;
6     process pProcess;
7 }Data;

   封装性的意义在于,函数和数据是绑在一起的,数据和数据是绑在一起的。这样,我们就可以通过简单的一个结构指针访问到所有的数据,遍历所有的函数。封装性,这是类拥有的属性,当然也是数据结构体拥有的属性。

(3)多态性

在C++中,多态通常都是使用虚函数来实现的,但是C语言中并没有虚函数,如何实现重载呢?

答案也显而易见,也是函数指针的扩展,以下面例子为例:

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 
  4 //虚函数表结构
  5 struct base_vtbl
  6 {
  7     void(*dance)(void *);
  8     void(*jump)(void *);
  9 };
 10 
 11 //基类
 12 struct base
 13 {
 14     /*virtual table*/
 15     struct base_vtbl *vptr;
 16 };
 17 
 18 void base_dance(void *this)
 19 {
 20     printf("base dance\n");
 21 }
 22 
 23 void base_jump(void *this)
 24 {
 25     printf("base jump\n");
 26 }
 27 
 28 /* global vtable for base */
 29 struct base_vtbl base_table =
 30 {
 31         base_dance,
 32         base_jump
 33 };
 34 
 35 //基类的构造函数
 36 struct base * new_base()
 37 {
 38     struct base *temp = (struct base *)malloc(sizeof(struct base));
 39     temp->vptr = &base_table;
 40     return temp;
 41 }
 42 
 43 
 44 //派生类
 45 struct derived1
 46 {
 47     struct base super;
 48     /*derived members */
 49     int high;
 50 };
 51 
 52 void derived1_dance(void * this)
 53 {
 54     /*implementation of derived1's dance function */
 55     printf("derived1 dance\n");
 56 }
 57 
 58 void derived1_jump(void * this)
 59 {
 60     /*implementation of derived1's jump function */
 61     struct derived1* temp = (struct derived1 *)this;
 62     printf("derived1 jump:%d\n", temp->high);
 63 }
 64 
 65 /*global vtable for derived1 */
 66 struct base_vtbl derived1_table =
 67 {
 68     (void(*)(void *))&derived1_dance,
 69     (void(*)(void *))&derived1_jump
 70 };
 71 
 72 //派生类的构造函数
 73 struct derived1 * new_derived1(int h)
 74 {
 75     struct derived1 * temp= (struct derived1 *)malloc(sizeof(struct derived1));
 76     temp->super.vptr = &derived1_table;
 77     temp->high = h;
 78     return temp;
 79 }
 80 
 81 
 82 
 83 int main(void)
 84 {
 85 
 86     struct base * bas = new_base();
 87     //这里调用的是基类的成员函数
 88     bas->vptr->dance((void *)bas);
 89     bas->vptr->jump((void *)bas);
 90 
 91 
 92     struct derived1 * child = new_derived1(100);
 93     //基类指针指向派生类
 94     bas  = (struct base *)child;
 95 
 96     //这里调用的其实是派生类的成员函数
 97     bas->vptr->dance((void *)bas);
 98     bas->vptr->jump((void *)bas);
 99     return 0;
100 }

 综上所述,可以实现C语言的面向对象功能;

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏java初学

4.4 静态域与静态方法

2627
来自专栏xingoo, 一个梦想做发明家的程序员

【java开发系列】—— 嵌套类与内部类

嵌套类与内部类在java中使用的很广泛,为了避免难以理解,这里用了几个小例子,说明它的用法。   嵌套类与内部类的结构如下图 ?   静态嵌套类     ...

1868
来自专栏Golang语言社区

Golang语言--一些基础用法

range类似迭代器操作,返回 (索引, 值) 或 (键, 值)。其可以使用的对象包括string,array/slice,map,channel。其中stri...

3317
来自专栏Zephery

2017-03-10学习笔记

1.Integer和int,装箱拆箱 1、基本型和基本型封装型进行“==”运算符的比较,基本型封装型将会自动拆箱变为基本型后再进行比较,因此Integer(0)...

3548
来自专栏行者常至

004.golang 常量与运算符

Go虽然保留了指针,但与其它编程语言不同的是,在Go当中不 支持指针运算以及”->”运算符,而直接采用”.”选择符来操作指针 目标对象的成员

841
来自专栏Java帮帮-微信公众号-技术文章全总结

Java面试系列10

Java面试系列10 1 Set里的元素是不能重复的,那么用什么方法来区分重复与否呢? 是用==还是equals()? 它们有何区别? Set里的元素是不能重...

2667
来自专栏java初学

4.3 用户自定义类

35216
来自专栏Golang语言社区

【基础篇】Go 语言范围(Range)

Go 语言范围(Range) Go 语言中 range 关键字用于for循环中迭代数组(array)、切片(slice)、通道(channel)或集合(map)...

36116
来自专栏javathings

Java 8 中的拉姆达表达式是什么?

拉姆达表达式就是一个匿名函数。在 C#中,拉姆达表达式是一个委托类型,因此拉姆达表达式可以赋值给一个委托变量。 Java 中,没有委托,Java 的设计者只能...

934
来自专栏数据处理

单例

1284

扫码关注云+社区