ITEM5:谨慎定义类型转换函数
两种函数允许编译器进行类型转换:单参数构造函数(single-argumentconstructors)和隐式类型转换运算符。
1. 单参数构造函数
构造函数只有一个参数,或者多个参数,但第一个参数以后的所有参数都有缺省值。
class Name{ // for names of things
public:
Name(const string& s); // 转换string 到Name
...
};
2. 隐式类型转换运算符
operator关键字后跟一个类型符号,不用定义函数返回类型,因为返回类型就是这个函数的名字。
classRational {
public:
...
operator double() const; // 转换Rational类成double 类型
};
在下面这种情况下,这个函数会被自动调用:
Rational r(1,2); // r 的值是1/2
double d = 0.5 * r; // 转换 r 到double,然后做乘法
问题:当你在不需要使用转换函数时,这些的函数缺却会被调用运行。
解决方法:
①是用不使用语法关键字的等同的函数来替代转换运算符。
classRational {
public:
...
double asDouble() const; //转变 Rational成double
};
这个成员函数能被显式调用:
Rationalr(1, 2);
cout<< r; // 错误! Rationa 对象没有operator<<
cout << r.asDouble(); // 正确, 用double类型打印r
②构造函数用explicit声明,如果这样做,编译器会拒绝为了隐式类型转换而调用构造函数。显式类型转换依然合法。
template<classT>
classArray {
public:
explicit Array(int size); // 注意使用"explicit"
};
Array<int>a(10); // 正确, explicit 构造函数在建立对象时能正常使用
Array<int>b(10); // 也正确
if(a == b[i]) ... // 错误! 没有办法隐式转换int 到 Array<int>
if(a == Array<int>(b[i])) //正确,显式从int到Array<int>转换(但是代码的逻辑不合理)
if(a == static_cast< Array<int> >(b[i])) // 同样正确,同样不合理
if (a == (Array<int>)b[i])//C 风格的转换也正确,但是逻辑依旧不合理
③数组模板
ITEM6:自增(increment)、自减(decrement)操作符前缀形式与后缀形式的区别
重载increment和decrement操作符
classUPInt {
public:
UPInt& operator++(); //++ 前缀
const UPInt operator++(int); // ++ 后缀
UPInt& operator--(); //-- 前缀
const UPInt operator--(int); //-- 后缀
UPInt& operator+=(int); //+= 操作符,UPInts与ints 相运算
};
UPInti;
++i; // 调用 i.operator++();
i++; // 调用 i.operator++(0);
--i; // 调用 i.operator--();
i--; // 调用 i.operator--(0);
① 前缀形式返回一个引用,后缀形式返回一个const类型
② 当处理用户定义的类型时,尽可能地使用前缀increment,因为它的效率较高。
(待续……)