Nothing Special   »   [go: up one dir, main page]

Oop in C

Download as pdf or txt
Download as pdf or txt
You are on page 1of 5
At a glance
Powered by AI
Some of the key challenges in implementing OOP in C include lack of built-in support for concepts like inheritance, polymorphism, and automatic memory management.

Some ways to implement OOP concepts in C include using structs to represent objects and function pointers to represent virtual functions for polymorphism.

The main challenges are lack of built-in support for concepts like constructors, destructors, and garbage collection. Memory management must be handled manually.

Object-Orientation in C

Can someone please share a set of nif ty preprocessor hacks (ANSI C89/ISO C90 compatible please) which enable some kind of ugly (but usable) objectorientation in C? I am f amiliar with a f ew dif f erent object-oriented languages, so please don't respond with answers like "Learn C++!". I hav e read "ObjectOriented Programming With ANSI C" (beware: pdf) and sev eral other interesting solutions, but I'm mostly interested in y ours :-)!

See also Can y ou write object oriented code in C?


c oop object

edited Aug 11 '09 at 22:58

community wiki 6 rev s, 3 users 78% Anthony Cuozzo

Can I respond to learn D and use the c compatible abi f or where y ou really need C. digitalmars.com/d Tim Matthews Jan 6 '09 at 11:53 Not really . I work with some embedded sy stems which only really hav e a C compiler av ailable. anon Jan 6 '09 at 21:51 @Dinah: Thank y ou f or the "See also". That post was interesting. anon Jan 6 '09 at 22:20 The interesting question seems to be why would y ou want a pre-processor hack of OOP on C. Caly th Jan 8 '09 at 19:13 @Caly th: I f ind that OOP is usef ul and "I work with some embedded sy stems which only really hav e a C compiler av ailable" (f rom abov e). Moreov er, don't y ou f ind nif ty preprocessor hacks interesting to look at? anon Jan 9 '09 at 21:09

f eedback

10 Answers
C Object Sy stem (COS) sounds promising (it's still in alpha v ersion). It tries to keep minimal the av ailable concepts f or the sake of simplicity and f lexibility : unif orm object oriented programming including open classes, metaclasses, property metaclasses, generics, multimethods, delegation, ownership, exceptions, contracts and closures. There is a draf t paper (PDF) that describes it. Exception in C is a C89 implementation of the TRY -CATCH-FINALLY f ound in other OO languages. It comes with a testsuite and some examples. Both by Laurent Deniau, which is working a lot on OOP in C. answered Jan 6 '09 at 7:51 philippe

10.4k

40

Very interesting! anon Jan 6 '09 at 21:52

f eedback

I would adv ise against preprocessor (ab)use to try and make C sy ntax more like that of another more object-oriented language. At the most basic lev el, y ou just use plain structs as objects and pass them around by pointers: struct monkey { float age; bool is_male; int happiness; }; void monkey_dance(struct monkey *monkey) { /* do a little dance */ } To get things like inheritance and poly morphism, y ou hav e to work a little harder. Y ou can do manual inheritance by hav ing the f irst member of a structure be an instance of the superclass, and then y ou can cast around pointers to base and deriv ed classes f reely : struct base { /* base class members */ };

struct derived { struct base super; /* derived class members */ }; struct derived d; struct base *base_ptr = (struct base *)&d; // upcast struct derived derived_ptr = (struct derived *)base_ptr; // downcast void poly morphism (i.e. v irtual f unctions), To get derived1_init(struct derived1 *d) y ou use f unction pointers, and optionally f unction pointer tables, also known as v irtual tables or v tables: { d->super.vtable = &derived1_vtable; /* init base members d->super.foo */ /* init derived1 members d->foo */ } struct derived2 { struct base super; /* derived2 members */ }; void derived2_dance(struct derived2 *d) { /* implementation of derived2's dance function */ } void derived2_jump(struct derived2 *d, int how_high) { /* implementation of derived2's jump function */ } struct base_vtable derived2_vtable = { &derived2_dance, &derived2_jump }; void derived2_init(struct derived2 *d) { d->super.vtable = &derived2_vtable; /* init base members d->super.foo */ /* init derived1 members d->foo */ } int main(void) { /* OK! We're done with our declarations, now we can finally do some polymorphism in C */ struct derived1 d1; derived1_init(&d1); struct derived2 d2; derived2_init(&d2); struct base *b1_ptr = (struct base *)&d1; struct base *b2_ptr = (struct base *)&d2; base_dance(b1_ptr); /* calls derived1_dance */ base_dance(b2_ptr); /* calls derived2_dance */ base_jump(b1_ptr, 42); /* calls derived1_jump */ base_jump(b2_ptr, 42); /* calls derived2_jump */ return 0; } And that's how y ou do poly morphism in C. It ain't pretty , but it does the job. There are some sticky issues inv olv ing pointer casts between base and deriv ed classes, which are saf e as long as the base class is the f irst member of the deriv ed class. Multiple inheritance is much harder - in that case, in order to case between base classes other than the f irst, y ou need to manually adjust y our pointers based on the proper of f sets, which is really tricky and error-prone. Another (tricky ) thing y ou can do is change the dy namic ty pe of an object at runtime! Y ou just reassign it a new v table pointer. Y ou can ev en selectiv ely change some of the v irtual f unctions while keeping others, creating new hy brid ty pes. Just be caref ul to create a new v table instead of modif y ing the global v table, otherwise y ou'll accidentally af f ect all objects of a giv en ty pe. edited Jan 6 '09 at 9:46 philippe answered Jan 6 '09 at 5:09 Adam Rosenf ield 1 9 40

10.4k

79.2k

11

115

211

Adam, the f un of changing the global v table of a ty pe is to simulate duck-ty ping in C. :) jmucchiello Sep 28 '09 at 14:59 Now I pity C++... Well of course the C++ sy ntax is clearer, but since it's not a triv ial sy ntax, I'm mitigated. I wonder if something hy brid between C++ and C could be achiev ed, so v oid* would still be v alid castable ty pe. The part with struct derived {struct base super;}; is obv ious to guess how it works, since by the by tes order it's correct. gokoon Jan 4 at 15:41

f eedback

(ripped f rom How to write production C code? [closed]) I once worked with a C library that was implemented in a way that struck me as quite elegant. They had written, in C, a way to def ine objects, then inherit f rom them so that they were as extensible as a C++ object. The basic idea was this: Each object had its own f ile Public f unctions and v ariables are def ined in the .h f ile f or an object Priv ate v ariables and f unctions were only located in the .c f ile To "inherit" a new struct is created with the f irst member of the struct being the object to inherit f rom Inheriting is dif f icult to describe, but basically it was this: struct vehicle { int power; int weight; } Then in another f ile: struct van { struct vehicle base; int cubic_size; }

Then y ou could hav e a v an created in memory , and being used by code that only knew about v ehicles: struct van my_van; struct vehicle *something = &my_van; vehicle_function( something ); It worked beautif ully , and the .h f iles def ined exactly what y ou should be able to do with each object. answered Jan 6 '09 at 4:28 Kiev eli

4,714

14

28

I'd like to know more about how this worked :) J Cooper Jan 6 '09 at 4:48 I really like this solution, except that all of the "object"'s internals are public. Sof tware Monkey Jan 6 '09 at 5:18

@Sof tware Monkey : C has no access control. The only way to hide implementation details is to interact through opaque pointers, which can get pretty painf ul, since all f ields would need to be accessed through accessor methods which probably can't be inlined. Adam Rosenf ield Jan 6 '09 at 5:26 @Adam: Compilers supporting link-time optimizations will inline them just f ine... Christoph Jan 6 '09 at 13:01

If y ou do this, y ou should also ensure that all the f unctions in the .c f ile that are not def ined as public are def ined as static so they don't end up as named f unctions in y our object f iles. That ensures no one can f ind their names in the link phase. jmucchiello Sep 28 '09 at 15:01

show 1 more comment f eedback

The GNOME desktop f or Linux is written in object-oriented C, and it has an object model called "GObject" which supports properties, inheritance, poly morphism, as well as some other goodies like ref erences, ev ent handling (called "signals"), runtime ty ping, priv ate data, etc. It includes preprocessor hacks to do things like ty pecasting around in the class hierarchy , etc. Here's an example class I wrote f or GNOME (things like gchar are ty pedef s): Class Source Class Header Inside the GObject structure there's a GTy pe integer which is used as a magic number f or GLib's dy namic ty ping sy stem (y ou can cast the entire struct to a "GTy pe" to f ind it's ty pe). edited Jan 7 '09 at 11:50 answered Jan 6 '09 at 5:06 James Cape

341

unf ortunately , the read me/tutorial f ile (wiki link) is not working and there is only ref erence manual f or that(i am talking about GObject and not GTK). please prov ide some tutorial f iles f or the same ... FL4SOF Jan 6 '09 at 5:22 See stackov erf low.com/questions/500501/ f mark Nov 6 '10 at 12:35

Was this post usef ul to y ou?

Yes

No

f f mpeg (a toolkit f or v ideo processing) is written in straight C (and assembly language), but using an object-oriented sty le. It's f ull of structs with f unction pointers. There are a set of f actory f unctions that initialize the structs with the appropriate "method" pointers. answered Jan 6 '09 at 4:31 Mr Fooz

8,479

14

37

I'll take a look at the source in a little while. I'll respond with my impressions of it either tonight or sometime tomorrow. anon Jan 6 '09 at 4:48 i don't see any f actory f unctions in it(f f mpeg), rather it doesnt seem to be using poly morphism/inheritance ( triv ial way suggested abov e). FL4SOF Jan 6 '09 at 5:39 av codec_open is one f actory f unction. It stuf f s f unction pointers into a AVCodecContext struct (like draw_horiz_band). If y ou look at FF_COMMON_FRAME macro usage in av codec.h, y ou'll see something akin to inheritance of data members. IMHO, f f mpeg prov es to me that OOP is best done in C++, not C. Mr Fooz Jan 6 '09 at 23:41

f eedback

Slightly of f topic but the original C++ compiler, c-f ront, compiled C++ to C and then to assembler. Preserv ed here answered Aug 5 '09 at 9:55 community wiki zebrabox

I'v e actually seen it bef ore. I believ e it was a nice piece of work. anon Aug 5 '09 at 10:11 @Anthony Cuozzo : Stan Lippman wrote a great book called 'C++ - Inside the object model' where he related a lot of his experiences and design decisions in writing and maintaining c-f ront. It's still a good read and helped me immensely when transitioning f rom C to C++ many y ears back zebrabox Aug 5 '09 at 10:40

f eedback

I used to do this kind of thing in C, bef ore I knew what OOP was. Following is an example, which implements a data-buf f er which grows on demand, giv en a minimum size, increment and maximum size. This particular implementation was "element" based, which is to say it was designed to allow a list-like collection of any C ty pe, not just a v ariable length by te-buf f er. The idea is that the object is instantiated using the xxx_crt() and deleted using xxx_dlt(). Each of the "member" methods takes a specif ically ty ped pointer to operate on. I implemented a linked list, cy clic buf f er, and a number of other things in this manner. I must conf ess, I hav e nev er giv en any thought on how to implement inheritance with this approach. I imagine that some blend of that of f ered by Kiev eli might be a good path. dtb.c: #include <limits.h> #include <string.h> #include <stdlib.h> static void dtb_xlt(void *dst, const void *src, vint len, const byte *tbl); DTABUF *dtb_crt(vint minsiz,vint incsiz,vint maxsiz) { DTABUF *dbp; if(!minsiz) { return NULL; } if(!incsiz) { incsiz=minsiz; } if(!maxsiz || maxsiz<minsiz) { maxsiz=minsiz; } if(minsiz+incsiz>maxsiz) { incsiz=maxsiz-minsiz; } if((dbp=(DTABUF*)malloc(sizeof(*dbp))) == NULL) { return NULL; } memset(dbp,0,sizeof(*dbp)); dbp->min=minsiz; dbp->inc=incsiz; dbp->max=maxsiz; dbp->siz=minsiz; dbp->cur=0; if((dbp->dta=(byte*)malloc((vuns)minsiz)) == NULL) { free(dbp); return NULL; } return dbp; } DTABUF *dtb_dlt(DTABUF *dbp) { if(dbp) { free(dbp->dta); free(dbp); } return NULL; } vint dtb_adddta(DTABUF *dbp,const byte *xlt256,const void *dtaptr,vint dtalen) { if(!dbp) { errno=EINVAL; return -1; } if(dtalen==-1) { dtalen=(vint)strlen((byte*)dtaptr); } if((dbp->cur + dtalen) > dbp->siz) { void *newdta; vint newsiz; if((dbp->siz+dbp->inc)>=(dbp->cur+dtalen)) { newsiz=dbp->siz+dbp->inc; } else { newsiz=dbp->cur+dtalen; } if(newsiz>dbp->max) { errno=ETRUNC; return -1; } if((newdta=realloc(dbp->dta,(vuns)newsiz))==NULL) { return -1; } dbp->dta=newdta; dbp->siz=newsiz; } if(dtalen) { if(xlt256) { dtb_xlt(((byte*)dbp->dta+dbp->cur),dtaptr,dtalen,xlt256); } else { memcpy(((byte*)dbp->dta+dbp->cur),dtaptr,(vuns)dtalen); } dbp->cur+=dtalen; } return 0; } static void dtb_xlt(void *dst,const void *src,vint len,const byte *tbl) { byte *sp,*dp; dtb.h typedef _Packed struct { vint min; vint inc; vint max; vint siz; vint cur; void *dta; } DTABUF; #define dtb_dtaptr(mDBP) #define dtb_dtalen(mDBP) DTABUF DTABUF vint vint vint vint void

/* initial size /* increment size /* maximum size /* current size /* current data length /* data pointer

*/ */ */ */ */ */

(mDBP->dta) (mDBP->cur)

*dtb_crt(vint minsiz,vint incsiz,vint maxsiz); *dtb_dlt(DTABUF *dbp); dtb_adddta(DTABUF *dbp,const byte *xlt256,const void *dtaptr,vint dtalen); dtb_addtxt(DTABUF *dbp,const byte *xlt256,const byte *format,...); dtb_rmvdta(DTABUF *dbp,vint len); dtb_reset(DTABUF *dbp); *dtb_elmptr(DTABUF *dbp,vint elmidx,vint elmlen);

PS: v int was simply a ty pedef of int - I used it to remind me that it's length was v ariable f rom platf orm to platf orm (f or porting). edited Aug 8 '09 at 3:04 answered Jan 6 '09 at 5:14 Sof tware Monkey

15.5k

38

71

holy moly , this could win an obf uscated C contest! i like it! :) banister Jul 29 '09 at 19:58

f eedback

If y ou think of methods called on objects as static methods that pass an implicit ' this ' into the f unction it can make thinking OO in C easier. For example: String s = "hi"; System.out.println(s.length()); becomes:

string s = "hi"; printf(length(s)); // pass in s, as an implicit this Or something like that. answered Jan 6 '09 at 5:04 jjnguy

34.9k

71

148

...stating the obv ious... Artelius Jan 6 '09 at 5:16

@Artelius: Sure, but sometimes the obv ious is not, until it's stated. +1 f or this. Sof tware Monkey Jan 6 '09 at 5:22

f eedback

f or me object orientation in C should hav e these f eatures : 1) encapsulation and data hiding ( can be achiev ed using structs/opaque pointers) 2) inheritance and support f or poly morphism ( single inheritance can be achiev ed using structs - make sure abstract base is not instantiable) 3) constructor and destructor f unctionality ( not easy to achiev e) 4) ty pe checking (at least f or user def ined ty pes as C doesn't enf orce any ) 5) ref erence counting ( or some thing to implement RAAI) 6) limited support f or exception handling (setjmp and longjmp ) on top of abov e it should rely on ANSI/ISO specif ications and should not rely on compiler specif ic f unctionality . answered Jan 6 '09 at 5:47 FL4SOF

322

16

For number (5) - Y ou can't implement RAII in a language without destructors (which means RAII is not a compiler-supported technique in C or Jav a). Tom Jan 6 '09 at 6:05 constructors and destructors can be written f or c based object - i guess GObject does it. and of course RAAI ( it is not straight f orward, may be ugly and need not be pragmatic at all) - all i was looking is to identif y C based semantics to acheiv e the abov e. FL4SOF Jan 6 '09 at 6:44 C doesn't support destructors. Y ou hav e to ty pe something in order to make them work. That means they don't clean up themselv es. GObject doesn't change the language. Tom Jan 7 '09 at 5:25

f eedback

If I were going to write OOP in C I would probably go with a pseudo-PIMPL design. Instead of passing pointers to structs, y ou end up passing pointers to pointers to structs. This makes the content opaque and f acilitates poly morphism and inheritance. The real problem with OOP in C is what happens when v ariables exit scope. There's no compiler generated destructors and that can cause issues. MACROS can possibly help but it is alway s going to be ugly to look at. answered Jan 6 '09 at 8:15 jmucchiello

6,934

11

28

f eedback

question f eed

You might also like