Object-oriented
Programming in C


History: Object-oriented programming (OOP) was introduced in a mature way in the 1960s with the language Simula67, an extension of Algol60, which in turn is the precursor for C, C++, Java, and many other languages. Stroustup incorporated Simula67 features into his C++. A simplified version of these features was then included in Java.

The old language Pascal was said to be actively hostile to OOP, although there were OOP extensions of Pascal: Classcal early on, and later Borland's Delphei. But it is not possible to do OOP in standard Pascal. On the other hand, the C language enables OOP -- one can do a good job of simulating OOP within standard C, and this is one reason (of several) for the success of C. Of course, C++ and Java do a good job of implementing OOP, within the constraint of efficiency at run-time.

The language Smalltalk is the prototypical OOP language, where absolutely everything is an object, and instead of methods, objects communicate with one another at run-time by sending messages to one another. The language Objective-C incorporated these Smalltalk features into an extension of C. Thus both Smalltalk and Objective-C do more at run-time and are inherently less efficient than C or C++.


How C enables OOP: The Java and C++ class is an extension of the C struct, which we will study later in the course. Since you are familiar with Java, let me say here that a C struct is sort-of a very low-tech class, with only data members and none of the other features of a class: no member functions, no constructors, no public/private distinctions. It is just a way to group heterogeneous data together in one object, just as an array is a way to group homogeneous data together. Because the C++/Java class extends the idea of the C struct, it is natural to think that we would use C structs to try to fake OOP in C, but that is not true.

Instead, C uses a separate file to give many of the features of OOP to the language. This is part of the reason I am starting before introducing C structs.

In fairness, I should also say that there is another way to simulate OOP in C: use a struct to hold all the different data members of an object. This is the approach taken in some parts of the Weiss textbook. This is an awkward method, where the data members are partly inaccessible just because it is so hard to get to them. I don't support this messy method, although it does allow multiple copies of an object to be created.


Separate Files for OOP in C: Here is how it works:

Item or Activity "Faked" OOP in C OOP in C++/Java
The object itselfA separate fileA class
Private date members Ordinary data declarations Data declared private
Public date members Data declared extern Data declared public
Private member function Function declared static Function declared private
Public member function Ordinary function definition Function declared public
Creating objects Only one instance possible
(separate file for each instance)
Any number of instances
Initialization Initializing code
(may need separate call)
Constructor
Connections
between objects
Header files C++: Header files
Java: None needed


Example: a stack: As an example, consider a simple array-based stack, in this case without even any checks for overflow/underflow. Here is the stack in C/C++/Java: stack.

Each of the implementations uses separate files for the class ("class" in C). The C++ implementation is very similar to the Java one, except that C++ needs a header file and a destructor. Let's focus, however on the C implementation:


Discussion: Separate files allow C to implement many of the features of an abstract data type, which refers to the implementation of an object with hidden data and a few public functions to make use of the object. The header file becomes the interface to this object. One could change the implementation completely, leaving the prototypes in the header the same, and have programs using this object not notice any change.

Other kinds of C++ and Java classes can't use separate files for their implementation in C: as examples consider situations where multiple instantiations are necessary, such as the node of a binary tree.


Using only a single file: I have rewritten the stack program in the three languages so that in each case it fits inside a single file. I've also simplified various parts of the code. Here is the result: stack.

As explained on the above listing, the C++ and Java programs in one file have most of the properties and functionality that they had in a separate file -- just that the Stack class can't be used from the outside, but there can be multiple instances of multiple sizes. The C program, however, has suffered a great deal from being implemented in a single file. Now there is no emcapsulation of the stack implementation. The data members are not hidden and are directly accessible from anywhere in the file. It would be possible for code to change stack variables and put the stack into an inconsistent state, something which is very bad.


Better stacks: Both C++ and Java allow generic versions of this stack: C++ using templates and Java using interfaces. There are also generic versions of stacks from the respective libraries. Here is a generic stack written "from scratch" in C++: Generic stack in C++. Normally you should use a library C++ container class from the Standard Template Library (STL) in C++.


Copyright © 2011, Neal R. Wagner. Permission is granted to access, download, share, and distribute, as long as this notice remains.