《C语言下的封装 继承 与多态.docx》由会员分享,可在线阅读,更多相关《C语言下的封装 继承 与多态.docx(10页珍藏版)》请在三一办公上搜索。
1、C语言下的封装 继承 与多态C语言下的封装、继承与多态 上次课,钱SIR提到,Liux下面也有很多用C实现的面向对象的结构。比较感觉兴趣,就在网上查了一些资料,原来C语言模拟实现面向对象语言所具有的特性:多态,继承,封装,也是一件很简单的事儿。并且现在很多开源软件都了用C语言实现了这几个特性,包括大型开源数据库系统postgreSQL,可移植的C语言面向对象框架GObject。 在自己机器上实践了下,感叹C语言的灵活与强大!总结一下,以便交流: 一、基础知识 结构体 结构体可以嵌套,因而可以把一个结构体当成另一个结构体的成员,如: cppview plaincopyprint? 1. stru
2、ct Point 2. int x; 3. int y; 4. ; struct Point int x; int y;cppview plaincopyprint? 1. struct Circle 2. struct Point point_; 3. int radius; 4. ; struct Circle struct Point point_; int radius; ; 该结构体与以下定义完全一样void * 指针是整个 C 语言的精髓所在。而你也一直敬畏着指针,又爱又恨地使用着它。许多教材都告诉你,int *叫做指向整型的指针,而 char *是指向字符型的指针,等等等等不一而
3、足。然而这里有一个另类的指针家族成员void *。不要按照通常的命名方式叫它做指向void 类型的指针,它的正式的名字叫做:可以指向任意类型的指针。 C中的参数个数可变函数 可变参数函数的原型声明: cppview plaincopyprint? 1. type VAFunction(type arg1, type arg2, ); type VAFunction(type arg1, type参数可以分为两部分:个数确定的固定参数和个数可变的可选参数。函数至少需要一个固定参数,固定参数的声明和普通函数一样;可选参数由于个数不确定,声明时用.表示。固定参数和可选参数公同构成一个函数的参数列表。
4、 标准C/C+包含头文件stdarg.h,该头文件中定义了操作不定变量的相关宏: cppview plaincopyprint? 1. void va_start ( va_list arg_ptr, prev_param ); /* ANSI version */ 2. type va_arg ( va_list arg_ptr, type ); 3. void va_end ( va_list arg_ptr ); void va_start ( va_list arg_ptrtype va_arg ( va_list arg_ptr, void va_end ( va_list arg_
5、ptr )在这些宏中,va就是variable argument(可变参数)的意思; arg_ptr 是指向可变参数表的指针; prev_param 指可变参数表的前一个固定参数; type 为可变参数的类型。 va_list 也是一个宏,其定义为typedef char * va_list,实质上是一char型指针。 具体用法可以参考: 二、封装 封装的主要含义是隐藏内部的行为和信息,使用者只用看到对外提供的接口和公开的信息。 在C语言中的实现方法:把私有数据信息放在一个不透明的priv变量或者结构体中,只有类的实现代码才知道priv或者结构体的真正定义。 例如: 头文件: cppview
6、plaincopyprint? 1. /=头文件:Point.h文件= 2. #ifndef POINT_H 3. #define POINT_H 4. typedef struct Point point; 5. typedef struct pointPrivate pointPrivate; 6. struct Point 7. 8. 9. struct pointPrivate *pp; 10. int get_x(point *point_); 11. int get_y(point *point_); 12. point * new_point(int x,int y); 13.
7、14. #endif /=头文件:Point.h文件=#ifndef POINT_H#define POINT_Htypedef struct Point point;typedef struct pointPrivate poist源文件 cppview plaincopyprint? 1. /=C文件:Point.c文件= 2. #include Point.h 3. #include 4. struct pointPrivate; 5. int x; 6. int y; 7. ; 8. 9. int get_x(point *point_) 10. return point_-pp-x;
8、 11. 12. 13. int get_y(point *point_) 14. return point_-pp-y; 15. 16. 17. point* new_point(int x,int y) 18. point* p=(point*)malloc(sizeof(point); 19. p-pp=(pointPrivate*)malloc(sizeof(pointPrivate); 20. p-pp-x=x; 21. p-pp-y=y; 22. return p; 23. /=C文件:Point.c文件=#include Point.h#includestruct pointPr
9、ivate; int x; int y;测试文件: cppview plaincopyprint? 1. int main 2. 3. point* p = new_point(1,2); 4. /printf(x:%d,y:%dn,p-pp-x,p-pp-y); 5. printf(x:%d,y:%dn,get_x(p),get_y(p); 6. int mainpoint* p = new_point(1,/printf(x:%d,y:%dn,printf(x:%d,y:%dn,ge在测试代码中,注释掉的一部分是编译不过的,因为我们已经把pointPrivate结构体的定义隐藏了。而且必须
10、使用new_point来创建point结构对象,否则无法初始化point结构体中的pp成员变量。 有意思的是:这段代码生成的exe文件可能会被360误认为病毒。 三、继承 在C语言中,可以利用“结构在内存中的布局与结构的声明具有一致的顺序”这一事实实现继承。比如我们要设计一个作图工具,其中可能涉及到的对象有Point(点),Circle(圆),由于圆是由点组成的,所有可以看成Circle继承自Point。另外,Point和Circle都需要空间申请,空间释放等操作,所有他们有共同的基类Base。 cppview plaincopyprint? 1. /基类Base的内部头文件Base.r,对外
11、隐藏 2. #ifndef BASE_R 3. #define BASE_R 4. #include 5. struct Base 6. size_t size; 7. void * (* ctor) (void * self, va_list * app);/构造函数 8. void * (* dtor) (void * self); /析构函数 9. void (* draw) (const void * self);/作图函数 10. ; 11. #endif 12. 13. /Point的内部头文件Point.r,对外隐藏 14. #ifndef POINT_R 15. #define
12、 POINT_R 16. struct Point 17. const void * base; /继承Base类,基类指针,放在第一个位置,const是防止修改 18. int x, y; /坐标 19. ; 20. #define x(p) (const struct Point *)(p) - x) 21. #define y(p) (const struct Point *)(p) - y) 22. #endif 23. 24. /Point的头文件Point.h 25. #ifndef POINT_H 26. #define POINT_H 27. extern const void
13、 * Point; /* new(Point, x, y); */ 28. void move (void * point, int dx, int dy); 29. #endif 30. 31. /Point的源文件Point.c 32. #include 33. #include Point.h 34. #include Point.r 35. #include new.h 36. #include Base.r 37. /*Point类自己的构造函数*/ 38. static void * Point_ctor (void * _self, va_list * app) 39. stru
14、ct Point * self = _self; 40. self - x = va_arg(* app, int); 41. self - y = va_arg(* app, int); 42. return self; 43. 44. /*Point类自己的绘图函数*/ 45. static void Point_draw (const void * _self) 46. const struct Point * self = _self; 47. printf(Point at %d,%dn, self - x, self - y); 48. 49. static const struc
15、t Base _Point = 50. sizeof(struct Point), Point_ctor, 0, Point_draw 51. ; 52. const void * Point = & _Point; 53. void move (void * _self, int dx, int dy) 54. struct Point * self = _self; 55. self - x += dx, self - y += dy; 56. 57. 58. /Circle内部头文件Circle.r,对外隐藏 59. #ifndef CIRCLE_R 60. #define CIRCLE
16、_R 61. #include Point.r 62. struct Circle 63. const struct Point _; /继承Point类,需放在第一位 64. int rad; 65. ; 66. #endif 67. 68. /Circle的头文件Circle.h 69. #ifndef CIRCLE_H 70. #define CIRCLE_H 71. #include Point.h 72. extern const void * Circle; /* new(Circle, x, y, rad) */ 73. #endif 74. 75. /Circle的源文件Cir
17、cle.c 76. #include 77. #include Circle.h 78. #include Circle.r 79. #include new.h 80. #include Base.r 81. /*Circle类自己的构造函数*/ 82. static void * Circle_ctor (void * _self, va_list * app) 83. struct Circle * self = (const struct Base *) Point) - ctor(_self, app); 84. self - rad = va_arg(* app, int); 85
18、. return self; 86. 87. /*Circle类自己的绘图函数*/ 88. static void Circle_draw (const void * _self) 89. const struct Circle * self = _self; 90. printf(circle at %d,%d rad %dn,x(self), y(self), self - rad); 91. 92. static const struct Base _Circle = 93. sizeof(struct Circle), Circle_ctor, 0, Circle_draw 94. ;
19、 95. const void * Circle = & _Circle; 96. 97. /内存管理类头文件new.h 98. #ifndef NEW_H 99. #define NEW_H 100. void * new (const void * base, .); 101. void delete (void * item); 102. void draw (const void * self); 103. #endif 104. 105. /内存管理类的源文件:new.c 106. #include 107. #include 108. #include 109. #include
20、Base.r 110. void * new (const void * _class, .) 111. const struct Base * base = _class; 112. void * p = calloc(1, base - size); 113. assert(p); 114. * (const struct Base *) p = base; 115. if (base - ctor) 116. va_list ap; 117. va_start(ap, _class); 118. p = base - ctor(p, & ap); 119. va_end(ap); 120
21、. 121. return p; 122. 123. void delete (void * self) 124. const struct Base * cp = self; 125. if (self & * cp & (* cp) - dtor) 126. self = (* cp) - dtor(self); 127. free(self); 128. 129. void draw (const void * self) 130. const struct Base * const * cp = self; 131. assert(self & * cp & (* cp) - draw
22、); 132. (* cp) - draw(self); 133. /基类Base的内部头文件Base.r,对#ifndef BASE_R#define BASE_R#include struct Base size_t size;四、多态可以是用C语言中的万能指针void* 实现多态,接上面的例子: cppview plaincopyprint? 1. #include Circle.h 2. #include new.h 3. int main (int argc, char * argv) 4. 5. void * p; 6. int i; 7. for(i=0; i2; i+) 8.
23、9. if(i=0) 10. p = new(Circle, 1, 2, 3); 11. else 12. p = new(Point, 1, 2); 13. draw(p); 14. move(p, 10, 20); 15. draw(p); 16. delete(p); 17. 18. return 0; 19. #include Circle.h#include new.hint main (int argc, char * argvoid * p;int i;输出结果: circle at 1,2 rad 3 circle at 11,22 rad 3 Point at 1,2 Point at 11,22 五、总结 面向对象是一种程序设计思想,而 C 语言则是一种编程语言。也许它并不是专门为了面向对象编程而设计,但是这绝不意味着它不能实现面向对象的程序设计。当然以上所展示的这几个操作,如果是用别的编程语言,可能只要寥寥几行就可以完成,但是 C 语言想告诉我们的是:也许我不擅长,但是并不意味着我做不到。 注: 有些头文件名被csdn误认为内部命令,而变很很诡异,请以所下载的代码为准。
链接地址:https://www.31ppt.com/p-3155220.html