C语言的对象化模型(RT-Thread)

( What's RT-Thread? )
面向对象的特征主要包括: 
• 封装,隐藏内部实现
• 继承,复用现有代码
• 多态,改写对象行为
采用C语言实现的关键是如何运用C语言本身的特性来实现上述面向对象的特征。
封装
        封装是一种信息隐蔽技术,它体现于类的说明,是对象的重要特性。封装使数据和加工该数据的方法(函数)封装为一个整体,以实现独立性很强的模块,使得用户只能见到对象的外特性(对象能接受哪些消息,具有那些处理能力),而对象的内特性(保存内部状态的私有数据和实现加工能力的算法)对用户是隐蔽的。封装的目的在于把对象的设计者和对象者的使用分开,使用者不必知晓行为实现的细节,只须用设计者提供的消息来访问该对象。
        在C语言中,大多数函数的命名方式是动词+名词的形式,例如要获取一个semaphore,会命名成take semaphore,重点在take这个动作上。在RT-Thread系统的面向对象编程中刚好相反,命名为rt sem take,即名词+动词的形式,重点在名词上,体现了一个对象的方法。另外对于某些方法,仅局限在对象内部使用,它们将采用static修辞把作用范围局限在一个文件的内部。通过这样的方式,把一些不想让用户知道的信息屏蔽在封装里,用户只看到了外层的接口,从而形成了面向对象中的最基本的对象封装实现。
        一般属于某个类的对象会有一个统一的创建,析构过程。在RT-Thread中这些分为两类(以semaphore对象为例):
• 对象内存数据块已经存在,需要对它进行初始化 – rt_sem_init;
• 对象内存数据块还未分配,需要创建并初始化 – rt_sem_create。
        可以这么认为,对象的创建(create)是以对象的初始化(init)为基础的,创建动作相比较而言多了个内存分配的动作。
        相对应的两类析构方式:
• 由rt_sem_init初始化的semaphore对象 – rt_sem_detach;
• 由rt_sem_create创建的semaphore对象 – rt_sem_delete.
继承
        继承性是子类自动共享父类之间数据和方法的机制。它由类的派生功能体现。一个类直接继承其它类的全部描述,同时可修改和扩充。继承具有传递性。继承分为单继承(一个子类只有一父类)和多重继承(一个类有多个父类,当前RT-Thread的对象系统不能支持)。类的对象是各自封闭的,如果没继承性机制,则类对象中数据、方法就会出现大量重复。继承不仅支持系统的可重用性,而且还促进系统的可扩充性。
类似的实现代码如下程序清单:
 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
/*父类*/
struct parent_calss
{
     int a, b;
     char *c;
};

/*子类*/
struct child_class
{
     struct parent_calss p;
     int a, b;
};

/*操作示例函数*/
void fun( void)
{
     struct child_class child, *child_ptr;
     struct parent_calss *parent_ptr;
    child_ptr = &child;
    parent_ptr = ( struct parent_ptr *) &child;
    parent_ptr->a =  1;
    parent_ptr->b =  2;
    parent_ptr->c =  "d";
    child_ptr->a =  100;
    child_ptr->b =  200;
}

int main( void)
{
    fun();
     return  0;
}
        在上面代码中,注意child class结构中第一个成员p,这种声明方式代表child class类型的数据中开始的位置包含一个parent class类型的变量。在函数func中obj是一个child class对象,正像这个结构类型指示的,它前面的数据应该包含一个parent class类型的数据。在第21行的强制类型赋值中parent ptr指向了obj变量的首地址,也就是obj变量中的p对象。好了,现在parent ptr指向的是一个真真实实的parent类型的结构,那么可以按照parent的方式访问其中的成员,当然也包括可以使用和parent结构相关的函数来处理内部数据,因为一个正常的,正确的代码,它是不会越界访问parent结构体以外的数据。
        经过这基本的结构体层层相套包含,对象简单的继存关系就体现出来了:父对象放于数据块的最前方,代码中可以通过强制类型转换获得父对象指针。
多态
        对象根据所接收的消息而做出动作。同一消息为不同的对象接受时可产生完全不同的行动,这种现象称为多态性。利用多态性用户可发送一个通用的信息,而将所有的实现细节都留给接受消息的对象自行决定,如是,同一消息即可调用不同的方法。例如:RT-Thread系统中的设备:抽象设备具备接口统一的读写接口。串口是设备的一种,也应支持设备的读写。但串口的读写操作是串口所特有的,不应和其他设备操作完全相同,例如操作串口的操作不应应用于SD卡设备中。
        多态性的实现受到继承性的支持,利用类继承的层次关系,把具有通用功能的协议存放在类层次中尽可能高的地方,而将实现这一功能的不同方法置于较低层次,这样,在这些低层次上生成的对象就能给通用消息以不同的响应。
        RT-Thread对象模型采用结构封装中使用 函数指针的形式达到面向对象中多态的效果,例如:
 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
/*
*   抽象类parent_class用来向用户提供统一的接口,如读/写,复位,初始化等等。
*   child1_class类比于串口
*   child2_class类比于SD卡
*/

#include <stdlib.h>
#include <assert.h>

/*抽象父类*/
struct parent_calss
{
     int a;
     void (*vfunc)( int a);
};

/*抽象类的方法调用,永远不会被调用*/
void parent_class_vfunc( struct parent_calss *parent_self_ptr,  int a)
{
    assert(parent_self_ptr !=  NULL);
    assert(parent_self_ptr->vfunc !=  NULL);
     /*调用对象本身的虚拟函数*/
    parent_self_ptr->vfunc(a);
}

/*继承自parent_class的子类child1_class*/
struct child1_class
{
     struct parent_calss parent;
     int b;
};
/*子类虚函数的实现*/
static  void child1_class_vfunc( struct child1_class *child1_self_ptr,  int a)
{
    child1_self_ptr->b = a +  10;
}

/*子类的构造函数*/
void child1_class_init( struct child1_class *child1_self_ptr)
{
     struct parent_calss *parent;
     /*强制类型转换获得子类中的父类指针*/
    parent = ( struct parent_calss *)child1_self_ptr;
    assert(parent !=  NULL);
     /*设置子类的虚函数*/
    parent->vfunc = child1_class_vfunc;
}


/*继承自parent_class的子类child2_class*/
struct child2_class
{
     struct parent_calss parent;
     int b;
};
/*子类虚函数的实现*/
static  void child2_class_vfunc( struct child2_class *child2_self_ptr,  int a)
{
    child2_self_ptr->b = a *  10;
}

/*子类的构造函数*/
void child2_class_init( struct child2_class *child2_self_ptr)
{
     struct parent_calss *parent;
     /*强制类型转换获得子类中的父类指针*/
    parent = ( struct parent_calss *)child2_self_ptr;
    assert(parent !=  NULL);
     /*设置子类的虚函数*/
    parent->vfunc = child2_class_vfunc;
}

int main( void)
{
     struct child1_class child1, *child1_ptr;
     struct child2_class child2, *child2_ptr;
     struct parent_calss *parent_ptr;
    
     /*child1_class类比于串口的结构体*/
    child1_ptr = &child1;
    parent_ptr = ( struct parent_calss *)child1_ptr;
    child1_ptr->b =  10;
    child1_class_init(child1_ptr);
    parent_ptr->vfunc(child1_ptr,  20);
    
     /*child2_class类比于SD卡的结构体*/
    child2_ptr = &child2;
    parent_ptr = ( struct parent_calss *)child2_ptr;
    child2_ptr->b =  20;
    child2_class_init(child2_ptr);
    parent_ptr->vfunc(child2_ptr,  20);
    
    getchar();
     return  0;
}

改编自“C语言的对象化模型”一小节,根据自己理解调试代码通过,看注释说明部分和结果应该不难~~~
ps:过几天把老外的Object-Oriented C翻译下~~~


你可能感兴趣的:(C语言的对象化模型(RT-Thread))