C 语⾔实现⾯向对象编程
C 语⾔实现⾯向对象编程
1、引⾔
⾯向对象编程(OOP)并不是⼀种特定的语⾔或者⼯具,它只是⼀种设计⽅法、设计思想。它表现出来的三个最基本的特性就是封装、继承与多态。很多⾯向对象的编程语⾔已经包含这三个特性了,例如 Smalltalk、C++、Java。但是你也可以⽤⼏乎所有的编程语⾔来实现⾯向对象编程,例如 ANSI-C。要记住,⾯向对象是⼀种思想,⼀种⽅法,不要太拘泥于编程语⾔。
2、封装
封装就是把数据和⽅法打包到⼀个类⾥⾯。其实C语⾔编程者应该都已经接触过了,C 标准库
中的 fopen(), fclose(), fread(), fwrite()等函数的操作对象就是 FILE。数据内容就是 FILE,数据的读写操作就是 fread()、fwrite(),fopen() 类⽐于构造函数,fclose() 就是析构函数。这个看起来似乎很好理解,那下⾯我们实现⼀下基本的封装特性。这是 Shape 类的声明,⾮常简单,很好理解。⼀般会把声明放到头⽂件⾥⾯ “Shape.h”。
来看下 Shape 类相关的定义,当然是在 “Shape.c” ⾥⾯。#ifndef SHAPE_H #define SHAPE_H #include <stdint.h>// Shape 的属性typedef struct { int16_t x; int16_t y; } Shape;// Shape 的操作函数,接⼝函数void Shape_ctor(Shape * const me, int16_t x, int16_t y);void Shape_moveBy(Shape * const me, int16_t dx, int16_t dy);int16_t Shape_getX(Shape const * const me);int16_t Shape_getY(Shape const * const me);#endif /* SHAPE_H */
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
再看下 main.c
编译之后,看看执⾏结果:
整个例⼦,⾮常简单,⾮常好理解。以后写代码时候,要多去想想标准库的⽂件IO操作,这样也有意识的去培养⾯向对象编程的思维。
3、继承
继承就是基于现有的⼀个类去定义⼀个新类,这样有助于重⽤代码,更好的组织代码。在 C 语⾔⾥⾯,去实现单继承也⾮常简单,只要把基类放到继承类的第⼀个数据成员的位置就⾏了。#include "shape.h"// 构造函数void Shape_ctor(Shape * const me, int16_t x, int16_t y){ me->x = x; me->y = y;}void Shape_moveBy(Shape * const me, int16_t dx, int16_t dy) { me->x += dx; me->y += dy;}// 获取属性值函数int16_t Shape_getX(Shape const * const me) { return me->x;}int16_t Shape_getY(Shape const * const me) { return me->y;}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24#include "shape.h" /* Shape class interface */#include <stdio.h> /* for printf() */int main() { Shape s1, s2; /* multiple instances of Shape */ Shape_ctor(&s1, 0, 1); Shape_ctor(&s2, -1, 2); printf("Shape s1(x=%d,y=%d)\n", Shape_getX(&s1), Shape_getY(&s1)); printf("Shape s2(x=%d,y=%d)\n", Shape_getX(&s2), Shape_getY(&s2)); Shape_moveBy(&s1, 2, -4); Shape_m
oveBy(&s2, 1, -2); printf("Shape s1(x=%d,y=%d)\n", Shape_getX(&s1), Shape_getY(&s1)); printf("Shape s2(x=%d,y=%d)\n", Shape_getX(&s2), Shape_getY(&s2)); return 0;}
12
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21Shape s1(x=0,y=1)Shape s2(x=-1,y=2)Shape s1(x=2,y=-3)Shape s2(x=0,y=0)
1
2
3
4c语言如何去学
例如,我们现在要创建⼀个 Rectangle 类,我们只要继承 Shape 类已经存在的属性和操作,再添加不同于 Shape 的属性和操作到Rectangle 中。
下⾯是 Rectangle 的声明与定义:
我们来看⼀下 Rectangle 的继承关系和内存布局#ifndef RECT_H #define RECT_H #include "shape.h" // 基类接⼝// 矩形的属性typedef struct { Shape super; // 继承 Shape // ⾃⼰的属性 uint16_t width; uint16_t height;} Rectangle;// 构造函数void Rectangle_ctor(Rectangle * const me, int16_t x, int16_t y, uint16_t width, uint16_t height);#endif /* RECT_H */
1
2
3
4
5
6
7
8
9
1011
12
13
14
15
16
17
18
19#include "rect.h"// 构造函数void Rectangle_ctor(Rectangle * const me, int16_t x, int16_t y, uint16_t width, uint16_t height){ /* first call superclass’ ctor */ Shape_ctor(&me->super, x, y); /* next, you initialize the attributes added by */ me->width = width; me->height = height;}
1
2
3
4
5
6
7
8
9
10
11
12
13
因为有这样的内存布局,所以你可以很安全的传⼀个指向 Rectangle 对象的指针到⼀个期望传⼊ Shape 对象的指针的函数中,就是⼀个函数的参数是 “Shape *”,你可以传⼊ “Rectangle *”,并且这是⾮常安全的。这样的话,基类的所有属性和⽅法都可以被继承类继承!
输出结果:#include "rect.h" #include <stdio.h> int main() { Rectangle r1, r2; // 实例化对象 Rect
angle_ctor(&r1, 0, 2, 10, 15); Rectangle_ctor(&r2, -1, 3, 5, 8); printf("Rect r1(x=%d,y=%d,width=%d,height=%d)\n", Shape_getX(&r1.super ), Shape_getY(&r1.super ), r1.width , r1.height ); printf("Rect r2(x=%d,y=%d,width=%d,height=%d)\n", Shape_getX(&r2.super ), Shape_getY(&r2.super ), r2.width , r2.height ); // 注意,这⾥有两种⽅式,⼀是强转类型,⼆是直接使⽤成员地址 Shape_moveBy((Shape *)&r1, -2, 3); Shape_moveBy(&r2.super , 2, -1); printf("Rect r1(x=%d,y=%d,width=%d,height=%d)\n", Shape_getX(&r1.super ), Shape_getY(&r1.super ), r1.width , r1.height ); printf("Rect r2(x=%d,y=%d,width=%d,height=%d)\n", Shape_getX(&r2.super ), Shape_getY(&r2.super ), r2.width , r2.height ); return 0;}
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
4、多态
C++ 语⾔实现多态就是使⽤虚函数。在 C 语⾔⾥⾯,也可以实现多态。
现在,我们⼜要增加⼀个圆形,并且在 Shape 要扩展功能,我们要增加 area() 和 draw() 函数。但是 Shape 相当于抽象类,不知道怎么去计算⾃⼰的⾯积,更不知道怎么去画出来⾃⼰。⽽且,矩形和圆形的⾯积计算⽅式和⼏何图像也是不⼀样的。
下⾯让我们重新声明⼀下 Shape 类Rect r1(x=0,y=2,width=10,height=15)Rect r2(x=-1,y=3,width=5,height=8)Rect r1(x=-2,y=5,width=10,height=15)Rect r2(x=1,y=2,width=5,height=8)
1
2
3
4#ifndef SHAPE_H #define SHAPE_H #include <stdint.h>struct ShapeVtbl;// Shape 的属性typedef struct { struct ShapeVtbl const *vptr; int16_t x; int16_t y; } Shape;// Shape 的虚表struct ShapeVtbl { uint32_t (*area)(Shape const * const me); void (*draw)(Shape const * const me);};// Shape 的操作函数,接⼝函数void Shape_ctor(Shape * const me, int16_t x, int16_t y);void Shape_moveBy(Shape * const me, int16_t dx, int16_t dy);int16_t Shape_getX(Shape const * const me);int16_t Shape_getY(Shape const * const me);static inline uint32_t Shape_area(Shape const * const me) { return (*me->vptr->area)(me);}static inline void Shape_draw(Shape const * const me){ (*me->vptr->draw)(me);}Shape const *largestShape(Shape const *shapes[], uint32_t nShapes);void drawAllShapes(Shape const *shapes[], uint32_t nShapes);#endif /* SHAPE_H */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
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论