Home > C++ Archive
C++ Archive
法則に違反したっていいじゃない
オブジェクト指向プログラミングにおける有名な法則の一つにデメテルの法則 (Law of Demeter, LoD) というものがある。これは、簡単に言えば「戻り値として返されたオブジェクトのメソッドを呼び出してはいけない」という法則であり、例えば次のようなコードを書くと、「それ、デメテルの法則に違反しているよ」などと言われたりするので注意が必要だ。
int id = projects.Find(projectName).GetID(); // プロジェクト名から ID を取得
そして、このコードをデメテルの法則に違反しないように書き換えると、次のようになる。
int id = projects.GetID(projectName); // プロジェクト名から ID を取得
変更後のコードは Find が返すオブジェクト(ここでは多分 Project みたいなクラス)に依存していないので、オブジェクト間の結合度が下がったことになる。結合度の低いプログラムは良いプログラムであり、デメテルの法則に従えば良いプログラムになるというわけだ。
でも、ちょっと待って欲しい。
- Comments: 0
- TrackBack (Close): 0
Pimpl イディオムのお手軽な実装
- 2009年4月15日 22:21
- C++
Pimpl イディオム(Handle-Body, Compilation or Compiler Firewall, Cheshire Cat とも呼ばれたりする)は実装の詳細を隠蔽したい時に用いられる手法だが、内部が委譲の嵐になったり、ポインタの扱いに注意を払う必要があったりと、気軽には使い難いパターンの一つではある。内部の委譲に関しては Pimpl の性質上仕方がないものとして諦められるが、せめてポインタ周りだけでもお手軽に扱えるようにならないだろうか、というのが今回のお題だ。
教科書に載っているような Pimpl の実装は、大抵の場合、次の例の前半部分まで。こうやって隠蔽した Impl のポインタ pImpl_ を正しく扱うためには、コンストラクタ、デストラクタ、コピーコンストラクタ、代入演算子を「正しく」実装しなければならない。
class PimplTest {
public:
// ... 外部に公開するインタフェース
private:
class Impl; // 実装の詳細は Impl に隠蔽し、
Impl* pImpl_; // そのポインタを保持する
// Impl を正しく扱うためには、以下のコードを「正しく」書かなければならない
public:
PimplTest(); // ここで new
~PimplTest(); // ここで delete
PimplTest(const PimplTest& obj); // Impl に対する深いコピーが必要
PimplTest& operator = (const PimplTest& rhs); // こちらも同様に深いコピー
};
時々、ポインタ周りを楽にするために shared_ptr を使って Pimpl イディオムを実装している例を見かけるが、これではコピーや代入時に実装の詳細が共有されてしまう。コピーや代入を禁止しても構わない場合ならこれで充分かも知れないが、そうでない場合は自前のコピーコンストラクタや代入演算子を用意する必要があるため、やはり、お手軽とは言い難いだろう。
- Comments: 0
- TrackBack (Close): 0
C++でメンバ関数テンプレートを仮想関数にできないのは何故?
- 2009年3月19日 21:44
- C++
C++ でメンバ関数テンプレートを仮想関数にしようとして、コンパイラに怒られた経験がある人は多いと思う。
class Hoge {
public:
template <typename T>
virtual void Func(const T& in) {} // メンバ関数テンプレートは仮想関数にできない
};
こういう場合、クラスを丸ごとテンプレート化してしまえば何とかなる場合が多いので、どうしてもという時は設計を見直すことになるだろう。こうすれば仮想関数でテンプレート引数の型が使えるようになる。
template <typename T> // テンプレートクラスにすれば、仮想関数で T が使える
class Hoge {
public:
virtual void Func(const T& in) {}
};
- Comments: 1
- TrackBack (Close): 0
Home > C++ Archive