summaryrefslogtreecommitdiff
path: root/C/OOP
diff options
context:
space:
mode:
authorCarlos Maiolino <[email protected]>2025-07-10 22:55:07 +0200
committerCarlos Maiolino <[email protected]>2025-07-10 22:56:55 +0200
commitd98f46ce647846b0aa30b2e16a30fd4e152a1bf5 (patch)
tree267474fcc77cf20b428f6f4c7f768ca09f4cfe0e /C/OOP
parent869e68986aa8f69af6e7842260a68d1e5c6f796f (diff)
Add new code
Signed-off-by: Carlos Maiolino <[email protected]>
Diffstat (limited to 'C/OOP')
-rw-r--r--C/OOP/Makefile18
-rw-r--r--C/OOP/README4
-rw-r--r--C/OOP/animal/animal.c72
-rw-r--r--C/OOP/cat/cat.c41
-rw-r--r--C/OOP/include/animal_p.h23
-rw-r--r--C/OOP/include/animal_priv.h19
-rw-r--r--C/OOP/include/cat_p.h19
-rw-r--r--C/OOP/main.c30
8 files changed, 226 insertions, 0 deletions
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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#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 <stdio.h>
+#include <stdlib.h>
+
+#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 <stdio.h>
+
+/*
+ * 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;
+}
+