Object oriented programming in C

COop

C Problem Overview


> Possible Duplicates:
> Can you write object oriented code in C?
> Object Oriented pattern in C ?

I remember reading a while ago about someone (I think it was Linus Torvalds) talking about how C++ is a horrible language and how you can write object-oriented programs with C. On having had time to reflect, I don't really see how all object oriented concepts carry over into C. Some things are fairly obvious. For example:

  1. To emulate member functions, you can put function pointers in structs.
  2. To emulate polymorphism, you can write a function that takes a variable number of arguments and do some voodoo depending on, say, the sizeof the parameter(s)

How would you emulate encapsulation and inheritance though?

I suppose encapsulation could sort of be emulated by having a nested struct that stored private members. It would be fairly easy to get around, but could perhaps be named PRIVATE or something equally obvious to signal that it isn't meant to be used from outside the struct. What about inheritance though?

C Solutions


Solution 1 - C

You can implement polymorphism with regular functions and virtual tables (vtables). Here's a pretty neat system that I invented (based on C++) for a programming exercise: alt text

The constructors allocate memory and then call the class's init function where the memory is initialized. Each init function should also contain a static vtable struct that contains the virtual function pointers (NULL for pure virtual). Derived class init functions call the superclass init function before doing anything else.

A very nice API can be created by implementing the virtual function wrappers (not to be confused with the functions pointed to by the vtables) as follows (add static inline in front of it, if you do this in the header):

int playerGuess(Player* this) { return this->vtable->guess(this); }

Single inheritance can be done by abusing the binary layout of a struct: alt text

Notice that multiple inheritance is messier as then you often need to adjust the pointer value when casting between types of the hierarchy.

Other type-specific data can be added to the virtual tables as well. Examples include runtime type info (e.g. type name as a string), linking to superclass vtable and the destructor chain. You probably want virtual destructors where derived class destructor demotes the object to its super class and then recursively calls the destructor of that and so on, until the base class destructor is reached and that finally frees the struct.

Encapsulation was done by defining the structs in player_protected.h and implementing the functions (pointed to by the vtable) in player_protected.c, and similarly for derived classes, but this is quite clumsy and it degrades performance (as virtual wrappers cannot be put to headers), so I would recommend against it.

Solution 2 - C

Have you read the "bible" on the subject? See Object Oriented C...

Solution 3 - C

> How would you emulate encapsulation and inheritance though?

Actually, encapsulation is the easiest part. Encapsulation is a design philosophy, it has nothing at all to do with the language and everything to to with how you think about problems.

For example, the Windows FILE api is completely encapsulated. When you open a file, you get back an opaque object that contains all of the state information for the file 'object'. You hand this handle back to each of the file io apis. The encapsulation is actually much better than C++ because there is no public header file that people can look at and see the names of your private variables.

Inheritance is harder, but it isn't at all necessary in order for your code to be object oriented. In some ways aggregation is better than inheritance anyway, and aggregation is just as easy in C as in C++. see http://www.gamearchitect.net/Articles/GameObjects1.html">this</a> for instance.

In response to Neil see http://en.wikipedia.org/wiki/Polymorphism_in_object-oriented_programming">Wikipedia</a> for an explanation of why inheritance isn't necessary for polymorphism.

Us old-timers wrote object oriented code years before C++ compilers were available, it's a mind-set not a tool-set.

Solution 4 - C

Apple's C-based CoreFoundation framework was actually written so that its "objects" could double as objects in Objective-C, an actual OO language. A fairly large subset of the framework is open source on Apple's site as CF-Lite. Might be a useful case study in a major OS-level framework done this way.

Solution 5 - C

From a little bit higher altitude and considering the problem rather more open-minded than as the OOP mainstream may suggest, Object-Oriented Programming means thinking about objects as of data with associated functions. It does not necessarily mean an function has to be physically attached to an object as it is in popular languages which support paradigm of OOP, for instance in C++:

struct T
{
   int data;
   int get_data() const { return data; }
};

I would suggest to take a closer look at GTK+ Object and Type System. It is a brilliant example of OOP realised in C programming language:

> GTK+ implements its own custom object > system, which offers standard > object-oriented features such as > inheritance and virtual function

The association can also be contractual and conventional.

Regarding encapsulation and data hiding techniques, popular and simple one may be Opaque Pointer (or Opaque Data Type) - you can pass it around but in order to load or store any information, you have to call associated function which knows how to talk to the object hidden behind that opaque pointer.

Another one, similar but different is Shadow Data type - check this link where Jon Jagger gives excellent explanation of this not-so-well-known-technique.

Solution 6 - C

the gtk and glib libraries use macros to cast objects to various types.
add_widget(GTK_WIDGET(myButton));
I can't say how it's done but you can read their source to find out exactly how it's done.

Solution 7 - C

Take a look at the way the VFS layer works in the Linux kernel for an example of an inheritance pattern. The file operations for the various filesystems "inherit" a set of generic file operations functions (eg generic_file_aio_read(), generic_file_llseek()...), but can override them with their own implementations (eg. ntfs_file_aio_write()).

Solution 8 - C

Definitely look at Objective-C.

typedef struct objc_object {
    Class isa;
} *id;

typedef struct objc_class {
    struct objc_class *isa;
    struct objc_class *super_class
    const char *name;
    long version;
    long info
    long instance_size;
    struct objc_ivar_list *ivars;
    struct objc_method_list **methodLists;
   struct objc_cache *cache;
   struct objc_protocol_list *protocols;
} *Class;

As you can see, inheritance information, along with other details is held in a class struct (conveniently the class can also be treated as an object).

Objective-C suffers in the same manner as C++ with encapsulation in that you need to declare your variables publicly. Straight C is much more flexible in that you can just return void pointers that only your module has internal access to, so in that respect encapsulation is much better.

I once wrote a basic OO style C paint program as part of a graphics course - I didn't go as far as the class declaration, I simply used a vtable pointer as the first element of the struct and implemented hand-coded inheritance. The neat thing about playing around with vtables at such a low level is that you can change class behaviour at runtime by changing a few pointers, or change on objects class dynamically. It was quite easy to create all sorts of hybrid objects, fake multiple inheritance, etc.

Solution 9 - C

Nice article & discussion regarding Objective-C here:

http://cocoawithlove.com/2009/10/objective-c-niche-why-it-survives-in.html

Solution 10 - C

For a great example of object-oriented programming in C, look at the source of POV-Ray from several years ago - version 3.1g is particularly good. "Objects" were struct with function pointers, of course. Macros were used to provide the core methods and data for an abstract object, and derived classes were structs that began with that macro. There was no attempt to deal with private/public, however. Things to be seen were in .h files and implementation details were in .c files, mostly, except for a lot of exceptions.

There were some neat tricks that I don't see how could be carried over to C++ - such as converting one class to a different but similar one on the fly just by reassigning function pointers. Simple for today's dynamic languages. I forgot the details; I think it might have been CSG intersection and union objects.

http://www.povray.org/

Solution 11 - C

An interesting bit of history. Cfront, the original C++ implementation output C code and then requires a C compiler to actually build the final code. So, anything that could be expressed in C++ could be written as C.

Solution 12 - C

One way to handle inheritance is by having nested structs:

struct base
{
    ...
};

void method_of_base(base *b, ...);

struct child
{
    struct base base_elements;
    ...
};

You can then do calls like this:

struct child c;
method_of_base(&c.b, ...);

Solution 13 - C

You might want to look at Objective-C, that's pretty much what it does. It's just a front-end that compiles Objective-C OO code to C.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionChinmay KanchiView Question on Stackoverflow
Solution 1 - CTronicView Answer on Stackoverflow
Solution 2 - CKornel KisielewiczView Answer on Stackoverflow
Solution 3 - CJohn KnoellerView Answer on Stackoverflow
Solution 4 - CChuckView Answer on Stackoverflow
Solution 5 - CmloskotView Answer on Stackoverflow
Solution 6 - CChris HView Answer on Stackoverflow
Solution 7 - CcafView Answer on Stackoverflow
Solution 8 - CDuncanView Answer on Stackoverflow
Solution 9 - ChiggoView Answer on Stackoverflow
Solution 10 - CDarenWView Answer on Stackoverflow
Solution 11 - CR Samuel KlatchkoView Answer on Stackoverflow
Solution 12 - CR Samuel KlatchkoView Answer on Stackoverflow
Solution 13 - CBill KView Answer on Stackoverflow