Inheritance/Single/C

From Rosetta Code

Manual Object System

Although C is not considered an OO language, you can do the following, which provides a semblance of an OO infrastructure allowing Inheritance and Polymorphism. The original C++ was a front end which translated C++ code to C. (C++ was much simpler in those days.)" <lang c>/* Animal.h */

  1. ifndef _ANIMAL_H
  2. define _ANIMAL_H
  1. include <stdio.h>
  2. include <stdlib.h>
  3. include <string.h>

typedef struct object *Animal;

extern char *ObjSpeak(Animal a); extern Animal ObjClone(Animal a); extern void ObjDestroy(Animal a);

  1. endif</lang>

<lang c>/* AnimalProt.h */

  1. include "Animal.h"

typedef struct sclass *Class; typedef void (*CloneFctn)(Animal s, Animal clo); typedef char * (*SpeakFctn)(Animal s); typedef void (*DestroyFctn)(Animal s); typedef void (*ClsRecInit)(Class c);

typedef struct object {

   Class class;

} SObject, *Object;

typedef struct sclass {

   size_t csize;		/* size of the class instance */
   char  *cname;		/* name of the class */
   Class  parent;		/* parent class */
   ClsRecInit crInit;          /* handle method inheritance for class record */
   CloneFctn clone;		/* clone function */
   SpeakFctn speak;		/* speak function */
   DestroyFctn del;		/* delete the object */

} sClass;

  1. define O_INHERIT (void *)-1

extern void ClassRecInit(Class c); extern void DfltClsInit(Class c); extern sClass boc;</lang> <lang c>/* Animal.c */

  1. include "AnimalProt.h"

static Animal obj_copy( Animal s, Class c ) {

   size_t size = s->class->csize;
   Animal clo;
   if (c->parent) 
       clo = obj_copy( s, c->parent);
   else {
       clo = (Animal )malloc( size );
       memcpy(clo, s, size);
   }
   if (clo)
       c->clone( s, clo );
   return clo;

}

static void obj_del( Animal s, Class c ) {

   if (c->del)
       c->del(s);
   if (c->parent)
       obj_del( s, c->parent);
   else
       free(s);

}

Animal ObjClone( Animal s ) { return obj_copy( s, s->class ); }

char * ObjSpeak( Animal s ) {

   return s->class->speak(s); 

}

void ObjDestroy( Animal s ) { if (s) obj_del( s, s->class ); }

void ClassRecInit( Class c) {

   if (c->crInit) {
       (*c->crInit)(c);
       c->crInit = NULL;
   }

} static void baseClsRecInit(Class c ) { if ((O_INHERIT == c->speak) && c->parent) c->speak = c->parent->speak; } void DfltClsInit(Class c) { if (c->parent && c->parent->crInit) { ClassRecInit(c->parent); } printf("Initializing class %s\n", c->cname); baseClsRecInit(c); } /* * * * * * */ static void baseClone( Animal s, Animal clone) {

   clone->class = s->class;

}

static char *baseSpeak(Animal s) {

   return "Hello, I'm an animal";

}

sClass boc = { sizeof(SObject), "Animal", NULL, &baseClsRecInit,

   &baseClone, &baseSpeak, NULL };

Class AnimalClass = &boc;</lang>

<lang c>/* DogProt.h */

  1. include "AnimalProt.h"

typedef struct sDogPart {

   double weight;
   char color[32];
   char name[24];

} DogPart;

typedef struct sDog *Dog;

struct sDog {

   Class   class;			// parent structure
   DogPart dog;

};

extern void InitDog(DogPart *dogp, char *name, char *color, double weight);

extern sClass dogc;</lang>

<lang c>/* Dog.c */ /** * * * * * * * * * * * * * * * * * *

* Dog - a class derived from Animal 
* * * * * * * * * * * * * * * * * * */
  1. include "DogProt.h"

static void dogClone( Animal s, Animal c) {

   Dog src = (Dog)s;
   Dog clone = (Dog)c;
   clone->dog = src->dog;	/* no pointers so strncpys not needed */

}

static char *dogSpeak( Animal s) {

   Dog d = (Dog)s;
   static char  response[90];
   sprintf(response, "woof! woof! My name is %s. I'm a %s %s", 
           d->dog.name, d->dog.color, d->class->cname);
   return response;

}

sClass dogc = { sizeof(struct sDog), "Dog", &boc, &DfltClsInit,

   &dogClone, &dogSpeak, NULL };

Class DogClass = &dogc;


void InitDog(DogPart *dogp, char *name, char *color, double weight) {

   dogp->weight = weight;
   strncpy(dogp->name, name, 23);
   strncpy(dogp->color, color, 31);

}

Animal NewDog( char *name, char *color, double weight ) {

   Dog dog = (Dog)malloc(DogClass->csize);
   if (dog) {
       ClassRecInit(DogClass);
       dog->class = DogClass;
       InitDog(&dog->dog, name, color, weight);
   }
   return (Animal)dog;

}</lang> <lang c>/* Dog.h */

  1. ifndef _DOG_H
  2. define _DOG_H
  3. include "Animal.h"

extern Animal NewDog(char *name, char *color, double weight);

  1. endif</lang>

<lang c>/* LabProt.h */

  1. include "DogProt.h"

/** * * * * * * * * * * * * * * * * * *

* Lab - a class derived from Dog 
* * * * * * * * * * * * * * * * * * */

typedef struct sLabPart {

   int  friendliness;
   int  tailIsWagging;	

} LabPart;

typedef struct sLab *Lab;

struct sLab {

   Class   class;			// parent structure
   DogPart dog;
   LabPart lab;			// my part

};

extern sClass labc;</lang> <lang c>/* Lab.c */

  1. include "LabProt.h"

void InitLab(LabPart *lab) {

   lab->friendliness = 5;
   lab->tailIsWagging = 1;

} static void labClone( Animal s, Animal c) {

   Lab src = (Lab)s;
   Lab clone = (Lab)c;
   clone->lab = src->lab;

}

sClass labc = { sizeof(struct sLab), "Lab", &dogc, &DfltClsInit,

   &labClone, O_INHERIT, NULL };

Class LabClass = &labc;

Animal NewLab( char *name, char *color, double weight ) {

   Lab dog = (Lab)malloc(LabClass->csize);
   if (dog) {
       ClassRecInit(LabClass);
       dog->class = LabClass;
       InitDog( &dog->dog, name, color, weight);
       InitLab( &dog->lab);
   }
   return (Animal)dog;

}</lang> <lang c>/* Lab.h */

  1. include "Dog.h"

extern Animal NewLab(char *name, char *color, double weight);</lang>

<lang c>/* CollieProt.h */ /** * * * * * * * * * * * * * * * * * *

* Collie - a class derived from Dog 
* * * * * * * * * * * * * * * * * * */
  1. include "DogProt.h"

typedef struct sColliePart {

   double  height;

} ColliePart;

typedef struct sCollie *Collie;

struct sCollie {

   Class   class;			// parent structure
   DogPart dog;
   ColliePart collie;			// my part

};

extern sClass colliec;</lang> <lang c>/* Collie.c */

  1. include "CollieProt.h"

static void collieClone( Animal s, Animal c) {

   Collie src = (Collie)s;
   Collie clone = (Collie)c;
   clone->collie = src->collie;

}

void InitCollie(ColliePart *collie, double height) {

   collie->height = 25.0;

}

sClass colliec = { sizeof(struct sCollie), "Collie", &dogc, &DfltClsInit,

   &collieClone, O_INHERIT, NULL };

Class CollieClass = &colliec;

Animal NewCollie( char *name, char *color, double weight, double height ) {

   Collie dog = (Collie)malloc(CollieClass->csize);
   if (dog) {
       ClassRecInit(CollieClass);
       dog->class = CollieClass;
       InitDog( &dog->dog, name, color, weight);
       InitCollie( &dog->collie, height);
   }
   return (Animal)dog;

}</lang> <lang c>/* Collie.h */

  1. include "Dog.h"

extern Animal NewCollie(char *name, char *color, double weight, double height);</lang>

<lang c>/* CatProt.h */

  1. include "AnimalProt.h"

/* * * * * * * * * * * * */ /* Cat - a derived class */

typedef struct sCatPart {

   char color[32];
   char *name;
   int  age;

} CatPart;

typedef struct sCat *Cat;

struct sCat {

   Class   class;			// parent structure
   CatPart catpart;

};

extern sClass catcls;</lang> <lang c>/* Cat.c */

  1. include "CatProt.h"

static void catClone( Animal s, Animal c) {

   Cat src = (Cat)s;
   Cat clone = (Cat)c;
   clone->catpart.name = strdup(src->catpart.name);

}

static char *catSpeak(Animal s) {

   Cat f = (Cat)s;
   static char  response[90];
   sprintf(response, "My name is %s. I'm a %d mo. old %s wiley %s", 
           f->catpart.name, f->catpart.age, f->catpart.color,
           f->class->cname);
   return response;

}

void catDel(Animal s) {

   Cat f = (Cat)s;
   CatPart *catpart = &f->catpart;	
   if (catpart->name) {
       free(catpart->name);
   }

}

sClass catcls = { sizeof(struct sCat), "Cat", &boc, &DfltClsInit,

   &catClone, &catSpeak, &catDel };

Class CatClass = &catcls;

Animal NewCat( char *name, char *color, int age ) {

   Cat cat = (Cat)malloc(CatClass->csize);
   if (cat) {
       CatPart *catpart = &(cat->catpart);
       ClassRecInit(CatClass);
       cat->class = CatClass;
       catpart->name = strdup(name);
       strncpy(catpart->color, color, 31);
       catpart->age = age;
   }
   return (Animal)cat;

}

/** * Now wasn' that fun. * **/</lang> <lang c>/* Cat.h */

  1. include "Animal.h"

extern Animal NewCat(char *name, char *color, int age);</lang>

<lang c>#include "Cat.h"

  1. include "Lab.h"
  2. include "Collie.h"

int main(int argc, char *argv[]) {

   Animal  kara = NewCat( "Kara", "grey", 15 );
   Animal  bruce = NewDog("Bruce", "yellow", 85.0 );
   Animal  bigrex = NewLab("Rex", "chocolate", 65.0 );
   Animal  sandy = NewCollie("Sandy", "yellow", 35.0, 21.0 );
   printf("Ok, created pets\n");
   printf("Kara says %s\n", ObjSpeak(kara));
   printf("Bruce says %s\n", ObjSpeak(bruce));
   printf("Big Rex says %s\n", ObjSpeak(bigrex));
   printf("Sandy says %s\n", ObjSpeak(sandy));
   ObjDestroy(kara);
   ObjDestroy(bruce);
   ObjDestroy(bigrex);
   ObjDestroy(sandy);
   return 0;

}</lang>