Object-oriented programming in standard ANSI C

R

Roland Pibinger

I'm interested in techniques used to program in an object-oriented way
using the C ANSI language. I'm studying the GObject library and Laurent
Deniau's OOPC framework published on his web site at
http://ldeniau.web.cern.ch/ldeniau/html/oopc/oopc.html.

I bookmarked that link some time ago as an example how it should _not_
be done.
The approach is
very instructive. I know that I could do much of this stuff with e.g.
C++, but the intellectual challenge of implementing these concepts with
pure ANSI C is relevant to me.

Are you aware of another approaches? Any experience in using such
techniques in production code?

Many approaches use function pointers or hand-written vtables to
emulate polymorphism. But, AFAIK, they all hide the implementation
under a bunch of preprocessor macros to make it appear more 'object
oriented'. Essentially they create their own OO-language based on
macros which might be 'instructive' but also is rather uninviting for
most real world developers. See e.g.

http://www.ddj.com/184406396
http://www.pvv.ntnu.no/~hakonhal/main.cgi/c/classes
http://www.embedded.com/97/fe29712.htm

You find many links when you search for 'object-oriented programming
in C'.

Best wishes,
Roland Pibinger
 
T

Thierry Chappuis

Roland Pibinger a écrit :
Many approaches use function pointers or hand-written vtables to
emulate polymorphism. But, AFAIK, they all hide the implementation
under a bunch of preprocessor macros to make it appear more 'object
oriented'. Essentially they create their own OO-language based on
macros which might be 'instructive' but also is rather uninviting for
most real world developers. See e.g.

Even with hand-written vtables, it is not a requirement to hide
implementation under macros and the resulting code does not seem to
heavy to handle and maintain. Do you think emulating inheritance and
polymorphism in this way is bad C practice?

Many thanks for the links. I'll study these differents approaches.

Best reagards

Thierry
 
D

Default User

CBFalconer said:
Chris Dollin wrote:

That is how earlier C++ systems were implemented. Look up Cfront.


I think, but wouldn't swear to it, that Comeau can provide a C++
compiler that produces C code.




Brian
 
R

Roland Pibinger

Even with hand-written vtables, it is not a requirement to hide
implementation under macros and the resulting code does not seem to
heavy to handle and maintain. Do you think emulating inheritance and
polymorphism in this way is bad C practice?

Not necessarily. Usability, as always, is the criterion. A solution
that avoids e.g. macros, void* parameters and casts required from
users has a higher probability of being accepted.

Best wishes,
Roland Pibinger
 
T

Thierry Chappuis

Roland Pibinger a écrit :
Not necessarily. Usability, as always, is the criterion. A solution
that avoids e.g. macros, void* parameters and casts required from
users has a higher probability of being accepted.

Best wishes,
Roland Pibinger

Thank you for your valuable input.

Best wishes

Thierry
 
L

Laurent Deniau

Roland said:
Not necessarily. Usability, as always, is the criterion. A solution
that avoids e.g. macros

Why do you think that macros should be avoided?
void* parameters and casts required from
users has a higher probability of being accepted.

Agreed.

a+, ld.
 
R

Roland Pibinger

Why do you think that macros should be avoided?

Macros usually obfuscate code more than clarify it. They make code
difficult to understand and write. Also error messages become harder
to decrypt. The following example hardly resembles procedural C code
any more:

#undef OBJECT
#define OBJECT person

BASEOBJECT_INTERFACE

char const* private(name);

BASEOBJECT_METHODS

void constMethod(print);

ENDOF_INTERFACE

CLASS_INTERFACE

t_person *const classMethod_(new) char const name[] __;
void method_(init) char const name[] __;
void method_(copy) t_person const*const per __;

ENDOF_INTERFACE

I expect from C code that it uses common C styles and idioms. IMO,
heavy use of the preprocessor is a means to avoid C programming.

Best regards,
Roland Pibinger
 
T

Thierry Chappuis

Roland Pibinger a écrit :
Why do you think that macros should be avoided?

Macros usually obfuscate code more than clarify it. They make code
difficult to understand and write. Also error messages become harder
to decrypt. The following example hardly resembles procedural C code
any more:

#undef OBJECT
#define OBJECT person

BASEOBJECT_INTERFACE

char const* private(name);

BASEOBJECT_METHODS

void constMethod(print);

ENDOF_INTERFACE

CLASS_INTERFACE

t_person *const classMethod_(new) char const name[] __;
void method_(init) char const name[] __;
void method_(copy) t_person const*const per __;

ENDOF_INTERFACE

I expect from C code that it uses common C styles and idioms. IMO,
heavy use of the preprocessor is a means to avoid C programming.

I cannot agree with your point of view. In the above-mentioned example,
macros only hide the implementation of the object system. Such
low-level details are probably irrelevant to the user.

All the logic of the a program is implemented in standardized C code.
How about the use the presented person abstraction:

t_person *const per = person.new("Thierry");
sendMsg(per, print);
delete(per);

or
t_person *const per = person.new("Thierry");
per->__vptr->print(per);
delete(per);

For me it is C code: t_person is a structure or an union (in the
present case) and new points to a function responsible to create the
object. You can easily avoid the use of the macro sendMsg to call the
function print if you have some knowledge of the implementation (the
essentiel of the model can be understood from ooc.h). And you use
delete as you would use a wrapper free. What is not C in this code?

Thierry
 
L

Laurent Deniau

Roland said:
Why do you think that macros should be avoided?


Macros usually obfuscate code more than clarify it. They make code
difficult to understand and write. Also error messages become harder
to decrypt. The following example hardly resembles procedural C code
any more:

#undef OBJECT
#define OBJECT person

BASEOBJECT_INTERFACE

char const* private(name);

BASEOBJECT_METHODS

void constMethod(print);

ENDOF_INTERFACE

CLASS_INTERFACE

t_person *const classMethod_(new) char const name[] __;
void method_(init) char const name[] __;
void method_(copy) t_person const*const per __;

ENDOF_INTERFACE

I expect from C code that it uses common C styles and idioms. IMO,
heavy use of the preprocessor is a means to avoid C programming.

I partially agree. I have often said here or on fr.c.l.c that OOPC was
more a didactic paper to explain some facettes of C++. I have never used
it nor recommended to use it for professionnal developement.

After OOPC I developped during my free time, 3 other frameworks to do OO
in C (OOC-1.0, OOC-2.0 and COS = C Object System). I will not go into
the details and the history of this evolution over the past 6 years (if
you read french, you may have a look on many threads on this topic on
fr.c.l.c).

About the usage of the macros, and if you have a small knowledge of CLOS
and Objective-C syntax, what do you think of following working (but
incomplete) C99 code which uses COS macros to defines generics, class
and multimethods as generics specialisations, does it looks so different
from what we find in OO langages?

// sample of Generic.h
defgeneric(OBJ, gGetAt , (Container, Position));
defgeneric(OBJ, gGetAtIdx, (Container, (int)idx);
defgeneric(OBJ, gPutAt , (Container, Object, Position));
defgeneric(OBJ, gPutAtIdx, (Container, Object), (int)idx);

// sample of Generic.c
makgeneric(OBJ, gGetAt , (Container, Position));
makgeneric(OBJ, gPutAt , (Container, Object, Position));
makgeneric(OBJ, gPutAtIdx, (Container, Object), (int)idx);

// sample of Array.h
#include <cos/Collection.h>

defclass(Array, Collection)
int len;
OBJ *data;
endclass

// sample of Array.c
#include <cos/Array.h>

makclass(Array, Collection);

defmethod(OBJ, gPutAtIdx, (Array, Object), (int)idx)
{
if (0 > idx && idx >= self1->len) {
useclass(ExOutOfBound);
gThrow(gNewWithStr(ExOutOfBound, "invalid array index"));
}

if (self1->data[idx] != self2) {
if (self1->data[idx] != NIL)
gRelease(self1->data[idx]);

self1->data[idx] = gRetain(self2);
}

retmethod(self1);
}

// sample of main.c
#include <stdio.h>
#include <cos/cos.h>

useclass(Array,Integer,ExOutOfBound);

int main(void)
{
TRY
OBJ array = gNewWithSize(Array, 100);
OBJ value = gNewWithInt(Integer, 10);

gPutAtIdx(array, value, 15); // OK
gPutAtIdx(array, value, 200); // throw ExOutOfBound

CATCH(ExOutOfBound, ex)
fprintf(stderr, "exception %s thrown (%s,%i) and caught (%s,%i):"
"%s\n",
gNameStr(ex), ex_file, ex_line, __FILE__, __LINE__,
gReasonStr(ex));

FINALLY(ex)
gRelease(ex);
gRelease(array);
gRelease(value);
ENDTRY;
}

Note that generics are C functions (you can take a pointer to them) and
I use the convention (it's only a convention, not a requirement) to call
them gGeneric or vGeneric (variadic) to mark the difference of their
role with C functions.

a+, ld.
 
L

Laurent Deniau

Laurent said:
defmethod(OBJ, gPutAtIdx, (Array, Object), (int)idx)
{
if (0 > idx && idx >= self1->len) {
useclass(ExOutOfBound);
gThrow(gNewWithStr(ExOutOfBound, "invalid array index"));
}

if (self1->data[idx] != self2) {
if (self1->data[idx] != NIL)
gRelease(self1->data[idx]);

self1->data[idx] = gRetain(self2);
}

retmethod(self1);
}

Sorry this closing brace must be replaced by 'endmethod' and its
corresponding openning brace must be removed.

a+, ld.
 
E

E. Robert Tisdale

Thierry said:
I'm interested in techniques used to program in an object-oriented way
using the C ANSI language. I'm studying the GObject library and Laurent
Deniau's OOPC framework published on his web site at
http://ldeniau.web.cern.ch/ldeniau/html/oopc/oopc.html. The approach is
very instructive. I know that I could do much of this stuff with e.g.
C++, but the intellectual challenge of implementing these concepts with
pure ANSI C is relevant to me.

Are you aware of another approaches? Any experience in using such
techniques in production code? The use of GObject seems to be well
implemented in the GNOME world, but I didn't find much about Laurent
Deniau's OOPC. Have you some comments about the strengths and drawbacks
of such techniques?

Please find attached a C implementation
of Bjarne Stroustrup's famous Shape class.

C is not an object oriented programming language
but you can write object oriented programs in C
including programs that implement run-time polymorphism.
The fprintf function on type *FILE is an example.
You don't need a language translator or a special library.

A program is not an object oriented programming language
just because it is written in an object oriented programming language.
All the popular object oriented programming languages are
procedural programming languages first.
An object oriented program must actually use
the object oriented features of the language.
Object oriented programming is first of all a programming style.

The problem with C is that it does not directly support features
such as inheritance and run-time polymorphism. Good C programmers
have always used an object oriented programming style
but implementing object oriented programs in C is problematic --
tedious and error prone. The C++ programming language provides
direct support for object oriented programming
so it is much easier and more reliable.

> cat Point.h
#ifndef GUARD_Point_h
#define GUARD_Point_h 1

typedef struct Point {
// representation
double X;
double Y;
} Point;
// functions
double
Point_x(const Point* p);
double
Point_y(const Point* p);
Point*
Point_initialize(Point* p, double x, double y);
// constructors
Point
Point_createExplicit(double x, double y);
Point
Point_createDefault(void);
Point*
Point_newExplicit(double x, double y);
Point*
Point_newDefault(void);
// destructors
void
Point_destroy(const Point* p);
void
Point_delete(const Point* p);

#endif // GUARD_Point_h

> cat Point.c
// gcc -Wall -std=c99 -pedantic -I. -O2 -c Point.c

#include<Point.h>
#include<stdlib.h>

// functions
double
Point_x(const Point* p) {
return p->X; }
double
Point_y(const Point* p) {
return p->Y; }
Point*
Point_initialize(Point* p, double x, double y) {
p->X = x;
p->Y = y;
return p;
}
// constructors
Point
Point_createExplicit(double x, double y) {
Point p;
Point_initialize(&p, x, y);
return p;
}
Point
Point_createDefault(void) {
return Point_createExplicit(0.0, 0.0); }
Point*
Point_newExplicit(double x, double y) {
Point* p = (Point*)malloc(sizeof(Point));
Point_initialize(p, x, y);
return p; }
Point*
Point_newDefault(void) {
return Point_newExplicit(0.0, 0.0); }
// destructors
void
Point_destroy(const Point* p) { }
void
Point_delete(const Point* p) {
Point_destroy(p);
free((void*)p); }

> cat Color.h
#ifndef GUARD_Color_h
#define GUARD_Color_h 1
typedef struct Color {
// representation
unsigned int R; // red
unsigned int G; // green
unsigned int B; // blue
} Color;
// functions
unsigned int
Color_red(const Color *c);
unsigned int
Color_green(const Color *c);
unsigned int
Color_blue(const Color *c);
Color*
Color_initialize(Color* c,
unsigned int r,
unsigned int g,
unsigned int b);
// constructors
Color
Color_createExplicit(
unsigned int r,
unsigned int g,
unsigned int b);
Color
Color_createDefault(void);
Color*
Color_newExplicit(
unsigned int r,
unsigned int g,
unsigned int b);
Color*
Color_newDefault(void);
// destructor
void
Color_destroy(const Color *c);
void
Color_delete(const Color *c);

#endif // GUARD_Color_h

> cat Color.c
// gcc -Wall -std=c99 -pedantic -I. -O2 -c Color.c

#include<Color.h>
#include<stdlib.h>

// functions
unsigned int
Color_red(const Color *c) {
return c->R; }
unsigned int
Color_green(const Color *c) {
return c->G; }
unsigned int
Color_blue(const Color *c) {
return c->B; }
Color*
Color_initialize(Color* c,
unsigned int r,
unsigned int g,
unsigned int b) {
c->R = r;
c->G = g;
c->B = b;
return c;
}
// constructors
Color
Color_createExplicit(
unsigned int r,
unsigned int g,
unsigned int b) {
Color c;
Color_initialize(&c, r, g, b);
return c; }
Color
Color_createDefault(void) {
return Color_createExplicit(0, 0, 0); }
Color*
Color_newExplicit(
unsigned int r,
unsigned int g,
unsigned int b) {
Color* c = (Color*)malloc(sizeof(Color));
Color_initialize(c, r, g, b);
return c; }
Color*
Color_newDefault(void) {
return Color_newExplicit(0, 0, 0); }
// destructors
void
Color_destroy(const Color *c) { }
void
Color_delete(const Color *c) {
Color_destroy(c);
free((void*)c); }

> cat Shape.h
#ifndef GUARD_Shape_h
#define GUARD_Shape_h 1

#include<Point.h>
#include<Color.h>

typedef struct Shape {
// representation
const
void* V; // virtual function table pointer
Point P;
Color C;
} Shape;
// functions
const Point*
Shape_point(const Shape* s);
const Color*
Shape_color(const Shape* s);
void
actualShape_draw(const Shape* s);
double
actualShape_area(const Shape* s);
void
Shape_draw(const Shape* s); // virtual function
double
Shape_area(const Shape* s); // virtual function
Shape*
Shape_initialize(Shape* s,
const void* v,
const Point* p,
const Color* c);
// constructors
Shape
Shape_createExplicit(
const Point* p,
const Color* c);
Shape
Shape_createDefault(void);
Shape*
Shape_newExplicit(
const Point* p,
const Color* c);
Shape*
Shape_newDefault(void);
// destructors
void
Shape_destroy(const Shape* s);
void
Shape_delete(const Shape* s);

#endif // GUARD_Shape_h

> cat Shape.c
// gcc -Wall -std=c99 -pedantic -I. -O2 -c Shape.c

#include<stdio.h>
#include<Shape.h>
#include<stdlib.h>

// functions
const Point*
Shape_point(const Shape* s) {
return &(s->P); }
const Color*
Shape_color(const Shape* s) {
return &(s->C); }
void
actualShape_draw(const Shape* s) {
fprintf(stderr, "Shape_draw(const Shape*)\n");
fflush(stderr); }
double
actualShape_area(const Shape* s) {
fprintf(stderr, "Shape_area(const Shape*)\n");
fflush(stderr);
return 0.0; }

typedef struct Shape_vtable_t {
void (*Shape_draw)(const Shape*);
double (*Shape_area)(const Shape*);
} Shape_vtable_t;
static const
Shape_vtable_t
Shape_vtable = {actualShape_draw, actualShape_area};

void
Shape_draw(const Shape* s) { // virtual function
((Shape_vtable_t*)(s->V))->Shape_draw(s); }
double
Shape_area(const Shape* s) { // virtual function
return ((Shape_vtable_t*)(s->V))->Shape_area(s); }
Shape*
Shape_initialize(Shape* s,
const
void* v,
const
Point* p,
const
Color* c) {
s->V = v;
Point_initialize(&(s->P), Point_x(p), Point_y(p));
Color_initialize(&(s->C), Color_red(c), Color_green(c), Color_blue(c));
return s; }
// constructors
Shape
Shape_createExplicitShape(
const Point* p,
const Color* c) {
Shape s;
Shape_initialize(&s, (const void*)(&Shape_vtable), p, c);
return s; }
Shape
Shape_createDefault(void) {
Shape s;
Point p = Point_createDefault();
Color c = Color_createDefault();
Shape_initialize(&s, (const void*)(&Shape_vtable), &p, &c);
Color_destroy(&c);
Point_destroy(&p);
return s; }
Shape*
Shape_newExplicitShape(
const Point* p,
const Color* c) {
Shape* s = (Shape*)malloc(sizeof(Shape));
Shape_initialize(s, (const void*)(&Shape_vtable), p, c);
return s; }
Shape*
Shape_newDefault(void) {
Shape* s = (Shape*)malloc(sizeof(Shape));
Point p = Point_createDefault();
Color c = Color_createDefault();
Shape_initialize(s, (const void*)(&Shape_vtable), &p, &c);
Color_destroy(&c);
Point_destroy(&p);
return s; }
// destructors
void
Shape_destroy(const Shape* s) {
Color_destroy(Shape_color(s));
Point_destroy(Shape_point(s));
}
void
Shape_delete(const Shape* s) {
Shape_destroy(s);
free((void*)s); }

> cat Circle.h
#ifndef GUARD_Circle_h
#define GUARD_Circle_h 1

#include<Shape.h>

typedef struct Circle {
Shape S; // public base class
double R; // radius
} Circle;
// functions
const Shape*
Circle_shape(const Circle* c);
double
Circle_radius(const Circle* c);
void
actualCircle_draw(const Circle* c);
double
actualCircle_area(const Circle* c);
void
Circle_draw(const Circle* c); // virtual function
double
Circle_area(const Circle* c); // virtual function
Circle*
Circle_initialize(Circle* c, const Shape* s, double r);
// constructors
Circle
Circle_createDefault(void);
Circle
Circle_createExplicit(const Shape* s, double r);
Circle*
Circle_newDefault(void);
Circle*
Circle_newExplicit(const Shape* s, double r);
// destructors
void
Circle_destroy(const Circle* c);
void
Circle_delete(const Circle* c);

#endif // GUARD_Circle_h

> cat Circle.c
// gcc -Wall -std=c99 -pedantic -I. -O2 -c Circle.c

#include<math.h>
#include<stdio.h>
#include<Circle.h>
#include<stdlib.h>

// functions
const Shape*
Circle_shape(const Circle* c) {
return &(c->S); }
double
Circle_radius(const Circle* c) {
return c->R; }
void
actualCircle_draw(const Circle* c) {
fprintf(stderr, "Circle_draw(const Circle*)\n");
fflush(stderr); }
double
actualCircle_area(const Circle* c) {
const
double pi = 3.14159265358979323846;
const
double r = Circle_radius(c);
fprintf(stderr, "Circle_area(const Circle*)\n");
fflush(stderr);
return pi*r*r; }

typedef struct Circle_vtable_t {
void (*Circle_draw)(const Circle*);
double (*Circle_area)(const Circle*);
} Circle_vtable_t;
static const
Circle_vtable_t
Circle_vtable = {actualCircle_draw, actualCircle_area};
void
Circle_draw(const Circle* c) { // virtual function
((Circle_vtable_t*)(c->S.V))->Circle_draw(c);
}
double
Circle_area(const Circle* c) { // virtual function
return ((Circle_vtable_t*)(c->S.V))->Circle_area(c);
}

Circle*
Circle_initialize(Circle* c, const Shape* s, double r) {
Shape_initialize(&(c->S),
(void*)(&Circle_vtable),
Shape_point(s),
Shape_color(s));
c->R = r;
return c; }

// constructors
Circle
Circle_createExplicit(const Shape* s, double r) {
Circle c;
Circle_initialize(&c, s, r);
return c; }
Circle
Circle_createDefault(void) {
Circle c;
const
Shape s = Shape_createDefault();
Circle_initialize(&c, &s, 0.0);
Shape_destroy(&s);
return c; }
Circle*
Circle_newExplicit(const Shape* s, double r) {
Circle* c = (Circle*)malloc(sizeof(Circle));
Circle_initialize(c, s, r);
return c; }
Circle*
Circle_newDefault(void) {
Circle* c = (Circle*)malloc(sizeof(Circle));
const
Shape s = Shape_createDefault();
Circle_initialize(c, &s, 0.0);
Shape_destroy(&s);
return c; }
// destructors
void
Circle_destroy(const Circle* c) {
Shape_destroy(Circle_shape(c));
}
void
Circle_delete(const Circle* c) {
Shape_destroy(Circle_shape(c));
free((void*)c); }

> cat main.c
// gcc -Wall -std=c99 -pedantic -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
Shape s = Shape_createDefault();
const
Circle c = Circle_createExplicit(&s, 2.0);
Shape_draw((const Shape*)(&c));
fprintf(stdout, "%g = radius\t %g = area\n",
Circle_radius(&c), Shape_area((const Shape*)(&c)));
return 0;
}

> cat Makefile
CC=gcc
DEFINES=
INCLUDE=-I.
OPTIONS=-Wall -std=c99 -pedantic -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 -f main $(OBJECTS)
 
R

Roland Pibinger

Please find attached a C implementation
of Bjarne Stroustrup's famous Shape class.

Your approach is similar to the results of my experiments with OO in
C. You can increase encapsulation when you only forward declare your
structs (e.g. struct Shape) in the header files. Also some functions
(e.g. actualShape_draw) can be removed form the header and made
'private', i.e. static, in the respecive *.c file.

Best regards,
Roland Pibinger
 
R

Roland Pibinger

There's a book/paper called "Object-Oriented Programming with ANSI-C"
by Axel-Tobias Schreiner, available as a PDF at
http://www.planetpdf.com/codecuts/pdfs/ooc.pdf. It explores this area
to a great extend and I'd really recommend it.

It's awful! IIRC, it needs AWK as preprocessor and uses mostly untyped
void* pointers. IIRC, the book was never published in English because
it found no publisher. Guess why.

Regards,
Roland Pibinger
 
M

matevzb

It's awful! IIRC, it needs AWK as preprocessor and uses mostly untyped
void* pointers.
That was just my opinion and you don't have to agree. I found it
useful, as it demonstrates what can be done in C. Void pointers can be
dangerous, but then again, what would C be without them? =)
(AWK is optional, depending on what you want to do)
IIRC, the book was never published in English because
it found no publisher. Guess why.
Many books haven't been published in English. That doesn't mean they're
bad books. (same goes for the authors)
 
C

Chris Thomasson

Thierry Chappuis said:
Hi,

I'm interested in techniques used to program in an object-oriented way
using the C ANSI language. I'm studying the GObject library and Laurent
Deniau's OOPC framework published on his web site at
http://ldeniau.web.cern.ch/ldeniau/html/oopc/oopc.html. The approach is
very instructive. I know that I could do much of this stuff with e.g.
C++, but the intellectual challenge of implementing these concepts with
pure ANSI C is relevant to me.

Are you aware of another approaches?

[...]

Check this crap out:

http://groups.google.com/group/comp.lang.c/msg/6cf857051ca4029b


;^)
 
E

E. Robert Tisdale

Roland said:
Your approach is similar to the results of my experiments with OO in
C. You can increase encapsulation when you only forward declare your
structs (e.g. struct Shape) in the header files.

Unfortunately, your approach precludes automatic function inlining.
Also some functions (e.g. actualShape_draw) can be removed form the header
and made 'private', i.e. static, in the respecive *.c file.

This would preclude any explicit call to function actualShape_draw.
An optimizing C++ compiler will elide the virtual {messenger} function
and call the actual function directly
if it can determine the actual type at compile time.
 
C

CBFalconer

E. Robert Tisdale said:
.... snip ...

This would preclude any explicit call to function actualShape_draw.
An optimizing C++ compiler will elide the virtual {messenger}
function and call the actual function directly if it can determine
the actual type at compile time.

This is c.l.c. comp.lang.c++ is thataway ------>
 
T

Thierry Chappuis

matevzb a écrit :
There's a book/paper called "Object-Oriented Programming with ANSI-C"
by Axel-Tobias Schreiner, available as a PDF at
http://www.planetpdf.com/codecuts/pdfs/ooc.pdf. It explores this area
to a great extend and I'd really recommend it.

Hi,

The Schreiner's approach uses heavy awk preprocessing, and too many
generic (void *) pointers. It is not the most convincing paper I've
read on the subject.

Thank you for your contribution

Thierry
 
T

Thierry Chappuis

Chris Thomasson a écrit :
Thierry Chappuis said:
Hi,

I'm interested in techniques used to program in an object-oriented way
using the C ANSI language. I'm studying the GObject library and Laurent
Deniau's OOPC framework published on his web site at
http://ldeniau.web.cern.ch/ldeniau/html/oopc/oopc.html. The approach is
very instructive. I know that I could do much of this stuff with e.g.
C++, but the intellectual challenge of implementing these concepts with
pure ANSI C is relevant to me.

Are you aware of another approaches?

[...]

Check this crap out:

http://groups.google.com/group/comp.lang.c/msg/6cf857051ca4029b


Thank you for the link! Bookmarked!

Thierry
 

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

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,007
Latest member
obedient dusk

Latest Threads

Top