This is a chapter in a thesis about software components, which use objects at their core. This chapter covers all the basics of implementing object-oriented programming in C, including naming, error handling and where to put the instance data of objects, and concludes with an overview of dynamic dispatch (which is a core element of an object-oriented system). Throughout this chapter, source code is used to demonstrate all key concepts. Indeed, you are encouraged to download the samples presented here, build them on your own system and toy with them (they are released under a very liberal license, so you are free to adapt them to your own needs). I hope you find this material useful, and please let me know if you have any comments. -- David Polberger
3 Demystifying dynamic dispatch
Dynamic dispatch is at the heart of object-based component technology. Without it, freestanding interfaces would not be possible. Dynamic dispatch, also known as late binding, makes it possible to program to a specification and bind to an implementation at runtime.1
Chapter 2 introduces some of the technology used to make component technology a reality. It glosses over the technical minutiae of dynamic dispatch, though, which this chapter aims to rectify. During the course of this chapter, two example programs, written in the C programming language, are developed that establish a set of conventions used when implementing object-oriented programs in C. These conventions essentially form a complete object model, supporting encapsulation and polymorphism, but not implementation inheritance or multiple interface inheritance. Chapter 4 builds on this material to sketch a component model.
The first example program, which does not use dynamic dispatch, is intended to set the stage for the second example program by introducing some fundamental concepts. The second example program builds on this foundation by introducing dynamic dispatch. C is a good choice for this task, as it has all the features needed to implement dynamic dispatch on top of an existing procedural language. The first example also appears as functionally equivalent Java code. Java already has the language constructs which are implemented for C in this chapter—classes, objects and interfaces.
There have been many attempts to bring object-oriented programming to C. In an article from 1997, Samek presents a battery of C macros and best practices making it possible to implement object-oriented constructs, including implementation inheritance. Bjarne Stroustrup’s first C++ compiler, Cfront, produced C code to be compiled by a traditional C compiler (Stroustrup 1994:66).
Another example is the GNOME desktop environment—primarily used with Unix-like operating systems—which uses the GObject object model pervasively. GObject is written in C, and may be used directly in native applications or through bindings to other languages. Vala is a fully object-oriented language that targets native code and uses GObject as its object model. Like Cfront, its compiler produces C code.
Some of the examples in this chapter are heavily abridged due to space constraints. The reader is encouraged to download and experiment with the source code. The C source code should be compatible with all compilers adhering to the C99 standard.2
- The form of dynamic dispatch discussed in this thesis is single dispatch, as opposed to multiple dispatch. Single dispatch resolves what implementation to use by only taking into account the type of the first argument (which by convention is the instance data of objects in object-oriented systems). Multiple dispatch takes the types of all arguments into account.
- The Java source code has been tested with Sun Microsystems’s Java Development Kit (JDK) for the Standard Edition, version 6. The C source code has been tested with the C front-end of the GNU Compiler Collection (GCC), version 4.3.3. The example programs have been developed on an x86-64 Linux system, and Valgrind 3.4.1 has been used to check the C programs for memory leaks.