0Pricing
C++ Academy · レッスン

PIMPLによる実装の隠蔽

ポインター・トゥ・インプリメンテーションイディオムで実装の詳細を隠します。

「PIMPLによる実装の隠蔽」はCoddyKit上の無料C++ Academyレッスンです。 これはレッスン3/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはC++ Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 C++ Academyコースには全4レッスンが含まれています。

PIMPLイディオム

PIMPLは「Pointer to IMPLementation」の略です。クラスのprivateデータを別のimpl構造体に移し、ポインター経由でアクセスします。

PIMPLを使う理由

利点:

  • 実装の詳細をヘッダーから隠せる
  • コンパイル時の依存関係を減らせる
  • privateメンバーを追加してもABIの安定性を維持できる
  • 実装を差し替えられる

基本構造

公開クラスは、.cppファイル内だけで定義されたImpl構造体へのポインターを保持します。

// widget.h
class Widget {
public:
    Widget();
    ~Widget();
    void doSomething();
private:
    struct Impl;
    std::unique_ptr<Impl> pimpl_;
};

cpp内のImpl

Impl構造体が実際のデータをすべて保持します。

// widget.cpp
struct Widget::Impl {
    std::string name;
    int counter;
    // ... anything else, freely
};

Widget::Widget()
    : pimpl_(std::make_unique<Impl>()) {}

Widget::~Widget() = default;  // must be in .cpp where Impl is complete

void Widget::doSomething() {
    pimpl_->counter++;
}

cpp内のデストラクター

デストラクターは、Implが完全型になる.cpp内で定義する必要があります。そうしないと、unique_ptrで不完全型を削除できません。

特殊メンバー関数

必要に応じて、コピー、ムーブ、代入も明示的に宣言する必要があります。ヘッダー内で不完全型を扱う場合、コンパイラーが生成するバージョンは機能しません。

// widget.h
class Widget {
public:
    Widget(const Widget& other);
    Widget& operator=(const Widget& other);
    Widget(Widget&&) noexcept;
    Widget& operator=(Widget&&) noexcept;
    ~Widget();
};

パフォーマンスコスト

PIMPLでは、メンバーアクセスのたびに間接参照が発生し、ヒープ割り当ても必要になります。頻繁に呼び出すメソッドでは影響する可能性があるため、必ず測定してください。

ビルドの高速化

これまでstdの型や高コストな依存関係をインクルードしていたヘッダーを、軽量にできます。.cppを変更しても、利用側を再コンパイルする必要はありません。

継承とPIMPL

継承と組み合わせることもできますが、複雑さが増します。通常、公開クラスは何も継承せず、Impl側では自由に継承を使用できます。

バリエーション

代替手段と発展形:

  • Fast PIMPL — placement newを使ったインラインストレージ
  • Stable address — オブジェクトのライフタイム中、Implを割り当てたままにする
  • Type erasure — Implをポリモーフィックにできる

実際の利用例

PIMPLは、次のようなソフトウェアで広く使用されています。

  • Qt(すべてのウィジェットがPIMPL)
  • 多くのプロプライエタリライブラリ
  • Boost(一部)

使う場面

次のような場合はPIMPLを使用してください。

  • バージョン間でABIの安定性を保ちたい
  • ヘッダーが推移的に多くのものをインクルードしている
  • 公開ライブラリAPIを提供する

避ける場面

次のような場合はPIMPLを避けてください。

  • クラスが内部用で、ヘッダーに依存する利用者がいない
  • ビルド時間よりパフォーマンスのオーバーヘッドのほうが重要
  • クラスが小規模、または変更頻度が低い

確認問題

PIMPLクラスのデストラクターを.cppファイル内で定義しなければならないのはなぜですか。

まとめ

PIMPLは、privateデータをunique_ptr経由でアクセスするImpl構造体に移すことで、実装を隠します。間接参照のコストと引き換えに、ABIの安定性とビルド時間を改善できます。特殊メンバー関数は、Implが完全型になる.cpp内で定義してください。

よくある質問

「PIMPLによる実装の隠蔽」レッスンは無料ですか?

はい。「PIMPLによる実装の隠蔽」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、C++ Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 C++ Academyコースには全4レッスンが含まれています。

「PIMPLによる実装の隠蔽」で何を学びますか?

ポインター・トゥ・インプリメンテーションイディオムで実装の詳細を隠します。 ブラウザで直接実行するハンズオンコードでC++ Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

C++ Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのC++ Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン3/4です。

「PIMPLによる実装の隠蔽」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このC++ Academyレッスンでコードを書いて実行できますか?

はい。すべてのC++ Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. ヘッダーオンリーライブラリとコンパイル済みライブラリ
  2. APIのバージョニングとABI安定性
  3. PIMPLによる実装の隠蔽
  4. 現代的なヘッダーオンリー・ユーティリティライブラリを書く
← C++ Academyに戻る