不透明なポインタの概念
CoddyのCジャーニー「Object Oriented Programming」セクションの一部 — レッスン 17/61。
これまでは、ヘッダーファイルで構造体(struct)を定義すると、そのヘッダーをインクルードした誰もが、そのすべてのメンバを表示し、直接アクセスできてしまいます。これは、内部の詳細を外部のコードから隠蔽するという原則である「カプセル化」を損なうことになります。
Cは、これを解決するために不透明なポインタ(opaque pointers)と呼ばれる強力な手法を提供しています。考え方は単純です。ヘッダー内で struct が存在することを宣言しますが、その中身は明かしません。これは不完全型(incomplete type)を使用して行われます:
// wallet.h
typedef struct Wallet Wallet; // 宣言のみ - 実体なし!
Wallet *create_wallet(int initial_balance);
void free_wallet(Wallet *w);
波括弧がないことに注意してください。Wallet に何が含まれているかは定義していません。コンパイラはその型が存在することは知っていますが、そのサイズやメンバについては知りません。つまり、このヘッダーをインクルードするコードは Wallet へのポインタしか扱うことができず、構造体自体を直接扱うことはできません。
なぜこれが重要なのでしょうか?実際の構造体の定義は .c ファイル内に隠されているため、あなたのヘッダーを使用するコードは w->balance や sizeof(Wallet) と書くことができません。それらは提供された関数を使用する必要があります。あなたがデータへのすべてのアクセスを制御し、ヘッダーに依存するコードを壊すことなく、後で内部構造を変更することができます。
次のレッスンでは、ソースファイル内で実際の struct の本体を定義し、不透明なポインタ(opaque pointer)パターンを完成させる練習をします。
チートシート
不透明なポインタは、不完全型を使用して構造体の実装の詳細を隠蔽し、カプセル化を強制します。
構造体の本体を定義せずに、ヘッダーで構造体を宣言します。
// wallet.h
typedef struct Wallet Wallet; // 宣言のみ - 波括弧なし
Wallet *create_wallet(int initial_balance);
void free_wallet(Wallet *w);
コンパイラはその型が存在することは認識しますが、そのサイズやメンバは認識しません。ユーザーは構造体へのポインタのみを扱うことができ、構造体とやり取りするには提供された関数を使用する必要があります。
実際の構造体の定義は .c ファイルに配置されるため、w->balance のような直接的なメンバアクセスや sizeof(Wallet) の使用を防ぐことができます。
自分で試してみよう
このレッスンにはコードチャレンジは含まれていません。
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。