14.9 重载类型转换运算符
类型转换运算符是特殊的成员函数,它负责将一个类类型的值转换成其他类型
一般形式为:
operator type() const;
定义一个比较简单的类,令其表示0到255之间的一个整数
class SmallInt {
public:
SmallInt(int i=0) : val(i) {
if (i < 0 || i > 255)
throw std::out_of_range("Bad SmallInt value");
}
operator int() const { return val; }
private:
std::size_t val;
};
SmallInt si;
si = 4; // 首先将4隐式地转换成SmallInt,然后调用SmallInt::operator=
si + 3; // 首先将si隐式地转换成int,然后执行整数的加法
/* 可以进行多次转换 */
// 内置类型转换将double实参转换成int
SmallInt si = 3.14; // 调用SmallInt(int)构造函数
// SmallInt类型转换运算符将si转换成int
si + 3.14; // 内置类型转换将所得的int继续转换成double
类型转换运算符是隐式执行的,不能传递实参
class SmallInt {
public:
int operator int() const; // error,不能指定返回类型
operator int(int=0) const; // error,不能有参数
operator int*() const { return 42; } // error,42不是指针
};
类型转换运算符可能产生意外结果
// 当stream含有向bool的类型转换时
int i = 42;
cin << i; // cin转为bool值左移42位
为了防止上面的异常,C++11引入了显示的类型转换运算符
class SmallInt {
public:
// 编译器不会自动执行这一类型转换
explicit operator int() const { return val; }
};
SmallInt si = 3; // 正确,SmallInt的构造函数不是显式的
si + 3; // error,此处需要隐式的类型转换,但运算符是显式的
static_cast<int>(si) + 3; // 正确,显式地请求类型转换
如果表达式被用作条件,编译器会隐式地执行需要显式的类型转换
if
、while
及do
语句的条件部分for
语句头的条件表达式!
、||
、&&
的运算对象?:
的条件表达式
避免有二义性的类型转换
// 最好不要在两个类之间构建相同的类型转换
struct B;
struct A {
A() = default;
A(const B&); // 把B转换成A
};
struct B {
operator A() const; // 也是把B转换成A
};
A f(const A&); // f函数需要一个A对象
B b;
A a = f(b); //二义性错误,含义是f(B::operator A()),还是f(A::A(const B&))?
A a1 = f(b.operatorA()); // 正确
A a2 = f(A(b)); // 正确
函数匹配与重载运算符
class SmallInt {
friend SmallInt operator+(const SmallInt&, const SmallInt&);
public:
SmallInt(int = 0); // 转换源为int的类型转换
operator int() const { return val; } // 转换目标为int的类型转换
private:
std::size_t val;
};
SmallInt s1, s2;
SmallInt s3 = s1 + s2; // 使用重载的operator+
int i = s3 + 0; // 二义性错误,int可以转为SmallInt,SmallInt也可以转为int