polymorphism-in-c

Table of Contents

Polymorphism in C

Here's a fun little one. Implementing some object oriented features in pure C. Let's have some fun and implement an abstract base class for a Node.

struct Node {
  int value;
  struct Node* next;
};

This Node is the base class that we will extend later, but we can also use it as is.

#include <stdio.h>

struct Node {
  int value;
  struct Node* next;
};

int main() {
  struct Node n = {20, NULL};
  printf("%d\n", n.value);
}

So let's start extending it by making a struct with a function pointer where we can add to the node value.

Clearly, we could just do something like n.value += new_value, but that's so procedural, isn't it

#include <stdio.h>

struct Node {
  int value;
  struct Node* next;
};

struct AddableNode {
  struct Node *super;
  void (*add)(struct AddableNode*, int);
}

void add_to_node(struct AddableNode *self, int value) {
  self->super->value += value;
}

int main() {
  struct Node n = {50, NULL};
  struct AddableNode an = {&n, add_to_node};

  an.add(&an, 10);

  printf("%u\n", an.super->value);
}

Here we've created a new AddableNode struct which takes a pointer to its base struct (The AddableNode) and a function pointer to add. This function pointer inside of the struct returns void, calls itself add, and takes in two paramters, a pointer to an AddableNode (self / this), and a value to add.

We then call the function on the struct with an.add(&an, 10), which is basically like saying self.add(self, 10), just in a roundabout way.

Now the problem here is that it becomes a bit of a pain to get the value from the pointer; we would have to do something like self->super->value which is a bit of typing. Why not just make a method for get and set for our node value too so we don't have to type as much?

#include <stdio.h>

struct Node {
  int value;
  struct Node* next;
};

struct AddableNode {
  struct Node *super;
  void (*add)(struct AddableNode*, int);
  int (*get_value)(struct AddableNode*);
  void (*set_value)(struct AddableNode*, int);
};

void add_to_node(struct AddableNode *self, int _value) {
  self->super->value += _value;
}

int get_node_value(struct AddableNode *self) {
  return self->super->value;
}

void set_node_value(struct AddableNode *self, int _value) {
  self->super->value = _value;
}

int main() {
  struct Node n = {50, NULL};
  struct AddableNode an = {&n, add_to_node, get_node_value, set_node_value};

  an.add(&an, 10);
  an.set_value(&an, 30);

  printf("%u\n", an.get_value(&an));
}

I guess an.get_value(&an); doesn't save much space compared to an->super->value, but its a bit more expressive.

it is a bit of a pain to always instantiate this class, so let's make a factory that takes in a value and returns an AddableNode.

struct AddableNode node_factory(int _value) {
  struct Node n = {_value, NULL};
  struct AddableNode an = {&n, add_to_node, get_node_value, set_node_value};
  return an;
}

Here's our final code.

#include <stdio.h>

struct Node {
  int value;
  struct Node* next;
};

struct AddableNode {
  struct Node *super;
  void (*add)(struct AddableNode*, int);
  int (*get_value)(struct AddableNode*);
  void (*set_value)(struct AddableNode*, int);
};

void add_to_node(struct AddableNode *self, int _value) {
  self->super->value += _value;
}

int get_node_value(struct AddableNode *self) {
  return self->super->value;
}

void set_node_value(struct AddableNode *self, int _value) {
  self->super->value = _value;
}

struct AddableNode node_factory(int _value) {
  struct Node n = {_value, NULL};
  struct AddableNode an = {&n, add_to_node, get_node_value, set_node_value};
  return an;
}

int main() {
  struct AddableNode an = node_factory(0);
  an.add(&an, 10);
  an.set_value(&an, 30);

  printf("%u\n", an.get_value(&an));
}