web-dev-qa-db-ja.com

Cの構造体は、関数のように振る舞うことができますか?

私はCとstructsを使用していますが、構造体にはメンバーを含めることができますが、関数を含めることはできません。簡単にするために、strという名前の文字列の構造体を作成し、str.replace(int i, char c)を実行できるようにしたいとします。ここで、iは文字列のインデックスであり、 cは、位置iの文字を置き換える文字です。構造体は関数を持てないか、この動作を実装して、構造体が実際に構造体だけを新しい構造体にコピーして更新する(単純な)関数を持つことができることを模倣できる方法があるので、これは決して不可能でしょうか?それは何ができるフィールド?

そのため、replaceは、アクセスされたときに更新される新しい構造体または類似の構造体を指す、構造体の3番目のメンバーになる可能性があります。できますか?それとも、私の意図を妨げる組み込みの、または何らかの理論やパラダイムがありますか?

背景は、私がCコードを書いていて、OOP言語のライブラリ組み込みであることがわかっている関数を再発明していることを発見し、OOPが良いだろうと思います文字列とコマンドを操作する方法。

13
Niklas

関数は次のようになります。

void
replace(struct string * s, int i, char c);

これは、操作するオブジェクトへのポインターを最初のパラメーターとして受け入れます。 C++では、これはthis- pointerと呼ばれ、明示的に宣言する必要はありません。 (これをPython必要な場所と比較してください。)

関数を呼び出すには、そのポインターを明示的に渡します。基本的には、o.f(…)構文をf(&o, …)構文と交換します。大したことではない。

polymorphism(別名virtual関数)をサポートする場合、ストーリーはより複雑になります。それはCでエミュレートすることもできます(私は この答え で示しました)。しかし、手作業で行うのはかなり簡単ではありません。

Jan Hudec がコメントしているため、Cには名前空間がないため、replaceという名前の単一の関数しか存在できないため、関数名の前に型名(つまり、string_replace)を付けることを習慣にする必要があります。 。

21
5gon12eder

構造体は関数ポインターを保持できますが、これらは実際には仮想メソッドにのみ必要です。オブジェクト指向Cの非仮想メソッドは、通常、構造体を最初の引数として通常の関数に渡すことによって実行されます。 CのOOPフレームワークの良い例については、 Gobject を参照してください。継承と多態性に必要な多くのボイラープレートを処理するためにマクロを使用します。

Cは44年前に作成されました。オープンソースで非常に人気のある言語です。あなたは、標準のC文字列が扱いにくいと考える最初の人ではありません。 C文字列ライブラリを検索します。ホイールを再発明する必要はありません。

43
Karl Bielefeldt

関数ポインタを使用すると、次のことができます。

str.replace(&str, i, c);

これは一般に、実装が変更される可能性がある場合にのみ役立ちます。その場合は、vtableを使用して、オーバーヘッドが構造体ごとに1つのポインターのみになるようにする必要があります。

str.vtable->replace(&str, i, c);
8
o11c

はい、できます。 Cがメモリ内の関数ブロックへのポインター、別名関数ポインターを許可していることを利用して、仮想関数だけでなく、ポリモーフィズムのようなインターフェイスを作成することもできます(それほどきれいではない場合でも)。

私は、CとGoのインターフェースのようなコードに関する最近私の学生の1人からの質問に続いて、このテーマについてブログ投稿を書きました。

非OOインターフェースのブログ投稿

それがあなたに何かアイデアを与えるかどうか見てください。

他の回答で説明されているように、コードに無料の関数を入れて「this」ポインタを使用することもできます。つまり、作業する既存の構造体にポインタを渡します。

3