nazolabo

フリーランスのWebエンジニアが近況や思ったことを発信しています。

Cでオブジェクト指向

CodeZine:Cで実現する「ぷちオブジェクト指向」(オブジェクト指向, C)
http://codezine.jp/a/article/aid/885.aspx

επιστημη先生だ!LL全盛期の今にこういう記事は貴重。
ところでこの手法の場合、先頭部分が同じ構造体にするんじゃなくて、派生構造体に派生元へのポインタを持たせたほうがよりC++っぽい実装になる気がする。

struct Car_type {
  int capacity_; /* タンク容量[L]   */
  int remain_;   /* ガソリン残量[L] */
  int mileage_;  /* 燃費[L/km]      */
  int distance_; /* 走行距離[km]    */
};

struct Bus_type {
  Car_type* low_class;
  int passengers_; /* 乗客数: 新たに追加(記事のほうセミコロン抜けてる) */
};

な感じにして、car_newはそのままで、bus_newの先頭でlow_classにcar_newする感じ。ああでも多態じゃねえ。
1継承だけなら

struct Car_type {
  void* self;  /* 自身へのポインタ */
  int capacity_; /* タンク容量[L]   */
  int remain_;   /* ガソリン残量[L] */
  int mileage_;  /* 燃費[L/km]      */
  int distance_; /* 走行距離[km]    */
};

struct Bus_type {
  Car_type* low_class;
  int passengers_; /* 乗客数: 新たに追加(記事のほうセミコロン抜けてる) */
};

ってな感じでCar_typeにselfポインタを追加すれば、どっちも同じサイズになるはずだから、Car_typeにアクセスする時は必ず先頭を取るような感じにすれば行けそう。でも手間かかるなぁ。これ以上継承できないし。
ちなみに宿題のところの関数のオーバーライドは…、この方法じゃちょっと頭が回らないので記事のやりかたで。
各構造体の最後に

...
void* functions[MAX_FUNCTIONS];
};

とか追加して、最初にcarの関数全部をつっこんで、その後に上からbusの関数をつっこめば上書き?
アクセスする場合は#defineなりenum(ってCだっけ?)で関数名に連番を振って、(*p->functions[CAR_FUNC_DRIVE])()みたいな感じ?マクロにしちゃえばいいのかなぁ。でも手間だなぁ。あとメモリ使用量がひどい。
int type;とかをメンバに追加して、自身の型タイプ(0からの連番)を保存させておいて、別の場所にvoid* car_functions[MAX_TYPES][MAX_FUNCTIONS];とか作っておいて、(*car_functions[p->type][CAR_FUNC_DRIVE])()とか?メモリ使用量としてはまだ現実的だけど、なんかびみょー。ああでもこれなら最初のやり方にも適用できるのかな。
すっかりLL漬けになってしまった頭でこういうの考えるのは大変だけど、こういうほうがプログラミングっぽくて好きだ。