E
E. Robert Tisdale
The following example shows how an Object Oriented C programmer
might implement run-time polymorphism.
The Circle "class" is "derived" from the Shape "class".
Pointers to functions
which actually draw and compute the area of a shape
are stored in a "virtual function table"
and a pointer to the appropriate virtual function table
is stored in every shape object.
The "virtual" functions use this pointer to retrieve
a pointer to the "actual" function and call it
through this pointer.
$ cat Point.h
#ifndef Guard_Point_h
#define Guard_Point_h 1
typedef struct Point {
/* representation */
double X;
double Y;
} Point;
/* functions */
double
xPoint(const Point* pP);
double
yPoint(const Point* pP);
/* constructors */
Point
createDefaultPoint(void);
Point
createExplicitPoint(double x, double y);
/* destructor */
void
destroyPoint(const Point* pP);
#endif/* Guard_Point_h */
$ cat Point.c
/* gcc -I. -O2 -c Point.c
*/
#include<Point.h>
/* functions */
double
xPoint(const Point* pP) {
return pP->X; }
double
yPoint(const Point* pP) {
return pP->Y; }
/* constructors */
Point
createDefaultPoint(void) {
Point p;
p.X = 0.0;
p.Y = 0.0;
return p; }
Point
createExplicitPoint(double x, double y) {
Point p;
p.X = x;
p.Y = y;
return p;
}
/* destructor */
void
destroyPoint(const Point* pP) { }
$ cat Color.h
#ifndef Guard_Color_h
#define Guard_Color_h 1
typedef struct Color {
unsigned char R; /* red */
unsigned char G; /* green */
unsigned char B; /* blue */
} Color;
/* functions */
unsigned int
redColor(const Color* pC);
unsigned int
greenColor(const Color* pC);
unsigned int
blueColor(const Color* pC);
/* constructors */
Color
createDefaultColor(void);
Color
createExplicitColor(
unsigned int r,
unsigned int g,
unsigned int b);
/* destructor */
void
destroyColor(const Color* pC);
#endif/* Guard_Color_h */
$ cat Color.c
/* gcc -I. -O2 -c Color.c
*/
#include<Color.h>
/* functions */
unsigned int
redColor(const Color* pC) {
return pC->R; }
unsigned int
greenColor(const Color* pC) {
return pC->G; }
unsigned int
blueColor(const Color* pC) {
return pC->B; }
/* constructors */
Color
createDefaultColor(void) {
Color c;
c.R = 0;
c.G = 0;
c.B = 0;
return c; }
Color
createExplicitColor(
unsigned int r,
unsigned int g,
unsigned int b) {
Color c;
c.R = r;
c.G = g;
c.B = b;
return c; }
/* destructor */
void
destroyColor(const Color* pC) { }
$ cat Shape.h
#ifndef Guard_Shape_h
#define Guard_Shape_h 1
#include<Point.h>
#include<Color.h>
typedef struct Shape {
const
void* pV; /* virtual function table */
Point P; /* first public base class */
Color C; /* second public base class */
} Shape;
/* functions */
Point*
pointShape(Shape* pS);
Color*
colorShape(Shape* pS);
void
drawShape(const Shape* pS);
void
actualDrawShape(const Shape* pS);
double
areaShape(const Shape* pS);
double
actualAreaShape(const Shape* pS);
/* constructors */
Shape
createDefaultShape(void);
Shape
createExplicitShape(
const Point* pP,
const Color* pC);
/* destructor */
void
destroyShape(const Shape* pS);
#endif/* Guard_Shape_h */
$ cat Shape.c
/* gcc -I. -O2 -c Shape.c
*/
#include<stdio.h>
#include<Shape.h>
/* functions */
Point*
pointShape(Shape* pS) {
return &(pS->P); }
Color*
colorShape(Shape* pS) {
return &(pS->C); }
void
actualDrawShape(const Shape* pS) {
fprintf(stderr, "drawShape(const Shape*)\n");
fflush(stderr); }
double
actualAreaShape(const Shape* pS) {
fprintf(stderr, "areaShape(const Shape*)\n");
fflush(stderr);
return 0.0; }
typedef struct vTableShape_t {
void (*drawShape)(const Shape*);
double (*areaShape)(const Shape*);
} vTableShape_t;
static const vTableShape_t
vTableShape = {actualDrawShape, actualAreaShape};
void
drawShape(const Shape* pS) {
((vTableShape_t*)(pS->pV))->drawShape(pS); }
double
areaShape(const Shape* pS) {
return ((vTableShape_t*)(pS->pV))->areaShape(pS); }
/* initializers */
Shape* initializeDefaultShape(Shape* pS, const void* pV) {
pS->pV = pV;
pS->P = createDefaultPoint();
pS->C = createDefaultColor();
return pS; }
Shape* initializeExplicitShape(Shape* pS, const void* pV,
const Point* pP, const Color* pC) {
pS->pV = pV;
pS->P = *pP;
pS->C = *pC;
return pS; }
/* constructors */
Shape
createDefaultShape(void) {
Shape S;
initializeDefaultShape(&S, &vTableShape);
return S; }
Shape
createExplicitShape(
const Point* pP,
const Color* pC) {
Shape S;
return *initializeExplicitShape(&S, &vTableShape, pP, pC); }
/* destructor */
void
destroyShape(const Shape* pS) {
destroyColor(colorShape((Shape*)pS));
destroyPoint(pointShape((Shape*)pS)); }
$ cat Circle.h
#ifndef Guard_Circle_h
#define Guard_Circle_h 1
#include<Shape.h>
typedef struct {
Shape S; /* public base class */
double R; /* radius */
} Circle;
/* functions */
Shape*
shapeCircle(Circle* pC);
double
radiusCircle(const Circle* pC);
void
drawCircle(const Circle* pC);
void
actualDrawCircle(const Circle* pC);
double
areaCircle(const Circle* pC);
double
actualAreaCircle(const Circle* pC);
/* constructors */
Circle
createDefaultCircle(void);
Circle
createExplicitCircle(const Point* pP,
const Color* pC, double r);
/* destructor */
void
destroyCircle(const Circle* pC);
#endif/* Guard_Circle_h */
$ cat Circle.c
/* gcc -I. -O2 -c Circle.c
*/
#include<math.h>
#include<stdio.h>
#include<Circle.h>
/* functions */
Shape*
shapeCircle(Circle* pC) {
return &(pC->S); }
double
radiusCircle(const Circle* pC) {
return pC->R; }
void
actualDrawCircle(const Circle* pC) {
fprintf(stderr, "actualDrawCircle(const Circle*)\n");
fflush(stderr); }
double
actualAreaCircle(const Circle* pC) {
const
double pi = 3.14159265358979323846;
double r = radiusCircle(pC);
fprintf(stderr, "actualAreaCircle(const Circle*)\n");
fflush(stderr);
return pi*r*r; }
typedef struct vTableCircle_t {
void (*drawCircle)(const Circle*);
double (*areaCircle)(const Circle*);
} vTableCircle_t;
static const vTableCircle_t
vTableCircle = {actualDrawCircle, actualAreaCircle};
void
drawCircle(const Circle* pC) {
((vTableCircle_t*)(pC->S.pV))->drawCircle(pC); }
double
areaCircle(const Circle* pC) {
return ((vTableCircle_t*)(pC->S.pV))->areaCircle(pC); }
/* constructors */
Circle
createDefaultCircle(void) {
Circle C;
extern Shape* initializeDefaultShape(Shape*, const void*);
initializeDefaultShape(&(C.S), &vTableCircle);
C.R = 0.0;
return C; }
Circle
createExplicitCircle(const Point* pP,
const Color* pC, double r) {
Circle C;
extern Shape* initializeExplicitShape(Shape*, const void*,
const Point*, const Color*);
initializeExplicitShape(&(C.S), &vTableCircle, pP, pC);
C.R = r;
return C; }
/* destructor */
void
destroyCircle(const Circle* pC) {
destroyShape(shapeCircle((Circle*)pC)); }
$ cat main.c
/* gcc -I. -O2 -o main main.c Circle.o Shape.o Color.o Point.o
*/
#include<stdio.h>
#include<Circle.h>
int
main(int argc, char* argv[]) {
const Point point = createDefaultPoint();
const Color color = createDefaultColor();
const Circle circle = createExplicitCircle(
&point, &color, 2.0);
drawShape((Shape*)(&circle));
fprintf(stdout, "%g = radius\t %g = area\n",
radiusCircle(&circle), areaShape((Shape*)(&circle)));
destroyCircle(&circle);
destroyColor(&color);
destroyPoint(&point);
return 0;
}
might implement run-time polymorphism.
The Circle "class" is "derived" from the Shape "class".
Pointers to functions
which actually draw and compute the area of a shape
are stored in a "virtual function table"
and a pointer to the appropriate virtual function table
is stored in every shape object.
The "virtual" functions use this pointer to retrieve
a pointer to the "actual" function and call it
through this pointer.
$ cat Point.h
#ifndef Guard_Point_h
#define Guard_Point_h 1
typedef struct Point {
/* representation */
double X;
double Y;
} Point;
/* functions */
double
xPoint(const Point* pP);
double
yPoint(const Point* pP);
/* constructors */
Point
createDefaultPoint(void);
Point
createExplicitPoint(double x, double y);
/* destructor */
void
destroyPoint(const Point* pP);
#endif/* Guard_Point_h */
$ cat Point.c
/* gcc -I. -O2 -c Point.c
*/
#include<Point.h>
/* functions */
double
xPoint(const Point* pP) {
return pP->X; }
double
yPoint(const Point* pP) {
return pP->Y; }
/* constructors */
Point
createDefaultPoint(void) {
Point p;
p.X = 0.0;
p.Y = 0.0;
return p; }
Point
createExplicitPoint(double x, double y) {
Point p;
p.X = x;
p.Y = y;
return p;
}
/* destructor */
void
destroyPoint(const Point* pP) { }
$ cat Color.h
#ifndef Guard_Color_h
#define Guard_Color_h 1
typedef struct Color {
unsigned char R; /* red */
unsigned char G; /* green */
unsigned char B; /* blue */
} Color;
/* functions */
unsigned int
redColor(const Color* pC);
unsigned int
greenColor(const Color* pC);
unsigned int
blueColor(const Color* pC);
/* constructors */
Color
createDefaultColor(void);
Color
createExplicitColor(
unsigned int r,
unsigned int g,
unsigned int b);
/* destructor */
void
destroyColor(const Color* pC);
#endif/* Guard_Color_h */
$ cat Color.c
/* gcc -I. -O2 -c Color.c
*/
#include<Color.h>
/* functions */
unsigned int
redColor(const Color* pC) {
return pC->R; }
unsigned int
greenColor(const Color* pC) {
return pC->G; }
unsigned int
blueColor(const Color* pC) {
return pC->B; }
/* constructors */
Color
createDefaultColor(void) {
Color c;
c.R = 0;
c.G = 0;
c.B = 0;
return c; }
Color
createExplicitColor(
unsigned int r,
unsigned int g,
unsigned int b) {
Color c;
c.R = r;
c.G = g;
c.B = b;
return c; }
/* destructor */
void
destroyColor(const Color* pC) { }
$ cat Shape.h
#ifndef Guard_Shape_h
#define Guard_Shape_h 1
#include<Point.h>
#include<Color.h>
typedef struct Shape {
const
void* pV; /* virtual function table */
Point P; /* first public base class */
Color C; /* second public base class */
} Shape;
/* functions */
Point*
pointShape(Shape* pS);
Color*
colorShape(Shape* pS);
void
drawShape(const Shape* pS);
void
actualDrawShape(const Shape* pS);
double
areaShape(const Shape* pS);
double
actualAreaShape(const Shape* pS);
/* constructors */
Shape
createDefaultShape(void);
Shape
createExplicitShape(
const Point* pP,
const Color* pC);
/* destructor */
void
destroyShape(const Shape* pS);
#endif/* Guard_Shape_h */
$ cat Shape.c
/* gcc -I. -O2 -c Shape.c
*/
#include<stdio.h>
#include<Shape.h>
/* functions */
Point*
pointShape(Shape* pS) {
return &(pS->P); }
Color*
colorShape(Shape* pS) {
return &(pS->C); }
void
actualDrawShape(const Shape* pS) {
fprintf(stderr, "drawShape(const Shape*)\n");
fflush(stderr); }
double
actualAreaShape(const Shape* pS) {
fprintf(stderr, "areaShape(const Shape*)\n");
fflush(stderr);
return 0.0; }
typedef struct vTableShape_t {
void (*drawShape)(const Shape*);
double (*areaShape)(const Shape*);
} vTableShape_t;
static const vTableShape_t
vTableShape = {actualDrawShape, actualAreaShape};
void
drawShape(const Shape* pS) {
((vTableShape_t*)(pS->pV))->drawShape(pS); }
double
areaShape(const Shape* pS) {
return ((vTableShape_t*)(pS->pV))->areaShape(pS); }
/* initializers */
Shape* initializeDefaultShape(Shape* pS, const void* pV) {
pS->pV = pV;
pS->P = createDefaultPoint();
pS->C = createDefaultColor();
return pS; }
Shape* initializeExplicitShape(Shape* pS, const void* pV,
const Point* pP, const Color* pC) {
pS->pV = pV;
pS->P = *pP;
pS->C = *pC;
return pS; }
/* constructors */
Shape
createDefaultShape(void) {
Shape S;
initializeDefaultShape(&S, &vTableShape);
return S; }
Shape
createExplicitShape(
const Point* pP,
const Color* pC) {
Shape S;
return *initializeExplicitShape(&S, &vTableShape, pP, pC); }
/* destructor */
void
destroyShape(const Shape* pS) {
destroyColor(colorShape((Shape*)pS));
destroyPoint(pointShape((Shape*)pS)); }
$ cat Circle.h
#ifndef Guard_Circle_h
#define Guard_Circle_h 1
#include<Shape.h>
typedef struct {
Shape S; /* public base class */
double R; /* radius */
} Circle;
/* functions */
Shape*
shapeCircle(Circle* pC);
double
radiusCircle(const Circle* pC);
void
drawCircle(const Circle* pC);
void
actualDrawCircle(const Circle* pC);
double
areaCircle(const Circle* pC);
double
actualAreaCircle(const Circle* pC);
/* constructors */
Circle
createDefaultCircle(void);
Circle
createExplicitCircle(const Point* pP,
const Color* pC, double r);
/* destructor */
void
destroyCircle(const Circle* pC);
#endif/* Guard_Circle_h */
$ cat Circle.c
/* gcc -I. -O2 -c Circle.c
*/
#include<math.h>
#include<stdio.h>
#include<Circle.h>
/* functions */
Shape*
shapeCircle(Circle* pC) {
return &(pC->S); }
double
radiusCircle(const Circle* pC) {
return pC->R; }
void
actualDrawCircle(const Circle* pC) {
fprintf(stderr, "actualDrawCircle(const Circle*)\n");
fflush(stderr); }
double
actualAreaCircle(const Circle* pC) {
const
double pi = 3.14159265358979323846;
double r = radiusCircle(pC);
fprintf(stderr, "actualAreaCircle(const Circle*)\n");
fflush(stderr);
return pi*r*r; }
typedef struct vTableCircle_t {
void (*drawCircle)(const Circle*);
double (*areaCircle)(const Circle*);
} vTableCircle_t;
static const vTableCircle_t
vTableCircle = {actualDrawCircle, actualAreaCircle};
void
drawCircle(const Circle* pC) {
((vTableCircle_t*)(pC->S.pV))->drawCircle(pC); }
double
areaCircle(const Circle* pC) {
return ((vTableCircle_t*)(pC->S.pV))->areaCircle(pC); }
/* constructors */
Circle
createDefaultCircle(void) {
Circle C;
extern Shape* initializeDefaultShape(Shape*, const void*);
initializeDefaultShape(&(C.S), &vTableCircle);
C.R = 0.0;
return C; }
Circle
createExplicitCircle(const Point* pP,
const Color* pC, double r) {
Circle C;
extern Shape* initializeExplicitShape(Shape*, const void*,
const Point*, const Color*);
initializeExplicitShape(&(C.S), &vTableCircle, pP, pC);
C.R = r;
return C; }
/* destructor */
void
destroyCircle(const Circle* pC) {
destroyShape(shapeCircle((Circle*)pC)); }
$ cat main.c
/* gcc -I. -O2 -o main main.c Circle.o Shape.o Color.o Point.o
*/
#include<stdio.h>
#include<Circle.h>
int
main(int argc, char* argv[]) {
const Point point = createDefaultPoint();
const Color color = createDefaultColor();
const Circle circle = createExplicitCircle(
&point, &color, 2.0);
drawShape((Shape*)(&circle));
fprintf(stdout, "%g = radius\t %g = area\n",
radiusCircle(&circle), areaShape((Shape*)(&circle)));
destroyCircle(&circle);
destroyColor(&color);
destroyPoint(&point);
return 0;
}