Last active
November 1, 2023 17:29
-
-
Save cwchentw/16b4842f649e0c4877ec30a2a67f85a9 to your computer and use it in GitHub Desktop.
Polymorphism with Function Pointer in C.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdlib.h> | |
#include "iperson.h" | |
void iperson_delete(void *self) | |
{ | |
if (self) { | |
free(self); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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