カテゴリー別アーカイブ: Coding Tech

Pimplイディオム

オブジェクト指向の重要な概念のひとつに「カプセル化」というものがあります。

隠蔽化とも呼ばれ、ある機能を使いたい時に、ユーザーが実装詳細を意識しなくても動作し、ある日、実装の内容がドラスティックに変更されても、ユーザーは特に何もしなくても昨日までと同じようにその機能を使い続けられるということを期待するものです。

適切なカプセル化の思想の元に設計されたコードは変更に対して柔軟です。

あなたが学生時代に書いた、擬似乱数を生成するオブジェクトMyRandは昨日まで線形合同法で実装されていました。しかし、今日、急に思い立って擬似乱数の生成方法をxorshiftに変更したとしても、MyRandオブジェクトを使う側はその変更によって呼び出しコードを修正する必要はありません。

※この話はカルドセプトサーガおよび株式会社ロケットスタジオとは一切関係ありません。(http://www26.atwiki.jp/gcmatome/pages/2574.html

 

クラスの実装を呼び出し側から完全に分離し、隠蔽する手法にPimplイディオムというものがあります。

通常、クラス設計では公開するヘッダーファイルの定義の中にpublicからprivateまでの定義をひととおり書きます。

このクラスにメンバを足したり減らしたり、またはコメントを追加したり、何かしら変更を加えると、このクラスを使う(=ヘッダーファイルをインクルードしている)箇所全てが再コンパイルの対象になります。ライブラリの深いところのクラスをちょっと書き換えただけなのにフルビルドコースという話は決して珍しくありません。

また、ユーザーはクラスの公開されている部分にしか基本的にはアクセスできませんが、非公開関数のインターフェースとメンバ変数の詳細は見えています。

ああ、パスワードは最大16文字なんだな、とかCRC使ってるんだなとかの情報が読み取れてしまいますね。本例は多少作為的ですが、それでも外部に提供するクラスライブラリ等、なるべく情報を出したくないケースもあります。

データサイズとデータのレイアウトが想像できると、通信パケットやメモリダンプから情報を抜きやすくなってしまいますからね。これはもう圧倒的に抜かれます。

「公開されている部分にしか基本的にはアクセスできません」と書きましたが、基本的じゃない場合、その気になればメンバ変数pass_にも一瞬でアクセスできます。
アクセス指定子の無効化

クラス編集による再ビルドの影響範囲をなるべく抑えたい時やプライベートメンバをユーザーが見れる状況が好ましくない場合、Pimplイディオムを使ってクラスの実装を呼び出し側から完全に分離しましょう。

Pimplイディオム実装方法

ヘッダーファイル側の定義ではprivateメンバを書くのではなく内部実装の為のクラスのポインタのみ持ちます。

そして.cpp側でImplの詳細を定義することで実装を完全にヘッダーファイルから分離できます。

impl_経由で処理を呼び出します。

ちなみにPimplはピーインプルと読まれることが多く、Pointer To ImplementationやPrivate Implementationの意味で使われます。

Pimplイディオムは実装の詳細が分離できてコンパイル時間の減少にも貢献できる代償として、処理を呼び出す際にipml_を経由する過程で間接参照が必ず一回入るので、その分のオーバーヘッドのコストが発生する点だけ認識しておいてください。あと実際問題として、クラスの実装が委譲だらけになるので書くのが手間です。

まとめ

  1. Pimplイディオムを使うとクラスの定義と実装を完全に分離できる
  2. Pimplイディオムはコンパイル時間の抑制になる
  3. Pimplイディオムには間接参照のオーバーヘッドが発生する

アクセス指定子の無効化

世の中には知っていても「ほとんど悪にしかならない」知識があります。

例えば、簡易爆弾の作り方や、内鍵を糸だけで開ける方法などです。

さて、ここに誰かが定義したクラスがあります。

このクラスを使う側はpublic_func()しか呼べません。当たり前です。

private_func()にアクセスするにはどうすればいいでしょうか。

色々考えられます。

このクラスの設計者の家に押しかけてアクセスレベルの変更を迫るのも有力な手段です。また、我々はプログラマなので、お気に入りのエディタ(例えばEmacs)でおもむろにsomeone_defined.hppを開き、内容を勝手に書き換えてしまうのも悪くありません。

もっと(C++使い的に)スマートな方法もあります。

someone_defined.hppの内容を一切書き換えることなく、SomeoneDefinedクラスの内容に好きなだけアクセスする方法。

こちらを御覧ください。

はい、一丁上がりです。

someone_defined.hppは自分が何をされたのか気づいてすらいません。

この手法を悪ではなく正義の為に活かしましょう。(そんなものはない)

この悪魔のような手法からアナタの大切なクラスを守る方法はPimplイディオムを使って、完全に内部実装を隠蔽することです。

あと、悪魔には悪魔払いを!というわけで、こういう魔のモノを拒絶する方法もあります。

怪しいマクロを定義しているヤツにはインクルードさせてやらねーよ!ということですね。

ただし開発業務は進まなくなります。

 

まとめ

  1. アクセスレベルは簡単に書き換えられる
  2. この知識との上手な付き合い方は単に使わないこと
  3. 防衛策はPimplイディオム

おまけ

このprivateを再定義するアプローチは厳密にはc++のルールに違反している(c++のキーワードを再定義している)ので、本来何がおこっても不思議ではありません。たまたま無効化できているといったところです。

ちなみにある条件の下では、c++のルールに違反せずprivateメンバにアクセスする方法もあります。

参照:privateメンバへ合法的にアクセス