Hyoung said:
A simple method of simulating a class, such as C++ or UML class,
in C would be using the struct construct.
Similarly, we use C functions to simulate a methods;
e.g., rv method_a (&struct, parm_list);
Other methods would be fundamentally similar to this approach.
Are there any other approaches that would offer better maintainability and
readability? Do you have a better way of accurately simulating OO
visibility, inheritance, polymorphism, constructors, and destructors in C?
$ cat Point.h
#ifndef _Point_h
#define _Point_h 1
typedef struct {
/* representation */
double X;
double Y;
} Point;
/* functions */
double
xPoint(const Point *p);
double
yPoint(const Point *p);
/* constructors */
Point
createDefaultPoint(void);
Point
createExplicitPoint(double x, double y);
/* destructor */
void
destroyPoint(Point* p);
#endif /* _Point_h */
$ cat Point.c
/* gcc -I. -O2 -c Point.c
*/
#include<Point.h>
/* functions */
double
xPoint(const Point *p) {
return p->X; }
double
yPoint(const Point *p) {
return p->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(Point* p) { }
$ cat Color.h
#ifndef _Color_h
#define _Color_h 1
typedef struct {
unsigned char R; /* red */
unsigned char G; /* green */
unsigned char B; /* blue */
} Color;
/* functions */
unsigned int
redColor(const Color *c);
unsigned int
greenColor(const Color *c);
unsigned int
blueColor(const Color *c);
/* constructors */
Color
createDefaultColor(void);
Color
createExplicitColor(
unsigned int r,
unsigned int g,
unsigned int b);
/* destructor */
void
destroyColor(Color *c);
#endif /* _Color_h */
$ cat Color.c
/* gcc -I. -O2 -c Color.c
*/
#include<Color.h>
/* functions */
unsigned int
redColor(const Color *c) {
return c->R; }
unsigned int
greenColor(const Color *c) {
return c->G; }
unsigned int
blueColor(const Color *c) {
return c->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(Color *c) { }
$ cat Shape.h
#ifndef _Shape_h
#define _Shape_h 1
#include<Point.h>
#include<Color.h>
typedef void* virtual_t;
typedef struct {
Point P; /* first public base class */
Color C; /* second public base class */
virtual_t* V; /* virtual function table */
} Shape;
/* functions */
Point*
pointShape(Shape* s);
Color*
colorShape(Shape* s);
void
drawShape(const Shape *s);
void
drawGeneralShape(const Shape *s);
double
areaShape(const Shape *s);
double
areaGeneralShape(const Shape *s);
/* constructors */
Shape
createDefaultShape(void);
Shape
createExplicitShape(
const Point *p,
const Color *c);
/* destructor */
void
destroyShape(Shape *s);
#endif /* _Shape_h */
$ cat Shape.c
/* gcc -I. -O2 -c Shape.c
*/
#include<stdio.h>
#include<Shape.h>
typedef void (*drawShape_t)(const Shape *);
typedef double (*areaShape_t)(const Shape *);
/* functions */
Point*
pointShape(Shape* s) {
return &(s->P); }
Color*
colorShape(Shape* s) {
return &(s->C); }
void
drawGeneralShape(const Shape *s) {
fprintf(stderr, "drawShape(const Shape *s)\n");
fflush(stderr); }
double
areaGeneralShape(const Shape *s) {
fprintf(stderr, "areaShape(const Shape *s)\n");
fflush(stderr);
return 0.0; }
static virtual_t
vtableShape[] = {(virtual_t)drawGeneralShape,
(virtual_t)areaGeneralShape};
void
drawShape(const Shape *s) {
((drawShape_t)(s->V[0]))(s); }
double
areaShape(const Shape *s) {
return ((areaShape_t)(s->V[1]))(s); }
/* constructors */
Shape
createDefaultShape(void) {
Shape S;
S.P = createDefaultPoint();
S.C = createDefaultColor();
S.V = vtableShape;
return S; }
Shape
createExplicitShape(
const Point *p,
const Color *c) {
Shape S;
S.P = *p;
S.C = *c;
S.V = vtableShape;
return S; }
/* destructor */
void
destroyShape(Shape *s) {
destroyColor(colorShape(s));
destroyPoint(pointShape(s));
}
$ cat Circle.h
#ifndef _Circle_h
#define _Circle_h 1
#include<Shape.h>
typedef struct {
Shape S; /* public base class */
double R; /* radius */
} Circle;
/* functions */
Shape*
shapeCircle(Circle* c);
double
radiusCircle(const Circle* c);
void
drawCircle(const Circle *c);
double
areaCircle(const Circle *c);
/* constructors */
Circle
createDefaultCircle(void);
Circle
createExplicitCircle(const Shape *s, double r);
/* destructor */
void
destroyCircle(Circle *c);
#endif /* _Circle_h */
$ cat Circle.c
/* gcc -I. -O2 -c Circle.c
*/
#include<math.h>
#include<stdio.h>
#include<Circle.h>
typedef void (*drawCircle_t)(const Circle *);
typedef double (*areaCircle_t)(const Circle *);
/* functions */
Shape*
shapeCircle(Circle* c) {
return &(c->S); }
double
radiusCircle(const Circle* c) {
return c->R; }
void
drawCircle(const Circle *c) {
fprintf(stderr, "drawCircle(const Circle *c)\n");
fflush(stderr); }
double
areaCircle(const Circle *c) {
const
double pi = 3.14159265358979323846;
double r = radiusCircle(c);
fprintf(stderr, "areaCircle(const Circle *c)\n");
fflush(stderr);
return pi*r*r; }
static virtual_t
vtableCircle[] = {(virtual_t)drawCircle,
(virtual_t)areaCircle};
/* constructors */
Circle
createDefaultCircle(void) {
Circle C;
C.S = createDefaultShape();
C.R = 0.0;
C.S.V = vtableCircle;
return C; }
Circle
createExplicitCircle(const Shape *s, double r) {
Circle C;
C.S = *s;
C.R = r;
C.S.V = vtableCircle;
return C; }
/* destructor */
void
destroyCircle(Circle *c) {
destroyShape(shapeCircle(c));
}
$ 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[]) {
Shape s = createDefaultShape();
Circle c = createExplicitCircle(&s, 2.0);
drawShape((Shape*)(&c));
fprintf(stdout, "%g = radius\t %g = area\n",
radiusCircle(&c), areaShape((Shape*)(&c)));
return 0;
}
$ cat Makefile
CC=gcc
DEFINES=
INCLUDE=-I.
OPTIONS=-O2
LIBRARY=
OBJECTS=Point.o Color.o Shape.o Circle.o
SOURCES=Point.c Color.c Shape.c Circle.c
HEADERS=Point.h Color.h Shape.h Circle.h
library=
COMPILE=$(CC) $(DEFINES) $(INCLUDE) $(LIBRARY) $(OPTIONS)
main: $(HEADERS) $(OBJECTS) main.c
$(COMPILE) -o main main.c $(OBJECTS) $(library)
Point.o: Point.h Point.c
$(COMPILE) -c Point.c
Color.o: Color.h Color.c
$(COMPILE) -c Color.c
Shape.o: Shape.h Shape.c
$(COMPILE) -c Shape.c
Circle.o: Circle.h Circle.c
$(COMPILE) -c Circle.c
clean:
rm $(OBJECTS) main