From d98f46ce647846b0aa30b2e16a30fd4e152a1bf5 Mon Sep 17 00:00:00 2001 From: Carlos Maiolino Date: Thu, 10 Jul 2025 22:55:07 +0200 Subject: Add new code Signed-off-by: Carlos Maiolino --- C/OOP/Makefile | 18 ++++++++++++ C/OOP/README | 4 +++ C/OOP/animal/animal.c | 72 +++++++++++++++++++++++++++++++++++++++++++++ C/OOP/cat/cat.c | 41 ++++++++++++++++++++++++++ C/OOP/include/animal_p.h | 23 +++++++++++++++ C/OOP/include/animal_priv.h | 19 ++++++++++++ C/OOP/include/cat_p.h | 19 ++++++++++++ C/OOP/main.c | 30 +++++++++++++++++++ 8 files changed, 226 insertions(+) create mode 100644 C/OOP/Makefile create mode 100644 C/OOP/README create mode 100644 C/OOP/animal/animal.c create mode 100644 C/OOP/cat/cat.c create mode 100644 C/OOP/include/animal_p.h create mode 100644 C/OOP/include/animal_priv.h create mode 100644 C/OOP/include/cat_p.h create mode 100644 C/OOP/main.c (limited to 'C/OOP') diff --git a/C/OOP/Makefile b/C/OOP/Makefile new file mode 100644 index 0000000..478ddab --- /dev/null +++ b/C/OOP/Makefile @@ -0,0 +1,18 @@ +oop_prog: main.o animal.o cat.o + gcc -Wall -o oop_prog main.o cat/cat.o animal/animal.o + +main.o: main.c + gcc -I./include -c main.c + +animal.o: animal/animal.c + gcc -I./include -c animal/animal.c -o animal/animal.o + +cat.o: cat/cat.c + gcc -I./include -c cat/cat.c -o cat/cat.o + + +clean: + rm animal/*.o + rm cat/*.o + rm main.o + rm oop_prog diff --git a/C/OOP/README b/C/OOP/README new file mode 100644 index 0000000..4aab525 --- /dev/null +++ b/C/OOP/README @@ -0,0 +1,4 @@ +This is a simple example on how to write Object-oriented code in C. + +The structure here is simple, we have a 'parent' class named Animal, +and its sub-classes based on different animals. diff --git a/C/OOP/animal/animal.c b/C/OOP/animal/animal.c new file mode 100644 index 0000000..01934d7 --- /dev/null +++ b/C/OOP/animal/animal.c @@ -0,0 +1,72 @@ +/* Animal class implementation */ + +#define MAX_NAME_LEN 10 +#include +#include +#include + +#include "animal_priv.h" + + +struct animal * animal_new() { + return (struct animal *)malloc(sizeof(struct animal)); +} + +/* + * By passing the custom sound function to the constructor, we prevent the need to expose the + * Animal's private interface to the sub-class + * + * This is an attempt to get as much abstraction as possible of a C program. + * The sub-class has no business in understanding the inner functionality of the parent class, + * so, this is an attempt to hide the animal implementation as much as possible from the sub-class. + */ +void animal_ctor(struct animal *animal, + void (*sound_fn)(void)) +{ + animal->name = malloc(MAX_NAME_LEN * sizeof(char)); + + if (sound_fn) + animal->make_sound = sound_fn; + else + animal->make_sound = NULL; +} + +void animal_dtor(struct animal *animal) +{ + free(animal->name); +} + +void animal_get_name(struct animal *animal, char *name) +{ + strncpy(name, animal->name, MAX_NAME_LEN); +} + +void animal_set_name(struct animal *animal, const char *name) +{ + if (strlen(name) >= MAX_NAME_LEN) + strncpy(animal->name, "\0", 1); + else + strncpy(animal->name, name, MAX_NAME_LEN); +} + +/* + * To be able to access the object specific implementation of make_sound(), + * this function should somehow access the function pointer to the + * object-specific implementation. + * + * This could be done in two ways: + * - By having the Animal object embedded within the sub-class, so both + * the Animal object and the Sub-Class object will share the same address + * in memory, or: + * - We add an 'ops' field in the Animal object, which should be populated + * by the sub-class. + * + * In both ways, there is no way to really hide the Animal implementation from + * the sub-class, as in one way or another, we'll need to have access to the + * Animal class fields, so we can override the functions. + */ +void animal_sound(struct animal *animal) +{ + if (animal->make_sound) + animal->make_sound(); +} diff --git a/C/OOP/cat/cat.c b/C/OOP/cat/cat.c new file mode 100644 index 0000000..c513bb6 --- /dev/null +++ b/C/OOP/cat/cat.c @@ -0,0 +1,41 @@ +/* + * Cat class. + * + * This is a subclass of the animal class + */ + +#include +#include + +#include "animal_priv.h" +#include "animal_p.h" + +/* + * We need access to animal's definition, so we can embbed it + * within our sub-class + */ +struct cat { + struct animal animal; +}; + +void __cat_sound(void) +{ + printf("The cat makes MEOOOOOW\n"); +} + +struct cat *cat_new(void) +{ + return (struct cat*)malloc(sizeof(struct cat)); +} + +void cat_ctor(struct cat *cat) +{ + animal_ctor((struct animal *)cat, + __cat_sound); + printf("cat_ctor: cat: %p animal: %p\n", cat, &cat->animal); +} + +void cat_dtor(struct cat *cat) +{ + animal_dtor((struct animal *)cat); +} diff --git a/C/OOP/include/animal_p.h b/C/OOP/include/animal_p.h new file mode 100644 index 0000000..e09aa7c --- /dev/null +++ b/C/OOP/include/animal_p.h @@ -0,0 +1,23 @@ +/* Animal class public interface */ + +#ifndef ANIMAL_P_H +#define ANIMAL_P_H + +/* Forward declaration */ +struct animal; + +/* Alloc new object */ +struct animal* animal_new(void); + +/* Constructor - make_sound may be NULL*/ +void animal_ctor(struct animal*, void (*make_sound)(void)); + +/* Destructor */ +void animal_dtor(struct animal*); + +/* Behavior */ +void animal_get_name(struct animal*, char*); +void animal_set_name(struct animal*, const char*); +void animal_sound(void *); + +#endif /* ANIMAL_P_H */ diff --git a/C/OOP/include/animal_priv.h b/C/OOP/include/animal_priv.h new file mode 100644 index 0000000..78a83c1 --- /dev/null +++ b/C/OOP/include/animal_priv.h @@ -0,0 +1,19 @@ +/* Animal class private definition */ + +#ifndef ANIMAL_PRIV_H +#define ANIMAL_PRIV_H + +/* + * We use a "private" definition as a way to encapsulate it, hiding + * it from the users. + * + * Access to its private definition is only allowed to its sub-classes. + * + * We could enforce it by moving here the allocator and constructors + */ +struct animal { + char *name; + void (*make_sound) (void); +}; + +#endif /* ANIMAL_PRIV_H */ diff --git a/C/OOP/include/cat_p.h b/C/OOP/include/cat_p.h new file mode 100644 index 0000000..82bcfb1 --- /dev/null +++ b/C/OOP/include/cat_p.h @@ -0,0 +1,19 @@ +/* Cat class public interface */ + +#ifndef CAT_P_H +#define CAT_P_H + +struct cat; + +/* Allocator */ +struct cat *cat_new(void); + +/* Constructor */ +void cat_ctor(struct cat *); + +/* Destructor */ +void cat_dtor(struct cat *); + +/* Behavior functions inherited from Animal class */ + +#endif /* CAT_P_H */ diff --git a/C/OOP/main.c b/C/OOP/main.c new file mode 100644 index 0000000..7943580 --- /dev/null +++ b/C/OOP/main.c @@ -0,0 +1,30 @@ +/* + * Simple program exemplifying the usage of Animal class + * and its sub-classes + */ +#include + +/* + * The main program here, only need access to the public interfaces + * but the sub-classes will need access to the animal's private interface + */ +#include "animal_p.h" +#include "cat_p.h" + +int main(void) { + + /* We don't need to know how the cat object is implemented */ + struct cat *myCat = cat_new(); + + cat_ctor(myCat); + + /* + * For us to have the Animal class definition hidden, the animal_sound() + * should have a way to defer the parent Animal class, from the cat class. + * + * See its implementation within animal.c + */ + animal_sound((struct animal *)myCat); + return 0; +} + -- cgit v1.2.3