Menu
Coddy logo textTech

プロジェクトの概要

CoddyのCジャーニー「Object Oriented Programming」セクションの一部 — レッスン 44/61。

challenge icon

チャレンジ

簡単

関数ポインタを通じて、あらゆる図形ができることを定義するインターフェースである、ベースの Shape 構造体を作成し、Shape Drawerプロジェクトの基礎を築きましょう。

このポリモーフィックなシステムを構築するために、2つのファイルを作成します:

  • shape.h: ここでコアとなるインターフェースを定義します。まず、Shape 構造体の前方宣言を作成します。次に、2つの関数ポインタ型を定義します:
    • DrawFuncconst Shape* パラメータを受け取り、何も返しません
    • AreaFuncconst Shape* パラメータを受け取り、double を返します
    最後に、2つの関数ポインタ drawDrawFunc 型)と areaAreaFunc 型)を含む Shape 構造体自体を定義します。この構造体は純粋にインターフェースとして機能します。図形固有のデータは保持せず、振る舞いのみを保持します。
  • main.c: シンプルなテスト用の図形を作成して、インターフェースが機能することを実証します。2つの関数を実装してください:
    • test_drawDrawing test shape と出力します
    • test_area42.0 を返します
    Shape インスタンスを作成し、これらのテスト関数に紐付け、インターフェースを介して両方を呼び出します。面積の結果を小数点以下1桁で出力してください。

出力は、関数ポインタが正しく機能していることを示す必要があります:

Drawing test shape
Area: 42.0

なぜ前方宣言が必要なのですか? 構造体が完全に定義されるtypedef struct Shape Shape; が現れるのはなぜか不思議に思うかもしれません。これは、DrawFuncAreaFunc がパラメータ型で const Shape* を参照しているため必要です。しかし、ファイルのその時点では、コンパイラはまだ完全な構造体定義を見ていません。前方宣言はコンパイラに「Shape という名前の構造体が存在する」ことを伝えます。これだけで、その構造体へのポインタを使用するには十分です。完全な定義は後で続きます。このパターンは、構造体が(直接、または関数ポインタを介して)自分自身を参照する必要がある場合に、C言語でよく使われます。

ここでの重要な洞察は、Shape は円や長方形については何も知らないということです。ただ、どんな図形も自分自身を draw(描画)でき、area(面積)を計算できなければならないということだけを知っています。今後のレッスンでは、このベース構造体を埋め込み、独自の実装を提供する具体的な図形を作成します。ヘッダーファイルにはインクルードガードを使用することを忘れないでください。

自分で試してみよう

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

// TODO: test_draw 関数を実装する
// - const Shape* 型の引数を取る
// - "Drawing test shape" と出力する
void test_draw(const Shape* shape) {
    // TODO: 必要なメッセージを出力する
}

// TODO: test_area 関数を実装する
// - const Shape* 型の引数を取る
// - 42.0 を返す
double test_area(const Shape* shape) {
    // TODO: テスト用の面積の値を返す
}

int main() {
    // TODO: Shape インスタンスを作成する
    
    // TODO: shape を test_draw 関数と test_area 関数に紐付ける
    
    // TODO: インターフェース経由で draw を呼び出す
    
    // TODO: インターフェース経由で area を呼び出し、小数点第1位まで表示する
    // フォーマット: "Area: %.1f\n"
    
    return 0;
}

Object Oriented Programmingのすべてのレッスン