『Java 謎+落とし穴 徹底解明』 3.3 寄り道 - Cで継承を実現してみる
p.177 - List 3.11 - 3.22 について、 たとえば ExtendedPolyline を追加す
るとしたらどうするのか、つたないながら考えてみました。
ここのところいろいろご面倒をおかけしておりますが、またよろしければご叱
正いただけると幸いです。
(なお、
http://kmaebashi.com/programmer/c_yota/inherit.html
も拝見しましたが、申し訳ないことにいまのわたしには難解でした。)
まず、 Shape.c の MethodTableIndex を Shape.h に移動するのはまずいでしょ
うか。しかし、そうしたとして、あとは以下のファイルを改変または追加しました。
(なお、 Shape は abstract 相当と理解しております。)
---- Polyline.h -----------------------------------------
#ifndef POLYLINE_H_INCLUDED
#define POLYLINE_H_INCLUDED
#include "Shape.h"
#include "Point2D.h"
typedef struct {
  Shape super;
  int nPoints;
  Point2D *point;
} Polyline;
Polyline *createPolyline(void);
void drawPolyline(Polyline *polyline);
ClassDescriptor *getPolylineClassDescriptor(void);
#endif /* POLYLINE_H_INCLUDED */
---- Polyline.c -----------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include "Polyline.h"
static void drawPolylineImpl(void);
static void (*methodTable[])() = {
  drawPolylineImpl
};
static ClassDescriptor polylineClassDescriptor = {
  methodTable
};
ClassDescriptor *getPolylineClassDescriptor(void) {
  return &polylineClassDescriptor;
}
Polyline *createPolyline(void)
{
  Polyline *p = malloc(sizeof(Polyline));
  p->super.super.classDescriptor = &polylineClassDescriptor;
  p->nPoints = 0;
  p->point = NULL;
  return p;
}
void drawPolyline(Polyline *polyline)
{
  polyline->super.super.classDescriptor->methodTable[(int)DRAW_INDEX]();
}
static void drawPolylineImpl(void)
{
  fprintf(stderr, "Polylineを描画\n");
}
---- ExtendedPolyline.h ---------------------------------
#ifndef EXTENDED_POLYLINE_H_INCLUDED
#define EXTENDED_POLYLINE_H_INCLUDED
#include "Polyline.h"
#include "Point2D.h"
typedef struct {
  Polyline super;
  int nPoints;
  Point2D *point;
} ExtendedPolyline;
ExtendedPolyline *createExtendedPolyline(void);
void drawExtendedPolyline(ExtendedPolyline *extendedPolyline);
#endif /* EXTENDED_POLYLINE_H_INCLUDED */
---- ExtendedPolyline.c ---------------------------------
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include "ExtendedPolyline.h"
static void drawExtendedPolylineImpl(void);
static void (*methodTable[])() = {};
static ClassDescriptor extendedPolylineClassDescriptor = {
  methodTable
};
/* このへんがとりわけリアリティにかけるのかも…… */
void initExtendedPolyline(void) {
  ClassDescriptor *cd = getPolylineClassDescriptor();
  void (**mt)() = cd->methodTable;
  memcpy(methodTable, mt, sizeof(mt));
  methodTable[(int)DRAW_INDEX] = drawExtendedPolylineImpl;
}
ExtendedPolyline *createExtendedPolyline(void)
{
  ExtendedPolyline *ep = malloc(sizeof(ExtendedPolyline));
  /*
    
http://kmaebashi.com/programmer/c_yota/inherit.html
    には super.super.super.... を回避する裏技が紹介されていますが……
  */
  ep->super.super.super.classDescriptor = &extendedPolylineClassDescriptor;
  ep->nPoints = 0;
  ep->point = NULL;
  return ep;
}
void drawExtendedPolyline(ExtendedPolyline *extendedPolyline)
{
  extendedPolyline->super.super.super.classDescriptor->methodTable[(int)DRAW_INDEX]();
}
static void drawExtendedPolylineImpl(void)
{
  fprintf(stderr, "ExtendedPolylineを描画\n");
}
---- draw.h ---------------------------------------------
#include "Shape.h"
void draw(Shape **shapes);
---- draw.c ---------------------------------------------
/*
  
http://kmaebashi.com/bbs/thread.php?boardid=kmaebashibbs&from=1906&range=1
 */
#include <stdio.h>
#include "Shape.h"
void draw(Shape **shapes)
{
  int i;
  for (i = 0; i < 4; i++) {
    drawShape(shapes[i]);
  }
}
---- main.c ---------------------------------------------
#include <stdio.h>
#include "Shape.h"
#include "Polyline.h"
#include "Circle.h"
#include "Rectangle.h"
#include "ExtendedPolyline.h"
#include "draw.h"
int main(void)
{
  Shape *shapes[4];
  int i;
  initExtendedPolyline();
  shapes[0] = (Shape*)createPolyline();
  shapes[1] = (Shape*)createCircle();
  shapes[2] = (Shape*)createRectangle();
  shapes[3] = (Shape*)createExtendedPolyline();
  draw(shapes);
  printf("\n");
  
  drawPolyline(createPolyline());
  drawPolyline((Polyline*)createExtendedPolyline());
  drawExtendedPolyline(createExtendedPolyline());
  return 0;
}
---------------------------------------------------------