デジタルちんぶろぐ

デジタルな話題

ホーム 連絡をする 同期する ( RSS 2.0 ) Login
投稿数  268  : 記事  0  : コメント  4383  : トラックバック  79

ニュース


技術以外は
ちんぶろぐ

記事カテゴリ

書庫

日記カテゴリ

Ognacさんが何か違うぞで書かれていたことをCで書いてみました。

# 元ネタはアセンブラって話ですが

この手のことは既に手垢が付きまくっていてまぁ今更感もあるのですが。

# その癖に無駄に長いコード載せてスイマセン

 

#include <stdio.h>

typedef    struct c_a_tag    c_a; // 自オブジェクトの型が必要なので先にtypedef
typedef struct { // 仮想関数テーブル
    void    (*func)(c_a* self);
} c_a_if;

struct c_a_tag {
    const c_a_if*    i_f;

    int            a;
};

typedef struct c_b_tag    c_b;

struct c_b_tag { // c_aを継承したつもりのc_b
    c_a    super;

    int    b;
};

typedef struct c_c_tag    c_c;
struct c_c_tag { // c_aを継承したつもりのc_b
    c_a    super;

    int    c;
};

void c_a_func(c_a* self) // 気分的には c_a::funcな仮想関数
{
    printf("Class c_a: a=%d\n", self->a );
}

void c_b_func(c_a* self) // 気分的には c_b::funcな仮想関数
{
    c_b* self_b = (c_b*) self;
    printf("Class c_b: a=%d/b=%d\n", self_b->super.a, self_b->b);
}

void c_c_func(c_a* self) // 気分的には c_c::funcな仮想関数
{
    c_c* self_c = (c_c*) self;
    printf("Class c_c: a=%d/c=%d\n", self_c->super.a, self_c->c);
}

// 仮想関数テーブル
const    c_a_if    c_a_if_i = { c_a_func };
const    c_a_if    c_b_if_i = { c_b_func };
const    c_a_if    c_c_if_i = { c_c_func };

// 各クラスのコンストラクタ的なもの
void construct_c_a(c_a* obj)
{
    obj->i_f = &c_a_if_i;
    obj->a = 0;
}

void construct_c_b(c_b* obj)
{
    construct_c_a(&obj->super);
    obj->super.i_f = &c_b_if_i;
    obj->super.a = 1;
    obj->b = 10;
}

void construct_c_c(c_c* obj)
{
    construct_c_a(&obj->super);
    obj->super.i_f = &c_c_if_i;
    obj->super.a = 2;
    obj->c = 20;
}

// お試しメイン
int main(void)
{
    c_a    a;
    c_b    b;
    c_c    c;
    c_a*    ar[3];
    int        i;

    construct_c_a(&a);
    construct_c_b(&b);
    construct_c_c(&c);

    ar[0] = &a;
    ar[1] = (c_a*) &b;
    ar[2] = (c_a*) &c;

    for(i = 0; i < 3; i++) ar[i]->i_f->func(ar[i]);

    return 0;
}

 

------実行結果------

Class c_a: a=0
Class c_b: a=1/b=10
Class c_c: a=2/c=20

------------------------

 

多分上司の方が言いたかったことはこういう事なんでしょう。

アセンブラで書く場合、構造体はオフセットで表すことが出来るので、各構造体のメンバの取得は

    mov eax,ofs[ebx] (x86だとこんな書き方だったっけ?)

みたいな感じで出来ますね。

 

main関数のforループのところまで来ると便利な感じで使えますが、そこまでのセットアップが面倒くさい。

とは言え僕はCオンリーな開発の場合この手の事をけっこうやっちゃいます。

多態モドキが出来ることが結構便利なのよね。

投稿日時 : 2008年3月26日 21:00

コメント

# re: 継承をCで書く 2008/03/26 23:16 ゆーち
こんちは。

深く読んでませんが(^◇^;仮想関数の実装方法は多くの処理系でだいたいそんな感じだとおもいます。

ただ、アセンブラレベルやCのレベルでオブジェクト指向の継承とその実装を説明するのだとすれば、よけいに元ネタの間違った内容の伝搬はよくないなぁと思うのであります。

自分のことは、とりあえず、棚に上げますが(w

# re: 継承をCで書く 2008/03/27 0:34 Ognac
Ognacです。
仮想関数になるので、この種の実装になるのでしょうね。
本文にも書いたのですが、低言語での実装方法と、コーディング思想を同一土俵で考えている人たちは、乱暴な言い方をすれば、回路で実現すべき物とソフトで実現すべきものを区別できてないと思うのです。
 Goto文やLong Jump は悪だというのは高級言語での話で、
Assembler lだと JUMPがなければプログラムが成立しない訳だし。
 適用局面の認識力かもしれません。
仮想関数のソースは懐かしかったです。業務系に移ったので縁が薄くなって忘れかけてました。

# re: 継承をCで書く 2008/03/27 10:38 スーパーあんどちん
>> ゆーちさん
深く読む必要なんてないですよ。
実装は大抵こんな感じになるでしょうから。
各構造体に仮想関数へのポインタを持たせると言う方法もありますが、メモリ効率良くないですしね。

>> Ognacさん
言われることはそのとおりだと思います。
でも、どう実装されているかを見ないと理解できないって人が居るのもまた事実。
(僕も最初はそうでした)
LongjumpはさておきGotoってそんなに悪かな?と思ってます。深いループから抜ける場合なんかGoto使ったほうがわかりやすいってのもありますし。



# re: 継承をCで書く 2008/03/27 11:07 中吉
>LongjumpはさておきGotoってそんなに悪かな?と思ってます

まぁ、できる人はどんな言語使ってもキレイに書いてくれますが……
という、散々言い古されている話に突入しそうなので(ry

真理表を起こしなおさなきゃいけないようなGoToをみると怒りがこみ上げるです。安易なGoToで見る気も起きない冗長な表になったしまうことがorz
#Let's say "UnSat!""


# re: 継承をCで書く 2008/03/27 12:47 スーパーあんどちん
>> 中吉さん

人、技量に関わる事言い出すとそこでFAもしくは無限ループになりそうですからそっちはスルーで^^;

安易なGoToは確かに嫌ですね。
僕が許容できるのは、インデントが深くなる事を抑えることが出来るとか、条件判定を減らすことが出来るとかそういった場合ですね。



Post Feedback

タイトル
名前
Url:
コメント: