Run Code  | API  | Code Wall  | Misc  | Feedback  | Login  | Theme  | Privacy  | Patreon 

polymorphism simulation in plain C with a simple structures

//gcc 5.4.0 [v]
//clang 3.8.0 [v]
//Microsoft (R) C/C++ Optimizing Compiler Version 19.00.23506 for x64 [v]
//polymorphism simulation in plain C with a simple structures
//code by Twareintor (2020)

#include  <stdio.h>

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

typedef enum {aDog, aCat} CLASS;

typedef void speak_();

typedef struct Animal
{
    int id; /* an general ID of every animal in the world */
    void (*speak)();
}ANIMAL;

/** a Dog structure identical with an Animal structure */
typedef struct Dog
{
    int id; 
    void (*speak)();
    char* name; /* not used */
    int tagId; /* a dog has an tag on the collar (not used) */
}DOG;

/** a Cat structure identical with an Animal structure */
typedef struct Cat
{
    int id;
    void (*speak)();
    char* name; /* not used */
    
}CAT;

/* simple (member) function printintg a message */
void bark(){printf("whoa! ");}

/* simple (member) function printintg a message */
void meow(){printf("meow! ");}

/** 
 * constructor or an animal: this takes account of the "class" of the animal
 * that is, in our case, if is a dog or a cat to construct differently the 
 * speak() function
 */
ANIMAL* ctor(CLASS class) 
{
    ANIMAL* animal = (ANIMAL*)malloc(sizeof(ANIMAL));
    animal->speak = 0;
    if(aDog==class) animal->speak = bark;
    if(aCat==class) animal->speak = meow;
    return animal;
}

/** 
 * destructor or an animal: only frees the resources
 */
void dtor(ANIMAL* animal) // destructor or an animal
{
    if(animal) free(animal); animal = 0;
}

/**
 * Shelter; please note tha this structure contains only animals
 * without knowing in advance which kind of animals does it contains
 * if DOG*s or CAT*s, everybody is an animal
 * NOTE that the initialization of the members is the task of the client code!!!
 * animalCount must be initialized to zero; animals not necessary or is up to
 * your compiler or implementation settings regarding realloc() function
 */
typedef struct Shelter
{
    ANIMAL** animals;
    int animalCount;
}SHELTER;

/** 
 * adds an animal in the shelter through using realloc() and adjusting the 
 * animal count - incrementing
 * note that it doesn't matter if the argument is DOG* or CAT*: is automatically casted to 
 * ANIMAL*
 * note that this function checks if the animal is already in the shelter (then does nothing)
 */
void includeAnimal(SHELTER* shelter, ANIMAL* animal)
{
    int i;
    for(i=0; i<shelter->animalCount; i++) /* that is, the animal is already here */
    {
        if(animal==shelter->animals[i]) return; 
    }
    shelter->animalCount++;
    shelter->animals = (ANIMAL**)realloc(shelter->animals, sizeof(ANIMAL*)*shelter->animalCount);
    shelter->animals[shelter->animalCount-1] = animal;
}

/** 
 * removes an animal in the shelter through using realloc() and adjusting the 
 * animal count - deincrementing
 * note that also this function uses realloc
 * if the animal is not in this shelter, nothing happens (checks on the fly)
 */
void excludeAnimal(SHELTER* shelter, ANIMAL* animal)
{
    int i;
    int j;
    for(i=0; i<shelter->animalCount; i++)
    {
        if(animal==shelter->animals[i])  /* that is, the animal is already here */
        {
            shelter->animalCount--;
            for(j=i; j<shelter->animalCount; j++)
            {
                shelter->animals[i] = shelter->animals[i+1];
            }
            shelter->animals = (ANIMAL**)realloc(shelter->animals, sizeof(ANIMAL*)*shelter->animalCount);
            break;
        } /* otherwise is nothing to exclude */
    }
}

/*****************************************************************************************************************/
/** main exit function */
int main(void)
{
    int i; /* to respect ANSI-C standard: all variables before the very first executive statement */
    
    printf("Hello World!\n");

    SHELTER* shelter = (SHELTER*)malloc(sizeof(SHELTER));
    shelter->animals = (ANIMAL**)0; /* initialize animals to nullptr: not really necessary... */
    shelter->animalCount = 0; /* ... but the animal count must be initializet to zero */
    
    /* An animal going to be a dog */
    ANIMAL* myPet = (DOG*)ctor(aDog);
    printf("my pet says: "); myPet->speak(); printf("\n");
    dtor(myPet); 
    /* the same animal going to be a cat this time... */
    myPet = (CAT*)ctor(aCat);
    printf("my pet says: "); myPet->speak(); printf("\n");
    
    /* another animals in the world */
    DOG* yourDog = (DOG*)ctor(aDog);
    DOG* hisDog = (DOG*)ctor(aDog);
    CAT* hersCat = (CAT*)ctor(aCat);
    
    /* let everyone to come under a shelter... */
    includeAnimal(shelter, myPet);
    includeAnimal(shelter, yourDog);
    includeAnimal(shelter, hisDog);
    includeAnimal(shelter, hersCat);
    
    /* see what happens in the shelter now... */
    printf("\n____________\n");        
    for(i=0; i<shelter->animalCount; i++)
        shelter->animals[i]->speak();
    printf("\n____________\n");        
    
    /* elliminate some animals ... */
    excludeAnimal(shelter, hisDog);
    excludeAnimal(shelter, hersCat);
    
    /* see what happens in the shelter now... */
    printf("\n____________\n");        
    for(i=0; i<shelter->animalCount; i++)
        shelter->animals[i]->speak();
    printf("\n____________\n");        

    /* free resources */
    dtor(hersCat);
    dtor(hisDog);
    dtor(yourDog);
    
    free(shelter);
    
    printf("Game Over!\n");
    return 0;
}

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

 run  | edit  | history  | help 1