自定义类型转换函数

(本文参考自《More Effecitve C++》 Item5 谨慎定义类型转换函数)

自定义类型转换函数有2种: 1.隐式类型转换运算符; 2.单参数构造函数。
隐式类型转换运算符是一个成员函数:operator其后跟一个类型和符号;不用定义函数的返回类型,因为返回类型就是这个函数的名字。
单参数构造函数是指只用一个参数即可以调用的构造函数。该函数可以是只定义了一个参数,也可以是虽定义了多个参数但第一个参数以后的所有参数都有缺省值。
类型转换函数为程序提供了便利,但是如果控制不好,会调入陷阱;当你在不需要使用转换函数时,这些转换函数却会被调用运行;这些不正确的程序调用会做出一些意想不到的事情,而又很难判断出原因。

下面示例分析下类型转换函数的陷阱:


1. 隐式类型转换运算符
下面代码中cout<<r<<endl; 
本意输出Rational的r,由于Rational没有重载"<<",r将隐式调用 operator double()转换为double类型,违背了输出为Rational类型的本意。
解决办法为使用函数显示转换。
详见代码注释:

#include <iostream>
using namespace std;

class Rational 
{
public:
	Rational(int numerator = 0, int denominator = 1){} 
    //隐式类型转换运算符,转换为double
	operator double() const{}
	//函数显示转换为double
	double asDouble() const{}
}; 

int main()
{
	Rational r(1, 2); 
	// 转换 r 到double进行运算,这里是合理的
	double d = 0.5 * r;

    //本意输出Rational的r	
	//由于Rational没有重载"<<",r将隐式调用 operator double()转换为double类型,违背了输出为Rational类型的本意
	cout<<r<<endl; 
	
	//解决办法是使用函数代替隐式类型转换
	cout<<r.asDouble()<<endl;

}


2.单参数构造函数(类型转换)
代码中a == b[i]本意是a[i] == b[i], 写成了a == b[i],但是编译不会报错;
a == b[i]调用operator== a的类型是Array<int>, 但是b[i]的类型是int,
将int类型的实参b[i]赋值给Array<int>类型时,将通过调用Array<int>构造函数“转换int 类型到Array<int>类型”,
这是一个不容易察觉的(单参数构造函数)隐式类型转换错误。
后续为解决办法。

#include <iostream>
using namespace std;

template<class T>
class Array 
{
public:
	Array(int lowBound, int highBound){}
	Array(int size){}
	T& operator[](int index){}
};

bool operator==( const Array<int>& lhs, const Array<int>& rhs){}

Array<int> a(10);
Array<int> b(10);

int main()
{
  for (int i = 0; i < 10; ++i)
  {
    //本意是a[i] == b[i], 写成了a == b[i],但是编译不会报错
    //a == b[i]调用operator== a的类型是Array<int>, 但是b[i]的类型是int,
	//将int类型的实参b[i]赋值给Array<int>类型时,
    //将通过调用Array<int>构造函数“转换int 类型到Array<int>类型”
	//这是一个不容易察觉的(单参数构造函数)隐式类型转换。
	if (a == b[i])
	{
	}
  }
}

2.1 解决办法1, 构造函数加上explicit 
加上explicit之后,构造函数必须显示调用, a==b[i]会报错
详见代码注释吧:

#include <iostream>
using namespace std;

template<class T>
class Array 
{
public:
	Array(int lowBound, int highBound){}
	//加上explicit之后,构造函数必须显示调用, a==b[i]会报错
	explicit Array(int size){}
	T& operator[](int index){}
};

bool operator==( const Array<int>& lhs, const Array<int>& rhs) {}

Array<int> a(10);
Array<int> b(10);

int main()
{
  for (int i = 0; i < 10; ++i)
  {
    //加上explict之后a == b[i]的隐式类型转换是无法编译通过的
	//但是加上显示的a == static_cast<Array<int> >(b[i])是可以编译通过的,虽然依旧违反了a[i] == b[i]的本意
	//注意static_cast<Array<int> >(b[i])中2个"> >"之间必须有空格,不然会变成输入流">>"
	if (a == static_cast<Array<int> >(b[i]))
	{
	}
  }
}

2.2 解决办法2, 使用proxy classes
这个方法比explicit要复杂,但是是一种很好的思路。
重点是: 隐式类型转换一次是可以的,从从int 到ArraySize,再转一次(从ArraySize 到Array<int>)就不合理了。

详见代码注释:

#include <iostream>
using namespace std;

template<class T>
class Array 
{
public:
	class ArraySize 
	{
		public:
		ArraySize(int numElements): theSize(numElements) {}

		private:
		int theSize;
	};

	//译器无法把int 转换成一个临时ArraySize 对象然后通过这个临时对象建立必须的Array<int> 对象, 
	//因为这将调用两个用户定义(user-defined)的类型转换,一个从int 到ArraySize,一个从ArraySize 到Array<int>。
	//这种转换顺序被禁止的,所以当试图进行比较时编译器肯定会产生错误。
	Array(ArraySize size) {}

	T& operator[](int index){}
};

bool operator==( const Array<int>& lhs, const Array<int>& rhs) {}

Array<int> a(10);
Array<int> b(10);

int main()
{  
  for (int i = 0; i < 10; ++i)
  {
    //a==b[i]将无法编译通过
	if (a == b[i])
	{
	}
  }
}



  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值