Home > C++ Archive
C++ Archive
static_cast をいい加減な気持ちで適当に付けないと決めた日
- 2010年3月15日 21:30
- C++
最近、些細なことに気付く程度には余裕が出てきたのだろう。ふと自分のコードを見直してみると、static_cast を単なる「警告除け」や「コンパイルエラー除け」として、あやふやな理解のまま使っていることに気付いた。どうやら私は、static_cast をなんとなく「それ以外の cast」といったような感覚で使っているようだ。「それ」とはもちろん、標準で用意されている static_cast 以外の cast、dynamic_cast, const_cast, reinterpret_cast の3つのこと。これらの cast は役割が結構はっきりしているので、それぞれ、安全なダウンキャスト用、const 外し用、強制置き換え用として(もちろん必要に迫られて)迷うことなく使っている。ところが static_cast だけは、それ以外の状況で警告(あるいはコンパイルエラー)が出た時に仕方なく付けているというわけだ。そこに明確な理由も意思もない。単なるコンパイラのご機嫌取りだ。情けない。
このままでは、新人君に「先輩、ここの static_cast にはどのような効果があるのですか?」と聞かれても、「あ、それ? なんとなく、コンパイラが文句言ってたし」としか答えられないし、先輩に「ここで static_cast はないだろう」と言われても「あ、はい、そうですね。コンパイルエラー出ちゃったんでなんとなく付けちゃいました」となんとも間抜けな回答しかできないことになる。このままではマズイ。
前置きが長くなってしまったが、要は「static_cast について自分なりにまとめましたよ」という話だ。
- Comments: 0
- TrackBack (Close): 0
法則に違反したっていいじゃない
オブジェクト指向プログラミングにおける有名な法則の一つにデメテルの法則 (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