if ( 无所不能的c语言 + 面向对象思维 == c++ ) {
printf("Select what?\n");
}
object-oriented programming now...
void *a = new(String, "a");
void *b = new(String, "b");
void *aa = clone(a);
我们关心的是:将一个自定义的结构体初始化,而结构体要有自己独立的初始化方式。
那么,new()就要有一定的通用性。new()的通用性如何实现?
/* 隐藏参数的类型,采用不定参 */
void *new(const void *_class, ...)
{
const struct Class *class = _class;
void *p = calloc(1, class->size); //struct String空间申请
assert(p);
*(const struct Class**)p = class; //p指向struct String,指向String的Class实体
/**
* p->struct String --> struct Class
*/
if(class->ctor)
{
va_list ap;
va_start(ap, _class);
p = class->ctor(p, &ap); //构造函数,回调自己的构造函数。回调函数也是c实现面向对象设计的关键
va_end(ap);
}
return p;
}
p = class->ctor(p, &ap); 该函数的使用说明之前我们已给回调函数赋值。也就是new()之前我们该做些什么。
先定义通用类(结构体):
struct Class {
size_t size;
void *(*ctor)(void *self, va_list *app);
void *(*dtor)(void *self);
void *(*clone)(const void *self);
int (*differ)(const void *self, const void *b);
};
通用类该包括什么:
自定义类的部分特征,
自定义类的操作函数。
因为通用,所以不能限制“类型”;对于自定义类的操作,参数个数也不可限制。
因为通用,也不能预知我们自定义的结构体。
但,自定义结构体的大小还是“通用的”,也就是说,这里自定义类的普遍特征暂时只有size。
那么,第一步,初始化出一个我们自己的实体:String
static const struct Class _String = {
sizeof(struct String),
String_ctor,
String_dtor,
String_clone,
String_differ
};
const void *String = &_String;
回调函数指针指向的具体的操作函数,例如:
ctor = String_ctor,
而String_ctor定义在自定义的.c或.h文件中。
/*构造函数*/
static void *String_ctor(void *_self, va_list *app)
{
/**
* 具体的String函数中才出现struct String
* 对外隐藏结构体特征
*/
struct String *self = _self;
const char *text = va_arg(*app, const char*);
self->text = malloc(strlen(text) + 1);
assert(self->text);
strcpy(self->text, text); //把app字符串拷贝到新的String里
return self;
}
如此,通用类中的class->ctor(p, &ap)有了具体的含义。
总结:
关键理解定义通用类(结构体)的技巧:
自定义类有哪些普遍特征:通用的参数,通用的操作。
注意:隐藏自定义类的结构体特点。
通用类中只分配自定义类的空间,至于对该空间的具体操作,由回调函数指向的“自定义类操作”具体执行。
示例代码:
通用类:
1 #ifndef _SET_H_
2 #define _SET_H_
3
4 #include <assert.h>
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <stdarg.h>
8
9 struct Class {
10 size_t size;
11
12 void *(*ctor)(void *self, va_list *app);
13 void *(*dtor)(void *self);
14 void *(*clone)(const void *self);
15 int (*differ)(const void *self, const void *b);
16 };
17
18
19 /*--------------------------------------------------------------*/
20
21 /* 隐藏参数的类型,采用不定参 */
22 void *new(const void *_class, ...)
23 {
24 const struct Class *class = _class;
25 void *p = calloc(1, class->size); //struct String空间申请
26
27 assert(p);
28 *(const struct Class**)p = class; //p指向struct String,指向String的Class实体
29
30 /**
31 * p->struct String --> struct Class
32 */
33
34 if(class->ctor)
35 {
36 va_list ap;
37
38 va_start(ap, _class);
39 p = class->ctor(p, &ap); //构造函数,回调自己的构造函数。回调函数也是c实现面向对象设计的关键
40 va_end(ap);
41 }
42
43 return p;
44 }
45
46
47 void delete(void *self)
48 {
49 const struct Class **cp = self;
50
51 if (self && (*cp) && (*cp)->dtor) {
52 self = (*cp)->dtor(self);
53 }
54
55 free(self);
56 }
57
58
59 int differ(const void *self, const void *b)
60 {
61 const struct Class *const *cp = self;
62 assert(self && *cp && (*cp)->differ);
63
64 return (*cp)->differ(self, b);
65 }
66
67
68 void *clone(const void *self)
69 {
70 const struct Class *const *cp = self;
71 assert(self && *cp && (*cp)->clone);
72
73 return (*cp)->clone(self);
74 }
75
76
77
78
79 size_t sizeOf(const void *self)
80 {
81 const struct Class *const *cp = self;
82 assert(self && (*cp));
83
84 return (*cp)->size;
85 }
86
87
88 #endif
自定义类:
1 #ifndef _STRING_H_
2 #define _STRING_H_
3
4 #include <stdarg.h>
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
8
9 #include "Set.h"
10
11 static void *String_ctor(void *_self, va_list *app);
12 static void *String_dtor(void *_self);
13 static void *String_clone(const void *_self);
14 static int String_differ(const void *_self, const void *_b);
15
16 const void *String;
17
18
19 struct String {
20 const void *class;
21 char *text;
22 };
23
24
25
26 /*构造函数*/
27 static void *String_ctor(void *_self, va_list *app)
28 {
29 /**
30 * 具体的String函数中才出现struct String
31 * 对外隐藏结构体特征
32 */
33 struct String *self = _self;
34 const char *text = va_arg(*app, const char*);
35
36 self->text = malloc(strlen(text) + 1);
37 assert(self->text);
38
39 strcpy(self->text, text); //把app字符串拷贝到新的String里
40
41 return self;
42 }
43
44 /*构析函数*/
45 static void *String_dtor(void *_self)
46 {
47 struct String *self = _self;
48
49 free(self->text);
50 self->text = 0; //清除String结构体text内容
51
52 return self;
53 }
54
55 /*复制一个新的类实体*/
56 static void *String_clone(const void *_self)
57 {
58 const struct String *self = _self;
59
60 return new(String, self->text);
61 }
62
63 static int String_differ(const void *_self, const void *_b)
64 {
65 const struct String *self = _self;
66 const struct String *b = _b;
67
68 if (self == b) {
69 return 0;
70 }
71
72 if(!b || b->class != String) {
73 return 1;
74 }
75
76 return strcmp(self->text, b->text);
77 }
78
79 static const struct Class _String = {
80 sizeof(struct String),
81 String_ctor,
82 String_dtor,
83 String_clone,
84 String_differ
85 };
86
87
88 const void *String = &_String;
89
90 #endif
主函数:
1 /**
2 * OOC设计
3 */
4
5
6
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10
11 #include "String.h"
12
13 int main(void)
14 {
15 /**
16 * 我们关心的是:将一个自定义的结构体初始化
17 * 而结构体要有自己独立的初始化方式
18 * 那么,new()就要有一定的通用性
19 * new()的通用性如何实现?
20 */
21
22 void *a = new(String, "a");
23 void *b = new(String, "b");
24 void *aa = clone(a);
25
26
27 printf("sizeOf(a) == %u\n", sizeOf(a));
28
29 if (differ(a, b)) {
30 puts("ok");
31 }
32 if (differ(a, aa)) {
33 puts("differ?");
34 }
35 if (a == aa) {
36 puts("clone?");
37 }
38
39 delete(a);
40 delete(b);
41 delete(aa);
42
43 return 0;
44
45 }