使用多态,后期扩展功能,不用修改上层策略代码,只需要补充底层模块代码。依赖倒置效果。

* 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 <assert.h>

/* 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 <stdio.h>

/* 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 <stdio.h>
#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

C语言实现多态 (polymorphism)_C

C语言实现多态 (polymorphism)_file_02

 

-----------------------------------------------  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函数指针指向的函数