にたまごほうれん草アーカイブ

はてなダイアリーで書いてた「にたまごほうれん草」という日記のアーカイブです。現在は「にたまごほうれん草ブログ」を運営中です。

C言語でオブジェクト指向に挑戦してみる

オブジェクト指向でなぜつくるのか」という本を買って、ちょっとずつ読んでいます。

オブジェクト指向でなぜつくるのか―知っておきたいプログラミング、UML、設計の基礎知識―

オブジェクト指向でなぜつくるのか―知っておきたいプログラミング、UML、設計の基礎知識―

で、もちろん内容はJAVAなどのオブジェクト指向言語を使う人のばあに応用できそうなのですが、私が現在開発で使用しているのはC言語C++オブジェクト指向(?)のようですが、触ったことはありません。そもそも組み込みの場合はC++を色々な都合上使えなかったりします。
なので、C言語でなんとかオブジェクト指向の真似事をしてみようという試みです。上手くいけば仕事にも活かせるかもしれません。
検索してみると、以下のようなサイトが出てくるので読んで色々テクを身につけたいと思います。

ただ、それだけでこのエントリを終わらせるのもアレなので、とりあえず自分が今できる範囲でオブジェクト指向っぽい書き方がどの程度できるのか、試してみました。
コードは最後に添付するとして、現状できたコードを見ての感想は以下のとおり。

  • ##演算子を使うと、なんかそれっぽくできる。(参考:#と##演算子
  • 無駄に構造体本体や型名を引数にとっていてかっこ悪い
  • クラスメソッドはもっと上手く書けるんじゃないだろうか。関数ポインタの使い方がミソ?
  • コンストラクタはもっときれいに書きたい

というわけで、張り切って勉強するのです。

今回できたコード

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct _human_ {
    char *(*getName)(struct _human_ *h);
    int   (*getAge)(struct _human_ *h);
    void  (*destructor)(struct _human_ *h);

    char* name;
    int   age;
} Human;

#define new(klass, ...)      klass##_new(__VA_ARGS__)
#define delete(obj)   (obj)->destructor((obj))
#define setfunc(klass, func) klass##_##func

char* Human_getName(Human *thiz) {
    return thiz->name;
}

int Human_getAge(Human *thiz) {
    return thiz->age;
}

void Human_delete(Human *h) {
    free(h->name);
    free(h);
    printf("human deleted\n");
    return;
}

Human* Human_new(char *name, int age) {
    Human *h;
    h = (Human*)malloc(sizeof(Human));
    
    h->getAge  = setfunc(Human, getAge);
    h->getName = setfunc(Human, getName);

    h->destructor = setfunc(Human, delete);
    
    h->name = strdup(name);
    h->age  = age;

    printf("human initialized\n");
    return h;
}

int main(int argc, char *argv[]) {
    Human *suzuki;

    suzuki = new(Human, "suzuki", 20);

    printf("%s's age: %d\n", 
           suzuki->getName(suzuki), suzuki->getAge(suzuki));

    delete(suzuki);

    return 0;
}

追記

  • deleteの引数に、クラス名を使わずに済むようデストラクタを定義