9

オブジェクト指向プログラミングをエミュレートする方法として、C 構造体で関数ポインターを使用することについてもっと学びたいのですが、私の検索では、このような質問を見つけました。仕事。

私の最良の推測は、このようなものです

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

struct my_struct
{
    int data;
    struct my_struct* (*set_data) (int);
};

struct my_struct* my_struct_set_data(struct my_struct* m, int new_data)
{
    m->data = new_data;
    return m;
}

struct my_struct* my_struct_create() {
    struct my_struct* result = malloc((sizeof(struct my_struct)));
    result->data = 0;
    result->set_data = my_struct_set_data;
    return result;
}

int main(int argc, const char* argv[])
{
    struct my_struct* thing = my_struct_create();
    thing->set_data(1);
    printf("%d\n", thing->data);
    free(thing);
    return 0;
}

しかし、それは私にコンパイラの警告を与えるwarning: assignment from incompatible pointer typeので、明らかに私は何か間違ったことをしています。誰かがC構造体で関数ポインタを正しく使用する方法の小さいが完全な例を提供してもらえますか?

Cで教えられた私のクラスは、これらについても言及していません。これらが実際に C プログラマーによって使用されているかどうか疑問に思います。C 構造体で関数ポインターを使用することの利点と欠点は何ですか?

4

2 に答える 2

14

Andy Stow Away による回答は、コンパイラの警告を修正しますが、2 番目の質問には回答しません。eddieantonio と Niklas R によって与えられたその回答へのコメントは、私の 2 番目の質問に答えますが、コンパイラの警告を修正しません。だから私はそれらを1つの答えにまとめています。

C はオブジェクト指向ではなく、C でオブジェクト指向の設計をエミュレートしようとすると、通常、スタイルが悪くなります。私の例のように、構造体へのポインターを使用して呼び出すことができるように、構造体で呼び出されるメソッドを複製することも例外ではありません。(率直に言って、これは DRY に違反しています。) 構造体の関数ポインターは、ポリモーフィズムに役立ちます。たとえば、要素の線形シーケンスの汎用コンテナーを表す struct ベクトルがある場合、関数ポインターである comparison_func メンバーを格納して、ベクトルの並べ替えと検索を行うと便利な場合があります。ベクトルの各インスタンスは、異なる比較関数を使用できます。ただし、構造体自体を操作する関数の場合は、構造体で重複しない単一の別個の関数を使用する方が適切です。

これにより、何が正しいかの答えがより複雑になります。上記の例をコンパイルする正しい方法は何ですか? 上記の例を再フォーマットして、スタイルを良くする方法はありますか? それとも、C プログラマーが行う方法で関数ポインターを使用する構造体の例は何ですか? 私の質問を定式化する際に、私は私の質問が間違っているという答えを期待していませんでした. 完全を期すために、質問に対する各回答の例を示します。

コンパイラ警告の修正

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

struct my_struct
{
    int data;
    struct my_struct* (*set_data) (struct my_struct*, int);
};

struct my_struct* my_struct_set_data(struct my_struct* m, int new_data)
{
    m->data = new_data;
    return m;
}

struct my_struct* my_struct_create()
{
    struct my_struct* result = malloc((sizeof(struct my_struct)));
    result->data = 0;
    result->set_data = my_struct_set_data;
    return result;
}

int main(int argc, const char* argv[])
{
    struct my_struct* thing = my_struct_create();
    thing->set_data(thing, 1);
    printf("%d\n", thing->data);
    free(thing);
    return 0;
}

スタイルの再フォーマット

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

struct my_struct
{
    int data;
};

void my_struct_set_data(struct my_struct* m, int new_data)
{
    m->data = new_data;
}

struct my_struct* my_struct_create()
{
    struct my_struct* result = malloc((sizeof(struct my_struct)));
    result->data = 0;
    return result;
}

int main(int argc, const char* argv[])
{
    struct my_struct* thing = my_struct_create();
    my_struct_set_data(thing, 1);
    printf("%d\n", thing->data);
    free(thing);
    return 0;
}

構造体での関数ポインタの使用方法のデモンストレーション

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

struct my_struct
{
    void* data;
    int (*compare_func)(const void*, const void*);
};

int my_struct_compare_to_data(struct my_struct* m, const void* comparable)
{
    return m->compare_func(m->data, comparable);
}

struct my_struct* my_struct_create(void* initial_data,
        int (*compare_func)(const void*, const void*))
{
    struct my_struct* result = malloc((sizeof(struct my_struct)));
    result->data = initial_data;
    result->compare_func = compare_func;
    return result;
}

int int_compare(const void* a_pointer, const void* b_pointer)
{
    return *(int*)a_pointer - *(int*) b_pointer;
}

int string_compare(const void* a_pointer, const void* b_pointer)
{
    return strcmp(*(char**)a_pointer, *(char**)b_pointer);
}

int main(int argc, const char* argv[])
{
    int int_data = 42;
    struct my_struct* int_comparator =
            my_struct_create(&int_data, int_compare);

    char* string_data = "Hello world";
    struct my_struct* string_comparator =
             my_struct_create(&string_data, string_compare);

    int int_comparable = 42;
    if (my_struct_compare_to_data(int_comparator, &int_comparable) == 0)
    {
        printf("The two ints are equal.\n");
    }

    char* string_comparable = "Goodbye world";
    if (my_struct_compare_to_data(string_comparator,
            &string_comparable) > 0)
    {
        printf("The first string comes after the second.\n");
    }

    free(int_comparator);
    free(string_comparator);

    return 0;
}
于 2012-07-14T07:33:36.787 に答える
11

構造体定義で、次のように変更します

struct my_struct
{
    int data;
    struct my_struct* (*set_data) (struct my_struct*,int);
};

上記の関数ポインタを main で次のように使用します

thing->set_data(thing,1);
于 2012-07-14T06:08:46.757 に答える