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.)"

/* Animal.h */
#ifndef _ANIMAL_H 
#define _ANIMAL_H

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct object *Animal;

extern char *ObjSpeak(Animal a);
extern Animal ObjClone(Animal a);
extern void ObjDestroy(Animal a);
#endif
/* AnimalProt.h */
#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;

#define O_INHERIT (void *)-1
extern void ClassRecInit(Class c);
extern void DfltClsInit(Class c);
extern sClass boc;
/* Animal.c */
#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;
/* DogProt.h */
#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;
/* Dog.c */
/** * * * * * * * * * * * * * * * * * *
 * Dog - a class derived from Animal 
 * * * * * * * * * * * * * * * * * * */
#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;
}
/* Dog.h */
#ifndef _DOG_H
#define _DOG_H
#include "Animal.h"
extern Animal NewDog(char *name, char *color, double weight);
#endif
/* LabProt.h */
#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;
/* Lab.c */
#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;
}
/* Lab.h */
#include "Dog.h"
extern Animal NewLab(char *name, char *color, double weight);
/* CollieProt.h */
/** * * * * * * * * * * * * * * * * * *
 * Collie - a class derived from Dog 
 * * * * * * * * * * * * * * * * * * */
#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;
/* Collie.c */
#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;
}
/* Collie.h */
#include "Dog.h"
extern Animal NewCollie(char *name, char *color, double weight, double height);
/* CatProt.h */
#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;
/* Cat.c */
#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. * **/
/* Cat.h */
#include "Animal.h"
extern Animal NewCat(char *name, char *color, int age);
#include "Cat.h"
#include "Lab.h"
#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;
}