Constructing Class in C

H

Hyoung Lee

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?

Hyoung
 
E

E. Robert Tisdale

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
 
W

William Ahern

Hyoung Lee 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?

you can get single inheritance through the property that a pointer to a
structure is also a pointer to the first member of that structure.

in some of my code i have something like:

typedef struct object {
...
} object_t;

typedef struct thread {
object_t obj;
...
} thread_t;

struct server {
thread_t thr;
...
};

however, your initializations and destructions of these "objects" becomes so
tedious and verbose, it's difficult to defend.

in C, a better paradigm is to spend the vast majority of your time designing
on paper your C interfaces. then [physically] modularize-- assuming unix--
thru seperate processes and/or well-defined, abstract interfaces like pipes.

in java you might end up w/ an app that has several tens of thousands
of lines of code. you should never let yourself get that far in C.

at least, this has been my experience, albeit short.

- Bill
 
M

Malcolm

Hyoung Lee said:
Do you have a better way of accurately simulating OO
visibility, inheritance, polymorphism, constructors, and destructors in C?
It is reasonable to have opaque objects in C - the stdio FILE structure is
an example.

Constructors and destructors have to be called explicitly, but this isn't
too much of a burden on the calling programmer.

Once you start trying to provide inheirtance and polymorphism, its much
simpler to code in C++.

It can be done in C, for instance you can declare a structure containing
function pointers to act like a virtual interface, and you can nest
structures to provide a sort of inheritance. Microsoft's COM interface
provides a C API - I can't remember all the details but you obtain an
"unknown" function pinter and then query it to see what services the object
provides. However it is a horrible thing to have to use. C is really for
procedural programming, not object-orientation.
 
N

news.telesouth1.com

HongKongHooker said:
Would it be cruel if I asked why you're so interested in re-inventing C++?

news:[email protected]...

Why would someone not learn C++ at this point ? It's a serious undertaking,
but you wouldn't have to use force C into an OOP mold ?

Sounds like stepping over boxes for weeks, rather than taking the time to
unpack.
 
J

John Devereux

news.telesouth1.com said:
Why would someone not learn C++ at this point ? It's a serious undertaking,
but you wouldn't have to use force C into an OOP mold ?


There are many systems, e.g. embedded ones, where there is no C++
compiler available.

I came accross one approach which the author calls "C+":

<http://www.quantum-leaps.com/cookbook/cplus.htm>

Didn't the early C++ compilers emit C as an intermediate step? That
may be another way to do it.
 
A

Alan Balmer

There are many systems, e.g. embedded ones, where there is no C++
compiler available.

Fortunately, most embedded systems get along fine without "OO
visibility, inheritance, polymorphism, constructors, and destructors"
:)
I came accross one approach which the author calls "C+":

<http://www.quantum-leaps.com/cookbook/cplus.htm>

Didn't the early C++ compilers emit C as an intermediate step? That
may be another way to do it.

Yep. Cfront.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,743
Messages
2,569,478
Members
44,898
Latest member
BlairH7607

Latest Threads

Top