Object Oriented C – Polymorphism

If you haven’t yet read ‘Object Oriented C – Objects‘ Stop! Go Back! Go and read that earlier post before continuing. In this post I build on the earlier concepts, so much of this won’t make sense without it.

In my last tutorial, I demonstrated that it is possible to write Object Oriented code in C. I wrote some classes, and instantiated objects on those classes. I even made a start on sorting out C’s hopeless string handling (before giving up because others have already solved the problem). This time I’m going to extend the tutorial to cover Polymorphism.

Recapping the last tutorial, Polymorphism is an partner concept to Inheritance. It allows 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).

To demonstrate Polymorphism in C, I’ve written a shapes class – with two subclasses, Ellipse and Square which implement common functions to calculate the area of the shape. Clearly the formula is different in each case so I couldn’t use the same function – but I still wanted to call them in the same way. To do this, I needed to write Polymorphic code.

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
 
#define SQUARE_TYPE 0
#define CIRCLE_TYPE 1
 
/* Super Class */
typedef struct shape shapeClass;
 
typedef struct shape {
 int type;
 void* thisShape;
 float width, height;
 float (*getArea) (void*);
} shape;
 
/* Ellipse Class */
typedef struct shape_ellipse ellipseClass;
 
typedef struct shape_ellipse {
 float (*getArea) (shapeClass*);
} shape_ellipse;
 
float shapeClassGetEllipseArea(shapeClass* self) {
 return (self->width/2) * (self->height/2) * M_PI;
}
 
ellipseClass* ellipseClassCreate() {
 ellipseClass* self = malloc((sizeof(ellipseClass)));
 self->getArea = shapeClassGetEllipseArea;
 return self; 
}
 
/* Square Class */
typedef struct shape_square squareClass;
 
typedef struct shape_square {
 float (*getArea) (shapeClass*);
} shape_square;
 
float shapeClassGetSquareArea(shapeClass* self) {
 return self->width * self->height;
}
 
squareClass* squareClassCreate() {
 squareClass* self = malloc((sizeof(squareClass)));
 self->getArea = shapeClassGetSquareArea;
 return self; 
}
 
/* Super Class */
void* shapeClassCreate(int shapeType, float width, float height) { //Constructor
 shapeClass* self = malloc((sizeof(shapeClass)));
 if (shapeType == SQUARE_TYPE) {
 self->thisShape = squareClassCreate();
 self->getArea = (void*)((squareClass*)self->thisShape)->getArea;
 } else if (shapeType == CIRCLE_TYPE) {
 self->thisShape = ellipseClassCreate();
 self->getArea = (void*)((ellipseClass*)self->thisShape)->getArea;
 } else {
 return NULL;
 }
 self->type = shapeType;
 self->width = width;
 self->height = height;
 return self; 
}
 
void destroyShape(void* shape) { // Destructor
 free(((shapeClass*)shape)->thisShape);
 free(shape);
}
 
/* Main */
int main(int argc, char *argv[]) {
 float clives_number = 27.0;
 shapeClass* ellipse = shapeClassCreate(CIRCLE_TYPE,clives_number,clives_number);
 shapeClass* square = shapeClassCreate(SQUARE_TYPE,clives_number,clives_number);
 float ellipseArea = ellipse->getArea(ellipse);
 float squareArea = square->getArea(square);
 printf("%f\n",ellipseArea);
 printf("%f\n",squareArea);
 destroyShape(ellipse);
 destroyShape(square);
}

Rather than cover all the same ground from the last post, I’ll just cover the additions. In the last post, I didn’t write a destructor for my class – there wasn’t any point, ‘free’ covered it nicely. This time though the memory used by the subclasses will also need to be released – so I have written a destructor function.

The constructor for the shape superclass has been extended too. This time, as well as allocating memory for itself, it needs to call the constructors for the subclasses. Note the use of void pointers – this is because the ellipse class and square classes are different, and yet I still need to be able to assign it to thisShape in the superclass. Void pointers are flexible pointers.

Finally, I initialise the data for the superclass. The subclasses could have their own data too, of course, but there is no need in this instance.

Once the objects for the square and ellipse have been instantiated I can use them in exactly the same manner. The same functions are available (getArea). I don’t need to know, or care, that different functions are being called to return the result depending on whether the object is an ellipse or a square.

So there you have it. Polymorphic, object oriented, code in C (with thanks to Clive Capisano for the use of his ‘special’ number).

Thinking about this, you could use many of the concepts here and call it Inheritance – in an ersatz kind of way.  So perhaps it is only really necessary to explore Encapsulation next?

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 *