条款5:小心用户自定义的转换函数
c++允许编译器在两种数据类型之间进行隐式类型转换。(implicit conversion).首先,c++继承了c语言的类型转换的策略。
除了这个,c++还有两种隐式转换: 单个参数的构造函数,以及隐式的类型转换运算符。单个参数的构造函数是指只传递给它
一个参数就可以调用的构造函数,这种构造函数可能只定义一个参数,也可以定义多个参数,定义多个参数的时候要求第一个
参数后面的所有参数都有一个默认值。下面是两个例子:
class name {
public:
Name(const string& s);
....
};
class Rational {
public:
Rational(int number = 0, int denominator);
....
};
隐式的类型转换符一般是这样定义的:
class A
{
...
operator B()
{
...
return B;
}
};
这样就定义了A到B的转换操作符。
条款6: 区分自增运算符和自减运算符的前缀和后缀形式。
i++和++i的区别大家都很熟悉了。我们知道c++可以重载运算符,同样的,我们也可以为类定义自增和自减运算符。为了区别前缀自增和后缀自增,c++规定后缀自增形式有一个int类型参数,这个参数相当于一个占位符,没有实际的意义。
例子如下:
class UPNINT{
public:
UPNINT& operator++(); //前缀自增
const UPNINT operator++(int); // 后缀自增
UPNINT& operator--(); //前缀自减
const UPNINT operator--(int); //后缀自减
UPNINT& operator+=(const UPNINT& upi);
};
条款7:不要重载"&&", "||"和","
与c一样,c++也使用了短路求值法对布尔表达式求值。这表达式一旦确定了布尔表达式为真或为假,即使还有部分表达式没有被测试,布尔表达式也停止运算。例如:
char *p;
...
if ( ( p != 0 ) && ( strlen(p) > 10 ) ) 这里不用担心当p为空时对它调用strlen是否会有问题。因为如果p不等于0的测试失败。strlen永远不会被调用。c++允许对用户自定义的类型来定制&&和||运算符。方法是通过重载operator&&函数和operator||函数。这种重载可以是全局的也可以是针对某个类的。然而如果你决定要采用这种方法,你必须知道它会对游戏规则带来根本性的改变。因为你用函数调用的语义代替短路求值法。也就是说,如果你重载了&&运算符。下面这段代码if (expression1 && expression2) ...对于编译器来说,就类似于:
if(expression1.operator&&(expression2) )// when operator is a member function
if(expression1.operator&&(expression2) )// when operator is global function
这看上去没很大的不同。但是函数调用的语义和短路求值法在以下两个方面是绝对不同的。首先,当函数调用时,需要对所有参数求值。所以当调用函数operator&&和operator||时,两个参数都需要计算。换句话说,它没有采用短路求值法。其次,c++语言规范没有定义函数参数的求值顺序,所以没有办法知道expression1和expression2哪一个先被求值。而这与短路求值法是非常不用的。短路求值法总是以从左到右的顺序对参数进行求值。
因此,如果你重载&&和||,就没有办法向程序员提供他们所期望的并且已经习惯了的行为特性。所以不要重载&&和||.
同样的,逗号运算符也会有这种问题。一般情况下你需要也不会重载他们的,不是吗、?