05項 ユーザ定義の変換関数に気をつける
ユーザ定義の変換関数に気をつける
単一の引数を持つクラス、あるいは、複数の引数を持ち2番目以降の引数にデフォルト値があるクラスは、暗黙の型変換による危険があります。
本書の例を引用します。
template<class T> class Array { public: Array(int size); T &operator[](int index); ... } bool operator=(const Array<int> &lhs, const Array<int> &rhs) Array<int> a(10); Array<int> b(10); ... for (int i = 0; i < 10; i++) { if(a == b[i]) //aとa[i]を間違えている { ... } }
この例はエラーを発生させずにコンパイルされます。
"a == b[i]"の部分は"a == Array"に、暗黙的な型変換がされているからです。
対策は、コンストラクタにexplicitを指定することです。explicitは、暗黙的な型変換を禁止します。
template<class T> class Array { public: explicit Array(int size); T &operator[](int index); ... }
コンパイラが古くexplicitに対応してない場合の対策が本書に掲載されていますが、省略します。
もうひとつ、キャスト演算子にも注意します。
class Rational { public: Rational(int numerator = 0, int denominator = 1); operator double() const; //キャスト演算子 ... }; ... Rational r(1, 2); cout << r; // 1/2と出力したいが、 // <<演算子をオーバロードしてない場合 // 0.5が出力される。
対策は、operator doubleをasDoubleのような名前の関数に置き換え、型変換の明示的な呼び出しを強制することです。
class Rational { public: Rational(int numerator = 0, int denominator = 1); double asDouble() const; ... };