質問: cの関数ポインターはどこのように機能しますか? 私は最近c言語で関数ポインタを使った経験があります。それで、あなた自身の質問に答える伝統を続けて、私は主題にすぐに飛び込むことを必要とする人々のために、非常に基本の簡単な要約をすることにしました。
回答: cの関数ポインタを使用して、cでオブジェクト指向プログラミングを実行できます。たとえば、次の行はcで記述されています。string s1 = newstring(); s1->set(s1, "hello"); はい、->とnew演算子の欠如は無意味ですが、いくつかのstringクラスのテキストを"hello"に設定していることを意味しているようです。関数ポインタを使用することにより、cでメソッドをエミュレートすることが可能。これはどのように達成されますか?stringクラスは、実際にはメソッドをシミュレートする方法として機能する関数ポインターの束を持つstructです。以下は、stringクラスの部分的な宣言です。typedef struct string_struct* string; struct string_struct { char* (*get)(const void* self); void (*set)(const void* self, char* value); int (*length)(const void* self); }; char* getstring(const void* self); void setstring(const void* self, char* value); int lengthstring(const void* self); string newstring(); ご覧のとおり、stringクラスのメソッドは、実際には宣言された関数への関数ポインターです。 stringのインスタンスを準備する際に、それぞれの関数への関数ポインターをセットアップするためにnewstring関数が呼び出されます。string newstring() { string self = (string)malloc(sizeof(struct string_struct)); self->get = &getstring; self->set = &setstring; self->length = &lengthstring; self->set(self, ""); return self; } たとえば、getstringメソッドを呼び出して呼び出されるget関数は、次のように定義されます。char* getstring(const void* self_obj) { return ((string)self_obj)->internal->value; } 注目できることの1つは、オブジェクトのインスタンスの概念がなく、実際にはオブジェクトの一部であるメソッドを持っているため、呼び出しごとに「自己オブジェクト」を渡す必要があるということです。 (また、internalは、以前のコードリストから省略された隠されたstructにすぎません。これは、情報の隠蔽を実行する方法ですが、関数ポインターには関係ありません。)そのため、s1->set("hello");を実行できるのではなく、s1->set(s1, "hello")でアクションを実行するためにオブジェクトを渡す必要があります。ささいな説明は自分への参照を邪魔にならないように渡さなければならないので、次の部分であるcの継承に進みます。stringのサブクラス、たとえばimmutablestringを作成するとします。文字列を不変にするために、setおよびgetへのアクセスを維持しながら、lengthメソッドにアクセスできず、「コンストラクター」にchar*を強制的に受け入れさせます。typedef struct immutablestring_struct* immutablestring; struct immutablestring_struct { string base; char* (*get)(const void* self); int (*length)(const void* self); }; immutablestring newimmutablestring(const char* value); 基本的に、すべてのサブクラスで利用可能なメソッドは、再び関数ポインターです。今回は、setメソッドの宣言が存在しないため、immutablestringで呼び出すことはできません。immutablestringの実装に関しては、関連するコードは「コンストラクター」関数であるnewimmutablestringのみです。immutablestring newimmutablestring(const char* value) { immutablestring self = (immutablestring)malloc(sizeof(struct immutablestring_struct)); self->base = newstring(); self->get = self->base->get; self->length = self->base->length; self->base->set(self->base, (char*)value); return self; } immutablestringをインスタンス化する際、getおよびlengthメソッドへの関数ポインターは、内部的に保存されているbaseオブジェクトであるstring変数を介して、実際にstring.getおよびstring.lengthメソッドを参照します。関数ポインターを使用すると、スーパークラスからメソッドを継承できます。さらに続けることができますcの多型。たとえば、何らかの理由でlengthメソッドの動作を変更して、immutablestringクラスで常に0を返すようにしたい場合は、以下を行う必要があります。 オーバーライドするlengthメソッドとして機能する関数を追加します。 「コンストラクター」に移動し、オーバーライドするlengthメソッドに関数ポインターを設定します。 lengthにオーバーライドするimmutablestringメソッドを追加するには、lengthoverridemethodを追加します。int lengthoverridemethod(const void* self) { return 0; } 次に、コンストラクター内のlengthメソッドの関数ポインターがlengthoverridemethodに接続されます。immutablestring newimmutablestring(const char* value) { immutablestring self = (immutablestring)malloc(sizeof(struct immutablestring_struct)); self->base = newstring(); self->get = self->base->get; self->length = &lengthoverridemethod; self->base->set(self->base, (char*)value); return self; } これで、lengthクラスのimmutablestringメソッドの動作がstringクラスと同じではなく、lengthメソッドがlengthoverridemethod関数で定義された動作を参照するようになりました。私はまだcでオブジェクト指向プログラミングスタイルを使用して書く方法を学んでいるという免責事項を追加する必要があります。 cのoop。しかし、私の目的は、関数ポインターの多くの使用法の1つを説明することでした。cでオブジェクト指向プログラミングを実行する方法の詳細については、次の質問を参照してください。 cのオブジェクト指向? cでオブジェクト指向コードを記述できますか?