Menu
Coddy logo textTech

インターフェースの概念

CoddyのCジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 40/61。

これまで、私たちの構造体では、たとえば名前と function pointer のように、データと振る舞いが一緒になっていました。しかし、構造体が function pointer だけを含んでいたらどうでしょうか? これによって、強力なものが作られます。それが interface です。

interface は、どのような操作を利用できるかを定義しますが、それらがどのように動作するかは指定しません。これは、「この interface を実装するすべてのオブジェクトは、これらの functions を提供しなければならない」と示す契約です。

typedef void (*LogFunc)(const char* message);

typedef struct {
    LogFunc log;
} ILogger;

ILogger 構造体には、function pointer 以外には何も含まれていません。独自のデータは持っていません。純粋に動作を記述します。「I」接頭辞は、これが interface であることを示す一般的な慣例です。

ILoggerを受け取るコードは、ログメッセージの送信先を気にしません。コンソールに出力したり、ファイルに書き込んだり、ネットワーク経由でデータを送信したりできます。呼び出し元は、logを呼び出せることだけを知っていればよいのです。

void process(ILogger* logger, const char* msg) {
    logger->log(msg);  // どのようにログを取るのかは分からない
}

この分離がポリモーフィズムの本質です。process関数は、どのようなロガー実装とも連携できます。関数のコードを変更せずに、動作を入れ替えられます。次のレッスンでは、このインターフェース契約を満たす具体的な実装を作成します。

challenge icon

チャレンジ

簡単

ICalculator interface を構築しましょう。これは function pointer のみを含む struct であり、各 calculator がサポートすべき操作を、それらの実装方法を指定せずに定義します。

コードを整理するために、2つのファイルを作成します。

  • calculator.h:ここで interface を Define します。2つの int parameters を受け取り、int を返す、BinaryOp という名前の function pointer 型を Create します。次に、2つの function pointer のみを含む ICalculator struct を Define します。1つは operate(型は BinaryOp)、もう1つは parameters を取らず何も返さない function pointer である describe です。この struct は純粋な interface です。データは保持せず、behavior のみを保持します。
  • main.c:header を include し、interface を満たすことができる具体的な functions を Implement します。
    • add:2つの integers の合計を返します
    • multiply:2つの integers の product を返します
    • describe_addAddition を表示します
    • describe_multiplyMultiplication を表示します
    次に ICalculator instance を Create し、input に基づいて接続して、計算を実行するために使用します。

プログラムは3つの input を受け取ります。2つの integers と、operation code(加算の場合は1、乗算の場合は2)です。

operation code に基づいて、ICalculator に appropriate な function の組み合わせを接続します。次に interface を通じて describe を Call して操作名を表示し、その後 operate を Call して計算結果を求め、result を表示します。

入力が 531 の場合の出力例:

Addition
8

入力が 472 の場合の出力例:

Multiplication
28

重要な insight は、ICalculator struct が contract を Define していることです。これを使用する code は、どの specific な functions が接続されているかを知らなくても、describeoperate を Call できることを know しています。header file では include guards を使用することを忘れないでください。

自分で試してみよう

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

// TODO: add関数を実装する
// 2つの整数の和を返す


// TODO: multiply関数を実装する
// 2つの整数の積を返す


// TODO: describe_add関数を実装する
// "Addition"を出力する


// TODO: describe_multiply関数を実装する
// Prints "Multiplication"


int main() {
    int num1, num2, op_code;
    scanf("%d", &num1);
    scanf("%d", &num2);
    scanf("%d", &op_code);
    
    // TODO: ICalculatorのインスタンスを作成する
    
    
    // TODO: op_codeに基づいて(1はadd、2はmultiply)、
    // 適切な関数でcalculatorを接続する
    
    
    // TODO: インターフェース経由でdescribeを呼び出す
    
    
    // TODO: インターフェース経由でoperateを呼び出し、結果を出力する
    
    
    return 0;
}
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

オブジェクト指向プログラミングのすべてのレッスン

自分で練習してみよう: Cオンラインコンパイラ