More Effective C++ 項目5 ユーザ定義の変換関数に気をつけよう
新訂版 More Effective C++ (AddisonーWesley professional co)
- 作者: スコット・メイヤーズ,安村通晃,伊賀聡一郎,飯田朱美,永田周一
- 出版社/メーカー: ピアソンエデュケーション
- 発売日: 2007/06/29
- メディア: 単行本(ソフトカバー)
- 購入: 8人 クリック: 129回
- この商品を含むブログ (43件) を見る
項目5 ユーザ定義の変換関数に気をつけよう
C++はCと同様、コンパイラがcharからintなど暗黙の型変換を行う。
コンパイラに暗黙の型変換を行わせるような関数が2種類ある。
単一の実引数のコンストラクタ
単一の引数を持つか、複数の引数で2番目以降がデフォルト引数を持つものとして宣言する。
以下の例ではstringからNameに変換可能になる。
class Name { public: Name(const string& s); ... };
暗黙の型変換演算子
class Rational { public: Rational(int numerator = 0, int denominator = 1); ... operator double() const; // Rationalをdoubleに変換する };
このようにすると、doubleに変換できる。
Rational r(1, 2); double d = 0.2 * r; // doubleに変換される
だが、予想外のところでも変換関数が使われるようになる。
cout << r; // double()が使われる。
explicitを使うと暗黙の型変換ができなくなる。
template<class T> class Array { public: ... explicit Array(int size); ... }; Array<int> a(10); // intなのでOK Array<int> b(10); if (a == b[i]) ... // b[i]を使ってArray<int>を作り、aとの比較をしようとするが、 // explicitなので暗黙にintからArray<int>に変換できない。
内部にクラスを作った場合
template<class T> class Array { public: class ArraySize { public: ArraySize(int numElements) : theSize(numElements) {} int size() const { return theSize; } private: int theSize; }; Array(int lowBound, int highBound); Array(ArraySize size); ... };
このとき
Array<int> a(10);
と書くと、コンパイラはintを引数にとるArray
コンパイラはArraySizeがintから作れることを知っているので、テンポラリのArraySizeオブジェクトを作り、Array
そうすると次のように比較だけはエラーにできる。
Array<int> a(10); Array<int> b(10); if (a == b[i]) ... // aと比較するため右辺にArray<int>オブジェクトが必要だが // intからArraySizeを作り、それからArray<int>を作るのは // 二つの変換関数を呼ぶ必要があるが、エラーになる
ArraySizeクラスはプロキシクラスと呼ばれることが多い。
まとめ
コンパイラの暗黙の型変換は通常は利点より災難をもたらすので、変換関数は用意しないほうがよい。