web-dev-qa-db-ja.com

ポリモーフィズム(C)

重複の可能性:
CでOOスタイルの多態性をどのようにシミュレートできますか?

私が知っている言語の例を使用して、ポリモーフィズムの概念をよりよく理解しようとしています。 Cには多態性がありますか?

14
Belgi

これは Nekuromentoの2番目の例 であり、私がオブジェクト指向Cの慣用的と考える方法で因数分解されます。

animal.h

#ifndef ANIMAL_H_
#define ANIMAL_H_

struct animal
{
    // make vtable_ a pointer so they can be shared between instances
    // use _ to mark private members
    const struct animal_vtable_ *vtable_;
    const char *name;
};

struct animal_vtable_
{
    const char *(*sound)(void);
};

// wrapper function
static inline const char *animal_sound(struct animal *animal)
{
    return animal->vtable_->sound();
}

// make the vtables arrays so they can be used as pointers
extern const struct animal_vtable_ CAT[], DOG[];

#endif

cat.c

#include "animal.h"

static const char *sound(void)
{
    return "meow!";
}

const struct animal_vtable_ CAT[] = { { sound } };

dog.c

#include "animal.h"

static const char *sound(void)
{
    return "arf!";
}

const struct animal_vtable_ DOG[] = { { sound } };

main.c

#include "animal.h"
#include <stdio.h>

int main(void)
{
    struct animal kitty = { CAT, "Kitty" };
    struct animal lassie = { DOG, "Lassie" };

    printf("%s says %s\n", kitty.name, animal_sound(&kitty));
    printf("%s says %s\n", lassie.name, animal_sound(&lassie));

    return 0;
}

これは、メソッドの解決が行われるときのランタイムポリモーフィズムの例です。

C1xは、マクロを介したコンパイル時のポリモーフィズムを可能にする一般的な選択を追加しました。次の例は、C1x Aprilドラフトのセクション6.5.1.1§5からの抜粋です。

#define cbrt(X) _Generic((X), \
    long double: cbrtl, \
    default: cbrt, \
    float: cbrtf \
)(X)

数学関数の型ジェネリックマクロは、ヘッダーtgmath.hを介してC99で既に使用可能でしたが、ユーザーがコンパイラー拡張を使用せずに独自のマクロを定義する方法はありませんでした。

35
Christoph

Cでのランタイムポリモーフィズムのほとんどすべての実装は関数ポインターを使用するため、これが基本的な構成要素です。

これは、プロシージャの実行時の動作が引数に応じて変化する場合の簡単な例です。

#include <stdio.h>

int tripple(int a) {
    return 3 * a;
}

int square(int a) {
    return a * a;
}

void transform(int array[], size_t len, int (*fun)(int)) {
    size_t i = 0;
    for(; i < len; ++i)
        array[i] = fun(array[i]);
}

int main() {
    int array[3] = {1, 2, 3};
    transform(array, 3, &tripple);
    transform(array, 3, &square);

    size_t i = 0;
    for (; i < 3; ++i)
        printf("%d ", array[i]);

    return 0;
}

関数ポインタを使用して、 仮想テーブル を作成し、それを使用して、均一に処理されるが実行時の動作が異なる「オブジェクト」を作成できます。

#include <stdio.h>

struct animal_vtable {
    const char* (*sound)();
};

struct animal {
    struct animal_vtable methods;
    const char* name;
};

const char* cat_sound() {
    return "meow!";
}

const char* dog_sound() {
    return "bark!";
}

void describe(struct animal *a) {
    printf("%s makes \"%s\" sound.\n", a->name, a->methods.sound());
}

struct animal cat = {{&cat_sound}, "cat"};
struct animal dog = {{&dog_sound}, "dog"};

int main() {
    describe(&cat);
    describe(&dog);

    return 0;
}
13
Nekuromento

Cにはポリモーフィズムの本質的なサポートはありませんが、関数ポインター、基本 'クラス'(構造)キャストなどを使用した、動的ディスパッチと論理的に同等の設計パターンがあります。 GTKライブラリ が良い例です。

3
Brett Hale

ポリモーフィズム に関するウィキペディアの記事をすでにチェックしていると思います。

コンピュータサイエンスでは、ポリモーフィズムはプログラミング言語の機能であり、さまざまなデータ型の値を統一されたインターフェイスを使用して処理できます。

その定義によれば、いいえ、Cはポリモーフィズムをネイティブにサポートしていません。たとえば、数値の絶対値を取得するための一般的な関数はありません(absfabsはそれぞれ整数と倍精度浮動小数点数用です)。

C++にも精通している場合は、OOP継承とテンプレートをご覧ください。これらは、そこでのポリモーフィズムのメカニズムです。

2
aztek