Skip to content

Instantly share code, notes, and snippets.

@cwchentw
Last active November 1, 2023 17:29
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cwchentw/16b4842f649e0c4877ec30a2a67f85a9 to your computer and use it in GitHub Desktop.
Save cwchentw/16b4842f649e0c4877ec30a2a67f85a9 to your computer and use it in GitHub Desktop.
Polymorphism with Function Pointer in C.
#include <stdlib.h>
#include <assert.h>
#include "person.h"
#include "employee.h"
#include "iperson.h"
// Private helper function declaration.
static void check_salary(double salary);
static char* _name(void *self);
static void _set_name(void *self, char *name);
static unsigned int _age(void *self);
static void _set_age(void *self, unsigned int age);
struct employee_t {
person_t* super;
char *company;
double salary;
};
employee_t* employee_new(
char *name, unsigned int age, char *company, double salary)
{
check_salary(salary >= 0.0);
// Create parent object.
person_t *super = person_new(name, age);
// Create child object.
employee_t *ee = malloc(sizeof(employee_t));
ee->super = super;
ee->company = company;
ee->salary = salary;
return ee;
}
char* employee_name(employee_t *self)
{
return person_name(self->super);
}
void employee_set_name(employee_t *self, char *name)
{
person_set_name(self->super, name);
}
unsigned int employee_age(employee_t *self)
{
return person_age(self->super);
}
void employee_set_age(employee_t *self, unsigned int age)
{
person_set_age(self->super, age);
}
char* employee_company(employee_t *self)
{
return self->company;
}
void employee_set_company(employee_t *self, char *company)
{
self->company = company;
}
double employee_salary(employee_t *self)
{
return self->salary;
}
void employee_set_salary(employee_t *self, double salary)
{
check_salary(salary);
self->salary = salary;
}
void employee_delete(void *self)
{
if (self) {
free(self);
}
}
iperson_t* employee_to_iperson()
{
iperson_t *ip = malloc(sizeof(iperson_t));
ip->name = _name;
ip->set_name = _set_name;
ip->age = _age;
ip->set_age = _set_age;
return ip;
}
static void check_salary(double salary)
{
assert(salary >= 0.0);
}
static char* _name(void *self)
{
return employee_name((employee_t *) self);
}
static void _set_name(void *self, char *name)
{
employee_set_name((employee_t *) self, name);
}
static unsigned int _age(void *self)
{
return employee_age((employee_t *) self);
}
static void _set_age(void *self, unsigned int age)
{
employee_set_age((employee_t *) self, age);
}
#pragma once
#include "iperson.h"
typedef struct employee_t employee_t;
employee_t* employee_new(
char *name, unsigned int age, char *company, double salary);
char* employee_name(employee_t *self);
void employee_set_name(employee_t *self, char *name);
unsigned int employee_age(employee_t *self);
void employee_set_age(employee_t *self, unsigned int age);
char* employee_company(employee_t *self);
void employee_set_company(employee_t *self, char *company);
double employee_salary(employee_t *self);
void employee_set_salary(employee_t *self, double salary);
void employee_delete(void *self);
iperson_t* employee_to_iperson();
#include <stdlib.h>
#include "iperson.h"
void iperson_delete(void *self)
{
if (self) {
free(self);
}
}
#pragma once
typedef struct iperson_t iperson_t;
struct iperson_t {
char* (*name) (void *self);
void (*set_name) (void *self, char *name);
unsigned int (*age) (void *self);
void (*set_age) (void *self, unsigned int age);
};
void iperson_delete(void *self);
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "person.h"
#include "employee.h"
#include "iperson.h"
int main()
{
person_t *p = person_new("Michael", 37);
if (!p) {
perror("Failed to allocate p\n");
goto ERROR;
}
iperson_t *ipp = person_to_iperson();
if (!ipp) {
perror("Failed to allocate ipp\n");
goto ERROR;
}
employee_t *ee = employee_new("Tommy", 28, "Google", 1000);
if (!ee) {
perror("Failed to allocate ee\n");
goto ERROR;
}
iperson_t *ipee = employee_to_iperson();
if (!ipee) {
perror("Failed to allocate ipee\n");
goto ERROR;
}
iperson_t *ips[] = {ipp, ipee};
void *objs[] = {(void *) p, (void *) ee};
// Polymorphic calls.
for (int i = 0; i < 2; i++) {
printf("Name: %s\n", ips[i]->name(objs[i]));
printf("Age: %d\n", ips[i]->age(objs[i]));
}
// Mutate p.
ipp->set_name(p, "Mike");
ipp->set_age(p, 39);
// Mutate ee.
ipee->set_name(ee, "Tom");
ipee->set_age(ee, 30);
// Mutate ee with non-polymorphic call here.
employee_set_company(ee, "Microsoft");
employee_set_salary(ee, 1200);
printf("\n"); // Separator.
// Polymorphic calls again.
for (int i = 0; i < 2; i++) {
printf("Name: %s\n", ips[i]->name(objs[i]));
printf("Age: %d\n", ips[i]->age(objs[i]));
}
iperson_delete(ipp);
iperson_delete(ipee);
person_delete(p);
employee_delete(ee);
return 0;
ERROR:
if (ipee)
iperson_delete(ipee);
if (ee)
employee_delete(ee);
if (ipp)
iperson_delete(ipp);
if (p)
person_delete(p);
return 1;
}
#include <stdlib.h>
#include "person.h"
static char* _name(void *self);
static void _set_name(void *self, char *name);
static unsigned int _age(void *self);
static void _set_age(void *self, unsigned int age);
struct person_t {
char *name;
unsigned int age;
};
person_t* person_new(char *name, unsigned int age)
{
person_t* p = malloc(sizeof(person_t));
p->name = name;
p->age = age;
return p;
}
char* person_name(person_t *self)
{
return self->name;
}
void person_set_name(person_t *self, char* name)
{
self->name = name;
}
unsigned int person_age(person_t *self)
{
return self->age;
}
void person_set_age(person_t *self, unsigned int age)
{
self->age = age;
}
void person_delete(void *self)
{
if (self) {
free(self);
}
}
iperson_t* person_to_iperson()
{
iperson_t* ip = malloc(sizeof(iperson_t));
ip->name = _name;
ip->set_name = _set_name;
ip->age = _age;
ip->set_age = _set_age;
return ip;
}
static char* _name(void *self)
{
return person_name((person_t *) self);
}
static void _set_name(void *self, char *name)
{
person_set_name((person_t *) self, name);
}
static unsigned int _age(void *self)
{
return person_age((person_t *) self);
}
static void _set_age(void *self, unsigned int age)
{
person_set_age((person_t *) self, age);
}
#pragma once
#include "iperson.h"
typedef struct person_t person_t;
person_t* person_new(char *name, unsigned int age);
char* person_name(person_t *self);
void person_set_name(person_t *self, char *name);
unsigned int person_age(person_t *self);
void person_set_age(person_t *self, unsigned int age);
void person_delete(void *self);
iperson_t* person_to_iperson();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment