使用多态,后期扩展功能,不用修改上层策略代码,只需要补充底层模块代码。依赖倒置效果。
* shape.h
#ifndef shape_h
#define shape_h
typedef short int16_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
struct ShapeVtbl;
typedef struct {
struct ShapeVtbl const *vptr;
int16_t x;
int16_t y;
} Shape;
struct ShapeVtbl {
uint32_t (*area)(Shape const * const me);
void (*draw)(Shape const *const me);
};
/* Shape's operations (Shape's interface)... */
void Shape_ctor(Shape * const me, int16_t x, int16_t y);
void Shape_moveBy(Shape * const me, int16_t dx, int16_t dy);
#define Shape_area(me_) ((*(me_)->vptr->area)((me_)))
#define Shape_draw(me_) ((*(me_)->vptr->draw)((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);
}
*/
/* generic operations on collections of Shapes */
Shape const *largestShape(Shape const *shapes[], uint32_t nShapes);
void drawAllShapes(Shape const *shapes[], uint32_t nShapes);
#endif /* shape_h */
* shape.c
#include "shape.h"
#include
/* Shape's prototypes of its virtual functions */
static uint32_t Shape_area_(Shape const * const me);
static void Shape_draw_(Shape const * const me);
/* Shape's operations (Shape's interface)... */
void Shape_ctor(Shape * const me, int16_t x, int16_t y) {
static struct ShapeVtbl const vtbl = {
/* vtbl of the Shape class */
&Shape_area_,
&Shape_draw_
};
me->vptr = &vtbl; /* "hook" the vptr to the vtbl */
me->x = x;
me->y = y;
}
void Shape_moveBy(Shape * const me, int16_t dx, int16_t dy) {
me->x += dx;
me->y += dy;
}
static uint32_t Shape_area_(Shape const * const me) {
assert(0); /* purely-virtual function should never be called */
return 0U; /* to avoid compiler warnings */
}
static void Shape_draw_(Shape const * const me) {
assert(0); /* purely-virtual function should never be called */
}
/* the following code finds the largest-area shape in the collection */
Shape const *largestShape(Shape const *shapes[], uint32_t nShapes) {
Shape const *s = (Shape *)0;
uint32_t max = 0U;
uint32_t i;
for (i = 0U; i < nShapes; ++i) {
uint32_t area = Shape_area(shapes[i]); /* virtual call */
if (area > max) {
max = area;
s = shapes[i];
}
}
return s; /* the largest shape in the array shapes[] */
}
/* The following code will draw all Shapes on the screen */
void drawAllShapes(Shape const *shapes[], uint32_t nShapes) {
uint32_t i;
for (i = 0U; i < nShapes; ++i) {
Shape_draw(shapes[i]);
}
}
* rect.h
#ifndef rect_h
#define rect_h
#include "shape.h" /* the base class interface */
typedef unsigned short uint16_t;
/* Rectangle's attributes... */
typedef struct {
Shape super; /* <== inherits Shape */
/* attributes added by this subclass... */
uint16_t width;
uint16_t height;
} Rectangle;
/* constructor prototype */
void Rectangle_ctor(Rectangle * const me, int16_t x, int16_t y,
uint16_t width, uint16_t height);
#endif /* rect_h */
* rect.c
#include "rect.h"
#include
/* Rectangle's prototypes of its virtual functions */
/* NOTE: the "me" pointer has the type of the superclass to fit the vtable */
static uint32_t Rectangle_area_(Shape const * const me);
static void Rectangle_draw_(Shape const * const me);
/* constructor */
void Rectangle_ctor(Rectangle * const me, int16_t x, int16_t y,
uint16_t width, uint16_t height) {
static struct ShapeVtbl const vtbl = {
/* vtbl of the Rectangle class */
&Rectangle_area_,
&Rectangle_draw_
};
Shape_ctor(&me->super, x, y);
me->super.vptr = &vtbl;
me->width = width;
me->height = height;
}
/* Rectangle's class implementations of its virtual functions... */
static uint32_t Rectangle_area_(Shape const * const me) {
/* explicit downcast */
Rectangle const * const me_ = (Rectangle const *)me;
return (uint32_t)me_->width * (uint32_t)me_->height;
}
static void Rectangle_draw_(Shape const * const me) {
/* explicit downcast */
Rectangle const * const me_ = (Rectangle const *)me;
printf("Rectangle_draw_(x=%d,y=%d,width=%d,height=%d)\n",
me_->super.x, me_->super.y, me_->width, me_->height);
}
* circle.h
#ifndef circle_h
#define circle_h
#include "shape.h"
/* Circle's attributes... */
typedef struct {
Shape super; /* <== inherits Shape */
/* attributes added by this subclass... */
int16_t x;
int16_t y;
uint16_t r;
} Circle;
/* constructor prototype */
void Circle_ctor(Circle * const me, int16_t x, int16_t y, uint16_t r);
#endif /* circle_h */
* circle.c
#include "circle.h"
static uint32_t Circle_area_(Shape const * const me);
static void Circle_draw_(Shape const * const me);
void Circle_ctor(Circle * const me, int16_t x, int16_t y, uint16_t r) {
static struct ShapeVtbl const vtbl = {
/* vtbl of the Rectangle class */
&Circle_area_,
&Circle_draw_
};
Shape_ctor(&me->super, x, y);
me->super.vptr = &vtbl;
me->r = r;
}
static uint32_t Circle_area_(Shape const * const me) {
Circle const * const me_ = (Circle const *)me;
return (uint32_t)me_->r * (uint32_t)me_->r;
}
static void Circle_draw_(Shape const * const me) {
Circle const * const me_ = (Circle const *)me;
printf("Circle_draw_(x=%d,y=%d,r=%d)\n",
me_->super.x, me_->super.y, me_->r);
}
* main.c
#include
#include "rect.h" /* Rectangle class interface */
#include "circle.h" /* Circle class interface */
#define count(a) sizeof(a)/sizeof((a)[0])
int main(int argc, const char * argv[]) {
Rectangle r1, r2; /* multiple instances of Rectangle */
Circle c1, c2; /* multiple instances of Circle */
Shape const *shapes[] = { /* collection of shapes */
&c1.super, &r2.super, &c2.super, &r1.super
};
Shape const *s;
/* instantiate rectangles... */
Rectangle_ctor(&r1, 0, 2, 10, 15);
Rectangle_ctor(&r2, -1, 3, 5, 8);
/* instantiate circles... */
Circle_ctor(&c1, 1, -2, 12);
Circle_ctor(&c2, 1, -3, 6);
s = largestShape(shapes, count(shapes));
printf("largetsShape s(x=%d,y=%d)\n", s->x, s->y);
drawAllShapes(shapes, count(shapes));
return 0;
}
* run:
largetsShape s(x=0,y=2)
Circle_draw_(x=1,y=-2,r=12)
Rectangle_draw_(x=-1,y=3,width=5,height=8)
Circle_draw_(x=1,y=-3,r=6)
Rectangle_draw_(x=0,y=2,width=10,height=15)
Program ended with exit code: 0
----------------------------------------------- FILE --------------------------------------
* file.h
#ifndef _FILE_H_
#define _FILE_H_
typedef unsigned int size_t;
typedef int ssize_t;
typedef long off_t;
typedef struct {
int (*open)(const char *path, int mode);
int (*close)(int fd);
ssize_t (*read)(int fd, void *ptr, size_t size, size_t nitems);
ssize_t (*write)(int fd, const void * ptr, size_t size, size_t nitems);
off_t (*seek)(int fd, off_t offset, int whence);
} FILE;
ssize_t open(const char *path, int mode);
int close(int fd);
ssize_t read(int fildes, void *buf, size_t nbyte);
ssize_t write(int fildes, const void *buf, size_t nbyte);
off_t lseek(int fildes, off_t offset, int whence);
#define CLOSED_FILENO -1
#define NULL ((void *)0)
#endif /* _FILE_H_ */
* console.h
#ifndef _CONSOLE_H_
#define _CONSOLE_H_
#define STDIN_FILENO 0
#define STDOUT_FILENO 1
#define EOF -1
int myputs(const char *s);
int mygetchar();
int myputchar(char ch);
#endif /* _CONSOLE_H_ */
* stdin.c
#include "file.h"
#include "console.h"
int kbd_open(const char *path, int mode);
int kbd_close(int fd);
ssize_t kbd_read(int fd, void *ptr, size_t size, size_t nitems);
ssize_t kbd_write(int fd, const void *ptr, size_t size, size_t nitems);
long kbd_seek(int fd, long offset, int whence);
FILE kbd = {
kbd_open,
kbd_close,
kbd_read,
kbd_write,
kbd_seek,
};
FILE *stdin = &kbd;
int kbd_open(const char *path, int mode) {
/* TODO: open "/dev/in" */
return STDIN_FILENO;
}
int kbd_close(int fd) {
return close(fd);
}
ssize_t kbd_read(int fd, void *ptr, size_t size, size_t nitems) {
ssize_t nret = 0, n;
while(nitems-- > 0) {
n = read(fd, ptr, size);
if (n < 0) {
return nret;
}
ptr += n;
nret += n;
}
return nret;
}
ssize_t kbd_write(int fd, const void *ptr, size_t size, size_t nitems) {
return EOF;
}
long kbd_seek(int fd, long offset, int whence) {
return lseek(fd, offset, whence);
}
int mygetchar() {
char buf[1];
int fd = stdin->open("/dev/stdin", 0444);
int nret = stdin->read(fd, buf, 1, 1);
if (nret < 0) {
return EOF;
} else if (nret == 0) {
return 0;
}
return buf[0];
}
* stdout.c
#include "file.h"
#include "console.h"
int console_open(const char *path, int mode);
int console_close(int fd);
ssize_t console_read(int fd, void *ptr, size_t size, size_t nitems);
ssize_t console_write(int fd, const void *ptr, size_t size, size_t nitems);
long console_seek(int fd, long offset, int whence);
FILE console = {
console_open,
console_close,
console_read,
console_write,
console_seek,
};
FILE *stdout = &console;
int console_open(const char *path, int mode) {
/* TODO: open "/dev/stdout" */
return STDOUT_FILENO;
}
int console_close(int fd) {
return close(fd);
}
ssize_t console_read(int fd, void *ptr, size_t size, size_t nitems) {
return EOF;
}
ssize_t console_write(int fd, const void *ptr, size_t size, size_t nitems) {
ssize_t nret = 0, n;
while(nitems-- > 0) {
n = write(fd, ptr, size);
if (n < 0) {
return nret;
}
ptr += n;
nret += n;
}
return nret;
}
long console_seek(int fd, long offset, int whence) {
return lseek(fd, offset, whence);
}
size_t len(const char *s) {
const char *p = s;
int n = 0;
while (*p++) {
++n;
}
return n;
}
void itoa(int n, char s[]) {
int i, j, sign;
if ((sign = n) < 0) {
n = -n;
}
i = 0;
do {
s[i++] = n % 10 + '0';
n /= 10;
} while ( n > 0 );
if (sign < 0) {
s[i++] = '-';
}
s[i] = '\0';
char t;
for (--i, j = 0; j < i; j++, i--) {
t = s[i];
s[i] = s[j];
s[j] = t;
}
}
int myputs(const char *s) {
int fd = stdout->open("/dev/stdout", 0444);
// char b[3];
// itoa(fd, b);
// write(1, b, len(b));
return stdout->write(fd, s, sizeof(char), len(s));
}
int myputchar(char ch) {
char buf[1];
buf[0] = ch;
int fd = stdout->open("/dev/stdout", 0444);
return stdout->write(fd, buf, 1, 1);
}
* main.c
#include "console.h"
void copy() {
int c;
while ((c = mygetchar()) != EOF) {
myputchar(c);
}
return;
}
int main(int argc, char *argv[]) {
const char *s = "Hello world!\n";
myputs(s);
myputs("Input something: ");
copy();
}
* test:
gcc stdin.c stdout.c main.c -Wall
./a.out
Hello world!
Input something: 1234567890
1234567890
^C
-----------------------------------------------
TODO: 把文件描述符fd 改为FILE的成员变量
mygetchar() 只是调用了STDIN所指向的FILE数据结构中的read函数指针指向的函数