関数を引数として渡す
CoddyのCジャーニー「Object Oriented Programming」セクションの一部 — レッスン 36/61。
関数ポインタの最も強力な使い方の1つは、それらを他の関数への引数として渡すことです。これにより、関数のコードを修正することなく、その関数にカスタムの動作を注入することができます。この手法は、コールバックと呼ばれることもあります。
2つの数値に対して計算を行う関数を考えてみましょう。操作をハードコーディングする代わりに、実行する操作を定義する関数ポインタを受け取ることができます。
typedef int (*Operation)(int, int);
int compute(int a, int b, Operation op) {
return op(a, b);
}compute関数は、自身が加算を行っているのか、減算を行っているのか、あるいは全く別のことを行っているのかを知りません。単に、渡された関数を呼び出すだけです:
int add(int a, int b) { return a + b; }
int multiply(int a, int b) { return a * b; }
int main() {
printf("%d\n", compute(5, 3, add)); // 出力: 8
printf("%d\n", compute(5, 3, multiply)); // 出力: 15
return 0;
}同じ compute 関数が、渡す関数によって異なる結果を生成することに注目してください。このパターンは、柔軟で再利用可能なコードを書くための基本です。構造を一度記述すれば、その関数の利用者が自分たちの必要とする具体的なロジックを提供できるようになります。
チャレンジ
簡単2つの整数と演算コードを受け取り、その演算を数値に対して2回連続で適用し、最終的な結果を返す関数 apply_twice を作成してください。
関数は、使用する演算を決定する演算コードを受け取ります。ソリューション内で演算関数を定義し、それらを関数ポインタを受け取るヘルパー関数 compute に渡す必要があります。
必要な構造:
- 2つの
int型パラメータを受け取りintを返す関数ポインタのtypedef名をOperationとして定義してください。 - 2つの演算関数を定義してください:
add(a + b を返す) とmultiply(a * b を返す) - 2つの整数と
Operation関数ポインタを受け取り、その演算を呼び出した結果を返すcompute関数を定義してください。 apply_twice内で、コードに基づいて適切な演算を選択し、computeを2回使用します。1回目は元の数値で、2回目はその結果と2番目の数値を使用して計算します。
ロジック:
op_codeに基づいて演算関数を選択します (1 = add, 2 = multiply)compute(a, b, operation)を呼び出して中間結果を取得しますcompute(intermediate, b, operation)を呼び出して最終結果を取得します- 最終結果を返します
パラメータ:
a(int): 1番目の数値b(int): 2番目の数値op_code(int): 演算コード (1 は add、2 は multiply)
戻り値: 演算を2回連続で適用した後の結果 (int)
例: a = 5, b = 3, op_code = 1 (add) の場合:
- 1回目の計算: 5 + 3 = 8
- 2回目の計算: 8 + 3 = 11
- 戻り値: 11
a = 2, b = 4, op_code = 2 (multiply) の場合:
- 1回目の計算: 2 × 4 = 8
- 2回目の計算: 8 × 4 = 32
- 戻り値: 32
チートシート
関数ポインタは他の関数に引数として渡すことができ、これによってコールバックが可能になります。これは、関数のコードを修正することなく、カスタムな振る舞いを注入するための手法です。
typedefを使用して関数ポインタ型を定義します:
typedef int (*Operation)(int, int);関数ポインタをパラメータとして受け取る関数を作成します:
int compute(int a, int b, Operation op) {
return op(a, b);
}異なる関数を渡すことで、異なる振る舞いを実現します:
int add(int a, int b) { return a + b; }
int multiply(int a, int b) { return a * b; }
int main() {
printf("%d\n", compute(5, 3, add)); // 出力: 8
printf("%d\n", compute(5, 3, multiply)); // 出力: 15
return 0;
}このパターンにより、構造を一度定義すれば、ユーザーが必要な特定のロジックを提供するだけで済む、柔軟で再利用可能なコードを書くことができます。
自分で試してみよう
int apply_twice(int a, int b, int op_code) {
// ここにコードを書いてください
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。