1 看不见的隐式类型转换
当构造函数只有一个,编译器会利用构造函数进行隐式类型转换。如下面所示:
class UInt {
public:
UInt();
UInt(int value);
}
UInt a = 0, b(0), c = 1; // 隐式转换:int变成UInt类型
UInt d = 1 + a; // 隐式类型转换
这种隐式类型转换十分危险,当有多种类似"UInt(int value)"函数被声明时,比如“UInt(SomeType value)”,就会造成比较严重的逻辑错误——误调用隐式类型转换。
为了消除这种危险,可以采用以下两种方法。但是,不推荐使用大量重载函数,会使软件更难维护。
方法1:使用explicit关键字
explicit关键字需要用户明确指出类型转换。
class UInt {
public:
Unit();
explicit UInt(int a);
}
UInt a = 1 + b; //错误,没有明确指出1的类型。
UInt a = UInt(1) + b; //正确,明确指出类型。
方法2:利用函数重载
如下,重载函数通过不同函数签名来识别。较低版本中,函数签名只依据传入参数的不同来识别。
const UInt operator+(int lhs, const UInt& rhs);
const UInt operator+(const UInt& lhs, int rhs);
const UInt operator+(const UInt& lhs, const UInt& rhs);
// 以上都正确,下面错误
const UInt operator+(int lhs, int rhs); // 重载的和库中的签名一致,错误。
2 复合操作符与其单独形式
C++允许我们重载+, -, *, /四种操作符,他们对应的复合操作符为:+=, -=, *=, /=。这8个操作符允许用户进行重载。由于单独操作符会涉及如下两个步骤,复合操作符只涉及第1步,因此具体运算可以直接使用复合操作符。
1,运算
2,获得运算结果,并存储在临时变量中,返回临时变量。
具体代码如下:
class MyClass {
public:
MyClass& operator += (const MyClass& rhs)
{
// do something
return *this;
}
}
const MyClass operator + (const MyClass& lhs, const MyClass& rhs)
{
return MyClass(lhs) += rhs;
}
// 进一步,可以使用template来实现
template<class T>
const T operator +(const T& lhs, const T& rhs)
{
return T(lhs) += rhs;
}