C is meant to be for structured programming, but is object
oriented programming possible with C ? Let us make an
attempt at it. Here would be our approach: We will take a
characteristic of OOP, implement it in C++ and then try
to implement it in C.
First basic characteristic of OOP is of course Objects
and their Methods.
Below is an example of C++ program which implement object
called sphere.
File: sphere.hpp
class sphere { public: sphere(int rad); int get_radius(); private: int radius; }; File: sphere.cpp #include "sphere.hpp" sphere::sphere(int rad) { radius = rad; } int sphere::get_radius() { return radius; } File: spheremain.cpp (to test) #include <stdio.h> #include "sphere.hpp" int main(void) { sphere *sphere1 = new sphere(30); printf( "Sphere 1 of radius %d\n", sphere1->get_radius() ); return 1; } |
The same can be implemented in C as below:
- C do not have built-in "constructor", so we have separate function sphere_constructor that will do the same.
- C do not support methods, so we use function binding.
- C do not have this pointer, we pass the pointer as first argument in methods.
File: sphere.h
typedef struct sphere_struct sphere; struct sphere_struct { int (*get_radius)(sphere*); int radius; }; void sphere_constructor(sphere* sptr, int rad); File: sphere.c #include "sphere.h" static int intern_get_radius(sphere *sptr); void sphere_constructor(sphere *sptr, int rad) { sptr->get_radius = intern_get_radius; sptr->radius = rad; } int intern_get_radius(sphere *sptr) { return sptr->radius; } File: spheremain.c #include <stdio.h> #include "sphere.h" int main(void) { sphere *sphere1 = (sphere*)malloc( sizeof( sphere ) ); sphere_constructor(sphere1, 30); printf( "Sphere 1 of radius %d\n", sphere1->get_radius(sphere1) ); return 1; } |
Next OOP characteristic is Inheritance.
Below is an extension of above example in which we extend sphere to csphere (colored sphere).
File: csphere.hpp
#include "sphere.hpp" #define CSPHERE_COL_LEN 4 class csphere : public sphere { public: csphere(int rad, const char *color); char *get_color(); private: char color[CSPHERE_COL_LEN]; }; File: csphere.cpp #include "csphere.hpp" #include <string.h> csphere::csphere(int rad, const char *col) :sphere( rad ) { strncpy(color, col, CSPHERE_COL_LEN-1); color[CSPHERE_COL_LEN-1] = '\0'; } char *csphere::get_color() { return color; } File: spheremain.cpp #include <stdio.h> #include "csphere.hpp" int main(void) { sphere *sphere1 = new sphere(30); csphere *csphere1 = new csphere(20, "red"); printf( "Sphere 1 of radius %d\n", sphere1->get_radius() ); printf( "Colored sphere 1 of radius %d and color %s\n", csphere1->get_radius(), csphere1->get_color() ); return 1; } |
The same using C:
- C do not support inheritance, so in our csphere structure, we have sphere field.
- csphere structure will have duplicate methods from sphere.
File: csphere.h
#include "sphere.h" #define CSPHERE_COL_LEN 4 typedef struct csphere_struct csphere; struct csphere_struct { sphere *parent_sphere; int (*get_radius)(csphere*); char *(*get_color)(csphere*); char color[CSPHERE_COL_LEN]; }; void csphere_constructor(csphere* csptr, int rad, const char *col); File: csphere.c #include "csphere.h" #include <string.h> static int intern_get_radius(csphere *csptr); static char *intern_get_color(csphere *csptr); void csphere_constructor(csphere *csptr, int rad, const char *col) { csptr->parent_sphere = (sphere*)malloc( sizeof( sphere ) ); sphere_constructor(csptr->parent_sphere, rad); strncpy( csptr->color, col, CSPHERE_COL_LEN-1 ); csptr->color[CSPHERE_COL_LEN-1] = '\0'; csptr->get_color = intern_get_color; csptr->get_radius = intern_get_radius; } char *intern_get_color(csphere* csptr) { return csptr->color; } int intern_get_radius(csphere *csptr) { return csptr->parent_sphere->radius; } File: spheremain.c #include <stdio.h> #include "csphere.h" int main(void) { sphere *sphere1 = (sphere*)malloc( sizeof( sphere ) ); csphere *csphere1 = (csphere*)malloc( sizeof( csphere ) ); sphere_constructor(sphere1, 30); csphere_constructor(csphere1, 20, "red"); printf( "Sphere 1 of radius %d\n", sphere1->get_radius(sphere1) ); printf( "Colored sphere 1 of radius %d and color %s\n", csphere1->get_radius(csphere1), csphere1->get_color(csphere1) ); return 1; } |
Next, we will have look at Polymorphism.
Below C++ example, adds sphere comparison which is overloaded by csphere.
File: sphere.hpp
class sphere { public: sphere(int rad); int get_radius(); bool operator==(const sphere &s1) { return (radius == s1.radius); } private: int radius; }; File: csphere.hpp #include "sphere.hpp" #include <string.h> #define CSPHERE_COL_LEN 4 class csphere : public sphere { public: csphere(int rad, const char *color); char *get_color(); bool operator==(const csphere &cs1) { return ( ( (*(sphere*)this) == (*(sphere*)&cs1) ) && !(strcmp(color, cs1.color)) ); } private: char color[CSPHERE_COL_LEN]; }; File: spheremain.cpp #include <stdio.h> #include "csphere.hpp" int main(void) { sphere *sphere1 = new sphere(30); csphere *csphere1 = new csphere(20, "red"); sphere *sphere2 = new sphere(30); csphere *csphere2 = new csphere(20, "red"); printf( "Sphere 1 of radius %d\n", sphere1->get_radius() ); printf( "Colored sphere 1 of radius %d and color %s\n", csphere1->get_radius(), csphere1->get_color() ); printf( "Sphere 2 of radius %d\n", sphere2->get_radius() ); printf( "Colored sphere 2 of radius %d and color %s\n", csphere2->get_radius(), csphere2->get_color() ); if( *sphere1 == *sphere2 ) { printf( "Sphere1 is equal to Sphere2\n" ); } else { printf( "Sphere1 is *not* equal to Sphere2\n" ); } if( *csphere1 == *csphere2 ) { printf( "Colored sphere 1 is equal to colored sphere 2\n" ); } else { printf( "Colored sphere 1 is *not* equal to colored sphere 2\n" ); } return 1; } |
The same now using C:
- Equal-to operator behaviour can not be changed in C, so we use function instead. Though it is not as good readable as C++ (spheremain.cpp) implementation, it serves the purpose.
File: sphere.h
typedef struct sphere_struct sphere; struct sphere_struct { int (*get_radius)(sphere*); int (*equal_to)(sphere*, sphere*); int radius; }; void sphere_constructor(sphere* sptr, int rad); File: sphere.c #include "sphere.h" static int intern_get_radius(sphere *sptr); static int intern_equal_to(sphere *s1, sphere *s2); void sphere_constructor(sphere *sptr, int rad) { sptr->get_radius = intern_get_radius; sptr->equal_to = intern_equal_to; sptr->radius = rad; } int intern_get_radius(sphere *sptr) { return sptr->radius; } int intern_equal_to(sphere *s1, sphere *s2) { return (s1->radius == s2->radius); } File: csphere.h #include "sphere.h" #define CSPHERE_COL_LEN 4 typedef struct csphere_struct csphere; struct csphere_struct { sphere *parent_sphere; int (*get_radius)(csphere*); const char *(*get_color)(csphere*); int (*equal_to)(csphere*, csphere*); char color[CSPHERE_COL_LEN]; }; void csphere_constructor(csphere* csptr, int rad, const char *col); File: csphere.c #include "csphere.h" #include <string.h> static int intern_get_radius(csphere *csptr); static const char *intern_get_color(csphere *csptr); static int intern_equal_to(csphere *cs1, csphere *cs2); void csphere_constructor(csphere *csptr, int rad, const char *col) { csptr->parent_sphere = (sphere*)malloc( sizeof( sphere ) ); sphere_constructor(csptr->parent_sphere, rad); strncpy( csptr->color, col, CSPHERE_COL_LEN-1 ); csptr->color[CSPHERE_COL_LEN-1] = '\0'; csptr->get_color = intern_get_color; csptr->get_radius = intern_get_radius; csptr->equal_to = intern_equal_to; } const char *intern_get_color(csphere* csptr) { return csptr->color; } int intern_get_radius(csphere *csptr) { return csptr->parent_sphere->radius; } int intern_equal_to(csphere *cs1, csphere *cs2) { return( (cs1->parent_sphere->equal_to(cs1->parent_sphere, cs2->parent_sphere) ) && !(strcmp(cs1->color, cs2->color)) ); } File: spheremain.c #include <stdio.h> #include "csphere.h" int main(void) { sphere *sphere1 = (sphere*)malloc( sizeof( sphere ) ); csphere *csphere1 = (csphere*)malloc( sizeof( csphere ) ); sphere *sphere2 = (sphere*)malloc( sizeof( sphere ) ); csphere *csphere2 = (csphere*)malloc( sizeof( csphere ) ); sphere_constructor(sphere1, 30); csphere_constructor(csphere1, 20, "red"); sphere_constructor(sphere2, 30); csphere_constructor(csphere2, 20, "red"); printf( "Sphere 1 of radius %d\n", sphere1->get_radius(sphere1) ); printf( "Colored sphere 1 of radius %d and color %s\n", csphere1->get_radius(csphere1), csphere1->get_color(csphere1) ); printf( "Sphere 2 of radius %d\n", sphere1->get_radius(sphere2) ); printf( "Colored sphere 2 of radius %d and color %s\n", csphere2->get_radius(csphere2), csphere2->get_color(csphere2) ); if( sphere1->equal_to( sphere1, sphere2 ) ) { printf( "Sphere 1 is equal to sphere 2\n" ); } else { printf( "Sphere 1 is *not* equal to sphere 2\n" ); } if( csphere1->equal_to( csphere1, csphere2 ) ) { printf( "Colored sphere 1 is equal to colored sphere 2\n" ); } else { printf( "Colored sphere 1 is *not* equal to colored sphere 2\n" ); } return 1; } |
But there is a catch, our C implementation won't be able compare sphere with csphere ! In C++, if csphere and sphere comparison will automatically call comparison operation from parent object i.e sphere object. Following lines of code would go ahead and compare, but corresponding C code won't work.
File: spheremain.cpp if( *sphere1 == *csphere1 ) { printf( "Sphere 1 is equal to colored sphere 1\n" ); } else { printf( "Sphere 1 is *not* equal to colored sphere 1\n" ); } File: spheremain.c if( sphere1->equal_to( sphere1, csphere1 ) ) { printf( "Sphere 1 is equal to colored sphere 1\n" ); } else { printf( "Sphere 1 is *not* equal to colored sphere 1\n" ); } |
Here is alternative then: we will have additional separate function to compare sphere with csphere.
int all_spheres_equal_to( sphere *sptr, csphere *csptr ) { return (sptr->radius == csptr->parent_sphere->radius); } File: spheremain.c int main(void) { . . if( all_spheres_equal_to( sphere1, csphere1 ) ) { printf( "Sphere 1 is equal to colored sphere 1\n" ); } else { printf( "Sphere 1 is *not* equal to colored sphere 1\n" ); } . . } |
References: For OOP concepts - An introduction to OOP by Timothy Budd.
Copyright © Samir Amberkar 2010-11 | § |
C Programming Guide « | C guide Index | » Object Oriented Programming using C - 2 |