05. 对定制的"类型转换函数"保持警觉

C++允许编译器在不同类型之间执行隐式类型转换(implicit conversions)。

两种函数允许编译器执行这样的转换:

  • 单自变量constructors
  • 隐式类型转换操作符
单自变量constructors

单自变量constructors是指能够以单一自变量成功调用的constructors。如此的constructor可能拥有单一参数,也可能声明拥有多个参数,并且除了第一个参数之外都有默认值。下面给出其这两种形式:

class Name
{
public:
	Name(const string& s);  // 可以把string转换成Name
};

class Rational
{
public:
	Rational(int numerator = 0, int denominator = 1); // 可以把int转换成Rational
}

对于如下调用:

void TestFunc(Name myName)
{
	...
}

string strName;
TestFunc(strName); // 调用成功,编译器调用了单参数的构造函数

编译不会报错,如果需要禁止这种行为,可以在单参数构造函数前加上关键字explicit即可。

class Name
{
public:
	explicit Name(const std::string& s); // 禁止调用进行隐式类型转换
};
隐式类型转换操作符

隐式类型转换操作符是关键字operator之后加上一个类型名称。不需要指定返回值类型,因为其返回值类型基本上已经表现在函数名称上。

class Rational
{
public:
	...
	operator double() const; // 将Rational转换为dobule
}

这个函数会在下面代码中自动调用:

Rational r(1, 2);
double d = 0.5 * r; // 将r转换成double, 然后执行乘法运算

接下来解释为什么最好不要提任何类型转换函数。根本原因在于,在你从未打算也未于其的情况下,此类函数可能会被调用,而其结果可能是不正确的、不直观的程序行为,很难调试。

例如,对于如下调用:

Rational r(1, 2);
cout << r; 

因为没有对Rational实现operator << , 所以预期会编译报错,但是结果确实正常运行,因为r会被编译器进行隐式类型转换成double类型。这也显示:隐式类型转换,它们的出现可能导致错误(非预期)的函数被调用。

解决的办法是以功能对等的另外一个函数取代类型转化操作符。
例如为了允许将Rational转换为double,可以以一个名为asDouble的函数取代operator double。

class Rational
{
public:
	...
	double asDouble() const; // 将Rational转换为double
};

此后member function必须被明确调用:

Rational r(1, 2);
cout << r; // 错误,Rational没有operator <<。
cout << r.asDouble(); // 可以以double形式输出

大部分时候,"必须明白调用类型转换函数"虽然带来了些许不便,却可以为"不再默默调用那些其实并不打算调用的函数"而获得弥补。这也是为什么不存在从string object至C-style char*的隐式转换函数的原因。而是提供了一个显示的member function c_str()来执行上述转换行为。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值