Cで実現する「ぷちオブジェクト指向」
↑このアーティクルのケツんとこで
「仮想関数をCでやらかすのはめんどくせー」
と書きました。
どのくらいめんどくせーかやってみた。
#include <cstdio>
class animal {
public:
virtual void sound() =0;
virtual ~animal();
};
animal::~animal() { puts("...合掌。"); }
class cat : public animal {
virtual void sound();
virtual ~cat();
};
void cat::sound() { puts("にゃー"); }
cat::~cat() { puts("ふぎゃー"); }
class dog : public animal {
virtual void sound();
virtual ~dog();
};
void dog::sound() { puts("わおーん"); }
dog::~dog() { puts("きゃいーん"); }
int main() {
animal* p;
p = new cat();
p->sound();
delete p;
p = new dog();
p->sound();
delete p;
}
C++だとこれで済むのが…
/*
* animal.h
*/
#ifndef animal_H__
#define animal_H__
typedef struct animal_t* animal;
void animal_ctor(animal);
void animal_dtor(animal);
animal animal_new();
void animal_delete(animal);
void animal_sound(animal);
#endif
/*
* cat.h
*/
#ifndef cat_H__
#define cat_H__
typedef struct cat_t* cat;
void cat_ctor(cat);
void cat_dtor(cat);
cat cat_new();
void cat_delete(cat);
void cat_sound(cat);
#endif
/*
* dog.h
*/
#ifndef dog_H__
#define dog_H__
typedef struct dog_t* dog;
void dog_ctor(dog);
void dog_dtor(dog);
dog dog_new();
void dog_delete(dog);
void dog_sound(dog);
#endif
/*
* trial.c おためし
*/
#include "animal.h"
#include "cat.h"
#include "dog.h"
int main() {
animal p;
p = (animal)cat_new();
animal_sound(p);
animal_delete(p);
p = (animal)dog_new();
animal_sound(p);
animal_delete(p);
return 0;
}
/*
* animal.vtbl 仮想関数テーブル
* 利用者にはナイショ
*/
struct v_animal {
void (*dtor)(animal);
void (*sound)(animal);
};
/*
* animal.c
*/
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "animal.h"
#include "animal.vtbl"
struct animal_t {
struct v_animal* v_tbl;
};
static void bad_sound(animal obj) {
assert(!"らめぇぇぇ!");
exit(-1);
}
void animal_sound(animal obj) { (*obj->v_tbl->sound)(obj); }
void animal_dtor(animal obj) { puts("...合掌。"); }
static struct v_animal animal_v_tbl = { &animal_dtor, &bad_sound };
void animal_ctor(animal obj) { obj->v_tbl = &animal_v_tbl; }
animal animal_new() {
animal result = (animal)malloc(sizeof(struct animal_t));
if ( result != NULL ) { animal_ctor(result); }
return result;
}
void animal_delete(animal obj) {
(*obj->v_tbl->dtor)(obj);
free(obj);
}
/*
* cat.c
*/
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "animal.h"
#include "animal.vtbl"
#include "cat.h"
struct cat_t {
struct v_animal* v_tbl;
};
void cat_sound(cat obj) { puts("にゃー"); }
void cat_dtor(cat obj) {
puts("ふぎゃー");
animal_dtor((animal)obj);
}
static struct v_animal cat_v_tbl = {
(void (*)(animal))&cat_dtor,
(void (*)(animal))&cat_sound
};
void cat_ctor(cat obj) { obj->v_tbl = &cat_v_tbl; }
cat cat_new() {
cat result = (cat)malloc(sizeof(struct cat_t));
if ( result != NULL ) { cat_ctor(result); }
return result;
}
void cat_delete(cat obj) {
(*obj->v_tbl->dtor)((animal)obj);
free(obj);
}
/*
* dog.c
*/
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "animal.h"
#include "animal.vtbl"
#include "dog.h"
struct dog_t {
struct v_animal* v_tbl;
};
void dog_sound(dog obj) { puts("わおーん"); }
void dog_dtor(dog obj) {
puts("きゃいーん");
animal_dtor((animal)obj);
}
dog dog_new() {
dog result = (dog)malloc(sizeof(struct dog_t));
if ( result != NULL ) { dog_ctor(result); }
return result;
}
static struct v_animal dog_v_tbl = {
(void (*)(animal))&dog_dtor,
(void (*)(animal))&dog_sound
};
void dog_ctor(dog obj) { obj->v_tbl = &dog_v_tbl; }
void dog_delete(dog obj) {
(*obj->v_tbl->dtor)((animal)obj);
free(obj);
}
めんどくせーっ!