Object Oriented C – Objects

Bear with me a while. I am going to stand of the shoulders of my favourite giants (Kernighan and Ritchie, since you ask) and address an oft-made point of criticism which is levelled against my code.

The criticism? Namely that my C++ code looks suspiciously like C. There’s a good reason for this – I like C, and I’m not so keen on C++. C++ is (in my view, and with apologies to its many fans) a bad way of making C object oriented – as evidenced by the need, on occasion, to drop into plain old C in order to avoid name mangling. Objective C is object oriented C done right – but that’s a topic for another day. In the mean time, I want to address my critics by making C look like C++ – and writing an OOP program in C.

First of all though, and because there are a surprising number of people in IT who don’t know, what do we mean by OOP (Object Oriented Programming)?

OOP (as opposed to Procedural Programming, from which it inherits) is a style of programming which revolves around the following concepts:

Objects

An object is an instance of a class. Objects might be something that the user can experience (a button on the screen, a window, or an alien spaceship for example), or they might be something invisible (but no less important) such as the means to load data from a file or open a network connection.

Classes contain the code and data required for the object to run – each object is an instance of a class.

Inheritance

Inheritance is a means of ensuring that code from existing classes can be reused. In addition, it permits existing classes to be extended without tampering with the actual class source code.

For example, imagine two classes ‘Male’ and ‘Female’ which are used to instantiate (create) complete men and women. If it weren’t for inheritance there’d be an awful lot of code duplication – it would be necessary to have two sets of lung code, two sets of brain code, two sets of heart code.

It’d be a maintainability disaster! Thankfully, we can write our ‘Male’ and ‘Female’ classes so that they inherit from a third class ‘Human’. ‘Human’ contains all the common code, and the ‘Male’ and ‘Female’ classes only need to cover functions for the primary and secondary sexual characteristics. Much simpler.

Encapsulation

Encapsulation is a means of preventing access to internal object data, ensuring that the data can only be accessed and modified via methods. That’s not to say the internal object data can never be manipulated directly – but one has the option to decide how best the data should be accessed. In explicitly OOP languages this is often achieved through the use of the ‘private’, ‘public’ and ‘protected’ keywords.

Polymorphism

Polymorphism is an partner concept to Inheritance. It allows the subclasses to implement their own versions of a common function. In the case of our ‘Male’ and ‘Female’ classes, both will be able to speak – but the characteristics of speech will be different. ‘Human’ will also have a ‘speak’ function to fall back on. For the sake of argument, lets say that the ‘Human’ speech function is defined to be flat, the ‘Female’ speech function is defined to pitched high and the ‘Male’ function pitched deep. If we call the speech function on an object instantiated from the ‘Male’ class, it will sound deep (the speech function in the ‘Male’ class has overridden the speech function in the ‘Human’ superclass).

That said, I’m not going to discuss all the terms that will be used in this post. You’ll need to have some programming chops before going any further (so if you don’t know your pointer from your struct you might want to stop now, and invest in a copy of The C Programming Language by Brian Kernighan and Dennis Ritchie (The C Programming Language (2nd Edition))

So without more ado, I’ll deal with the object part of Object Oriented – by creating an object in C. C gets us most of the way with a struct. A class (the code and data for the object) is just a struct with added code – so how hard can this be?

#include <stdio.h>
#include <stdlib.h>
 
typedef struct cClass class;
 
struct cClass { // this struct is the container for our class
 int data; // it has data…
 void (*setValue) (class*,int); // …and a function. A pointer to a function
 // in this case.
};
 
void cClassSetValue(class* self, int value) {
 self->data = value;
}
 
class* cClassCreate() {
 class* self = malloc((sizeof(class))); // gonna need some memory.
 self->data = 0; // …and initialise the data
 self->setValue = cClassSetValue; // …and pointers to our class functions
 return self; // and now we can return our 'self'
}
 
int main(int argc, const char* argv[]) {
 class* foo = cClassCreate(); // instantiate one object
 class* bar = cClassCreate(); // instantiate a second object
 foo->setValue(foo,1); // give it a value
 bar->setValue(bar,2);
 printf("%d\n", foo->data); // output the value
 printf("%d\n", bar->data);
 free(foo); // and release its memory now we're done
 free(bar);
 return 0;
}

Okay, I concede. It’s not the most elegant code – but it’s not too bad, and we’ve clearly got a class here and instantiated two objects (foo and bar). Incidentally, I’m told that this is how C++ started – originally C++ was nothing more than a bunch of preprocessor directives that converted Stroustrup’s C++ bits and pieces into Kernighan and Ritchie’s canonical C.

All that I’ve done is create a plain old C struct with some data in it (an int in this case), and a function pointer (for the executable code). To some eyes, it might not be elegant – but it contains data and code – so it is, demonstrably, a class. Anything we create with it is therefore an object.

Extending this a little further, one of the criticisms that often gets levelled at C is that its string handling is pretty rudimentary – which is amusing because, in fact, C can’t handle strings at all (or, at least, not without a fairly extensive library of functions). Using these OO techniques, we can hugely improve C’s string handling abilities. This is a start – the main point being to demonstrate that we can grow (and shrink) the storage for our C class. Your challenge is to extend this class to add all the other functions which might be useful. A little error handling might be useful too – but this is about how to create objects in C, not how to handle errors!

When a string is embiggened, more memory is automatically allocated by this class. When a string is debigulated, the extra, unneeded, memory is automatically freed.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
typedef struct cStringClass stringClass;
 
struct cStringClass {
 char *s;
 size_t size;
 void (*setString) (stringClass*,char*); // one function…
 size_t (*stringSize) (stringClass*); // …and a second function
};
 
void cStringClassSetString(stringClass *self, char* str) {
 char *buf;
 self->size = strlen(str);
 
 buf = realloc(self->s, self->size + 1); // reallocate enough memory for
 // the new string
 if (buf) { // if successful, update self
 self->s = buf;
 strncpy (self->s, str, self->size + 1); // and copy str into our s
 }
}
 
size_t cStringClassStringSize(stringClass* self) {
 return self->size; // Not using this function. It's just
 // here to show that your C class
 // doesn't have to be monofunctional!
}
 
stringClass* cStringClassCreate() {
 stringClass* self = malloc((sizeof(stringClass)));
 
 if (self != NULL) {
 self->stringSize = cStringClassStringSize;
 self->setString = cStringClassSetString;
 self->s = NULL;
 self->size = 0;
 }
 return self;
}
 
int main(int argc, const char* argv[]) {
 stringClass* foo = cStringClassCreate();
 stringClass* bar = cStringClassCreate();
 foo->setString(foo,"Hello");
 bar->setString(bar,"World");
 printf("%s\n", foo->s);
 printf("%s\n", bar->s);
 foo->setString(foo,"Watchamacallit"); // Allocate more memory on the heap
 bar->setString(bar,"!"); // free memory on the heap
 printf("%s\n", foo->s);
 printf("%s\n", bar->s);
 free(foo);
 free(bar);
 return 0;
}

In the loosest sense, this is Object Oriented programming. Sure, we’ve missed a few concepts – but the classes and objects are present, so I’m happy. And, of course, if we were doing this in anger then each class would be in its own file.

If you liked this then please comment and ‘Like’ this. With enough encouragement I’ll set myself the far bigger challenge of Inheritance, Polymorphism and Encapsulation.

This entry was posted in Code, Linux, Software, Technology. Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *