Object Oriented C

People that have always programmed in an object oriented language sometimes don't have a clear idea on the underlying mechanisms of inheritance and polymorphism. It also happend that people that have always programmed in a procedural language tend to think that they need an object oriented language to program in an object oriented way.

The large majority of experienced C programmers know how to program in C in an object oriented way, like it is possible to see in many open source projects. The problem is that it is not always easy to extrapolate a concept from a big and mature software project.

This is why I have written a little example program to explain how to program in C in an object oriented way. It has been a good exercise for me and I hope it will be also useful to other people.

main.c

#include <stdio.h>
#include "shape.h"
#include "square.h"
#include "circle.h"
 
#define NUM_SHAPES   2
 
int main(int argc, char **argv) {
   int i;
   Shape shape[NUM_SHAPES];
 
   shape[0] = (Shape) new_Circle(4, 4, 2);
   shape[1] = (Shape) new_Square(9, 4, 2);
 
   for (i = 0; i < NUM_SHAPES; i++) {
       shape[i]->draw(shape[i]);
   }
 
   for (i = 0; i < NUM_SHAPES; i++) {
       shape[i]->destroy(shape[i]);
   }
 
   return 0;       
}

UML Diagram
UML Diagram

Standard Output

CIRCLE_C: Creating a new Circle
SQUARE_C: Creating a new Square
CIRCLE_C: Drawing a Circle of radius 2 in (4,4)
SQUARE_C: Drawing a Square of length 2 in (9,4)
SHAPE_C: Destroing a shape
SHAPE_C: Destroing a shape

shape.h

#ifndef _SHAPE_H_
#define _SHAPE_H_
 
  #define SHAPE int x_center;             \
                int y_center;             \
                void (*draw)(Shape this); \
                void (*destroy)(Shape this)
 
  typedef struct Shape_struct* Shape;
  struct Shape_struct {
     SHAPE;
  } Shape_struct;
 
  void destroy(Shape this);
 
#endif

shape.c

#include <stdio.h>
#include <stdlib.h>
 
#include "shape.h"
 
void destroy(Shape this) {
   printf("SHAPE_C: Destroing a shape\n");
   if (this != NULL) free(this);
}

square.h

#ifndef _SQUARE_H_
#define _SQUARE_H_
 
  #include "shape.h"
 
  typedef struct Square_struct* Square;
  struct Square_struct {
     SHAPE;
     int length;
  } Square_struct;
 
  Square new_Square(int x_center, int y_center, int length);
 
#endif

square.c

#include <stdio.h>
#include <stdlib.h>
 
#include "square.h"
 
static void draw(Shape this) {
   Square thisSquare = (Square) this;
   printf("SQUARE_C: Drawing a Square of length %d in (%d,%d)\n",
      thisSquare->length,
      thisSquare->x_center,
      thisSquare->y_center);
}
 
Square new_Square (int x_center, int y_center, int length) {
   Square square;
 
   printf("SQUARE_C: Creating a new Square\n");
   square = (Square) malloc(sizeof(Square_struct));
 
   square->x_center = x_center;
   square->y_center = y_center;
   square->length = length;
 
   square->draw = draw;
   square->destroy = destroy;
 
   return square;
}

circle.h

#ifndef _CIRCLE_H_
#define _CIRCLE_H_
 
  #include "shape.h"
 
  typedef struct Circle_struct* Circle;
  struct Circle_struct {
    SHAPE;
    int radius;
  } Circle_struct;
 
  Circle new_Circle(int x_center, int y_center, int radius);
 
#endif

circle.c

#include <stdio.h>
#include <stdlib.h>
 
#include "circle.h"
 
static void draw(Shape this) {
   Circle thisCircle = (Circle) this;
   printf("Circle_C: Drawing a Circle of radius %d in (%d,%d)\n",
      thisCircle->radius,
      thisCircle->x_center,
      thisCircle->y_center);
}
 
Circle new_Circle (int x_center, int y_center, int radius) {
   Circle circle;
 
   printf("CIRCLE_C: Creating a new Circle\n");
   circle = (Circle) malloc(sizeof(Circle_struct));
 
   circle->x_center = x_center;
   circle->y_center = y_center;
   circle->radius = radius;
 
   circle->draw = draw;
   circle->destroy = destroy;
 
   return circle;
}

Memory Management

It is important to master how each part of the code will use the memory resources of your system.

The behavior of each object, the methods implementation, will be loaded on the static memory.

The instances of each object, the structure memory area (variables and pointer to functions), will be allocated in three possible memory area, depending on how they are declared in the code:

  • heap: when the instance is allocated dynamically with malloc (this is the default behavior of the new keyword in object oriented languages).
  • stack: When the instance, for example, is declared inside a function call
  • static: When the instance is declared as static.

The following graph gives an idea of this distinctions:

,
c/object_oriented_c.txt · Last modified: 2010/08/12 by emilmont
CC Attribution-Noncommercial-Share Alike 3.0 Unported
Valid CSS Driven by DokuWiki Recent changes RSS feed Valid XHTML 1.0