有关C++中类类型转换操作符总结(必看篇)
实例如下:
class SmallInt { public: SmallInt(int i = 0): val(i) { if (i < 0 || i > 255) throw std::out_of_range("Bad SmallInt initializer"); } operator int() const { return val; } private: std::size_t val; };
转换函数采用如下通用形式:
operator type();
type表示内置类型名、类类型名或由类型别名定义的名字。对任何可作为函数返回类型的类型(除了 void 之外)都可以定义转换函数。一般而言,不允许转换为数组或函数类型,转换为指针类型(数据和函数指针)以及引用类型是可以的。转换函数必须是成员函数,不能指定返回类型,并且形参表必须为空。operator int 返回一个 int 值;如果定义 operator Sales_item,它将返回一个 Sales_item 对象,诸如此类。转换函数一般不应该改变被转换的对象。因此,转换操作符通常应定义为 const 成员。
SmallInt si;
double dval;
si >= dval // si converted to int and then convert todouble
优点:类类型转换可能是实现和使用类的一个好处。通过为 SmallInt 定义到int 的转换,能够更容易实现和使用 SmallInt 类。int 转换使 SmallInt 的用户能够对 SmallInt 对象使用所有算术和关系操作符,而且,用户可以安全编写将 SmallInt 和其他算术类型混合使用的表达式。定义一个转换操作符就能代替定义 48个(或更多)重载操作符,类实现者的工作就简单多了。
缺点:二义性
class SmallInt { public: SmallInt(int= 0); SmallInt(double); //Usually it is unwise to define conversions to multiple arithmetic types operatorint() const { return val; } operatordouble() const { return val; } private: std::size_tval; }; void compute(int); void fp_compute(double); void extended_compute(long double); SmallInt si; compute(si); // SmallInt::operator int() const fp_compute(si); // SmallInt::operator double() const extended_compute(si); // error: ambiguous
对 extended_compute 的调用有二义性。可以使用任一转换函数,但每个都必须跟上一个标准转换来获得 long double,因此,没有一个转换比其他的更好,调用具有二义性。
如果两个转换操作符都可用在一个调用中,而且在转换函数之后存在标准转换,则根据该标准转换的类别选择最佳匹配。若无最佳匹配,就会出现二义性。
再比如:
可能存在两个转换操作符,也可能存在两个构造函数可以用来将一个值转换为目标类型。
考虑 manip 函数,它接受一个 SmallInt 类型的实参:
void manip(const SmallInt &); double d; int i; long l; manip(d); // ok: use SmallInt(double) to convert theargument manip(i); // ok: use SmallInt(int) to convert theargument manip(l); // error: ambiguous
第三个调用具有二义性。没有构造函数完全匹配于 long。使用每一个构造函
数之前都需要对实参进行转换:
1. 标准转换(从 long 到double)后跟 SmallInt(double)。
2. 标准转换(从 long 到int)后跟 SmallInt(int)。
这些转换序列是不能区别的,所以该调用具有二义性。
当两个类定义了相互转换时,很可能存在二义性:
class Integral; class SmallInt { public: SmallInt(Integral);// convert from Integral to SmallInt }; class Integral { public: operatorSmallInt() const; // convert from Integral to SmallInt }; void compute(SmallInt); Integral int_val; compute(int_val); // error: ambiguous
实参 int_val 可以用两种不同方式转换为 SmallInt 对象,编译器可以使
用接受 Integral 对象的构造函数,也可以使用将 Integral 对象转换为
SmallInt 对象的 Integral 转换操作。因为这两个函数没有高下之分,所以这
个调用会出错。
在这种情况下,不能用显式类型转换来解决二义性——显式类型转换本身既可以使用转换操作又可以使用构造函数,相反,需要显式调用转换操作符或构造函数:
compute(int_val.operator SmallInt()); // ok: useconversion operator compute(SmallInt(int_val)); // ok: use SmallInt constructor
改变构造函数以接受 const Integral 引用:
class SmallInt { public: SmallInt(constIntegral&); };
则对compute(int_val) 的调用不再有二义性!原因在于使用 SmallInt构造函数需要将一个引用绑定到 int_val,而使用 Integral 类的转换操作符可以避免这个额外的步骤。这一小小区别足以使我们倾向于使用转换操作符。
显式强制转换消除二义性
class SmallInt { public: // Usually it is unwise to define conversions tomultiple arithmetic types operatorint() const { return val; } operatordouble() const { return val; } // ... private: std::size_tval; }; void compute(int); void compute(double); void compute(long double); SmallInt si; compute(si); // error: ambiguous
可以利用显式强制转换来消除二义性:
compute(static_cast<int>(si)); // ok: convertand call compute(int)
显式构造函数调用消除二义性
class SmallInt { public: SmallInt(int= 0); }; class Integral { public: Integral(int= 0); }; void manip(const Integral&); void manip(const SmallInt&); manip(10); // error: ambiguous
可以用显示构造函数消除二义性:
manip(SmallInt(10)); // ok: call manip(SmallInt) manip(Integral(10)); // ok: call manip(Integral)
标准转换优于类类型转换
class LongDouble { public: LongDouble(double ); //… }; void calc( int ); void calc( LongDouble ); double dval; calc( dval ); // which function
最佳可行函数是voidcalc(int), 调用此函数的转换为:将实参double类型转换为int类型的,为标准转换;调用voidcalc( LongDouble)函数时,将实参从double转换为LongDouble类型,为类类型转换,因为标准转换优于类类型转换,所以第一个函数为最佳可行函数。
以上这篇有关C++中类类型转换操作符总结(必看篇)就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持猪先飞。
相关文章
- 这篇文章主要介绍了c++中system("pause")的作用和含义,非常不错,具有参考借鉴价值,需要的朋友参考下吧...2020-04-25
基于BootStrap Metronic开发框架经验小结【八】框架功能总体界面介绍
这篇文章主要介绍了基于BootStrap Metronic开发框架经验小结【八】框架功能总体界面介绍 的相关资料,需要的朋友可以参考下...2016-05-14- 这篇文章主要介绍了C# 16 进制字符串转 int的方法,非常不错,具有参考借鉴价值,需要的朋友可以参考下...2020-06-25
InterlliJ IDEA2020新建java web项目找不到Static Web的解决
这篇文章主要介绍了InterlliJ IDEA2020新建java web项目找不到Static Web的解决,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-09-02- 这篇文章主要介绍了C#类中static变量用法,实例分析了static变量使用技巧与相关注意事项,需要的朋友可以参考下...2020-06-25
- 这篇文章主要介绍了基于Ionic3实现选项卡切换并重新加载echarts,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下...2020-09-24
- 这篇文章主要给大家介绍C# winform快捷键设置技巧,涉及到C winform快捷键相关知识,对C winform知识感兴趣的朋友可以参考下本篇文章...2020-06-25
- 本篇文章是对C#中数据类型转换的几种形式进行了详细的分析介绍,需要的朋友参考下...2020-06-25
- 这篇文章主要介绍了C#判断一个字符串是否是数字或者含有某个数字的方法,本文给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下...2020-06-25
- 最近项目不多忙,于是抽点时间巩固下切换窗口问题,感兴趣的朋友跟着小编一起学习吧...2020-06-25
pytorch绘制并显示loss曲线和acc曲线,LeNet5识别图像准确率
今天小编就为大家分享一篇pytorch绘制并显示loss曲线和acc曲线,LeNet5识别图像准确率,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-05-02基于BootStrap Metronic开发框架经验小结【六】对话框及提示框的处理和优化
这篇文章主要介绍了基于BootStrap Metronic开发框架经验小结【六】对话框及提示框的处理和优化的相关知识,主要对比说明在Bootstrap开发中用到的这些技术要点,对此文感兴趣的朋友一起学习吧...2016-05-14- 这篇文章主要介绍了c#的类型转换详解,类型转换分两种形式:隐式转换、显示转换,下面是详细介绍...2020-06-25
- 这篇文章主要为大家详细介绍了PC蓝牙通信C#代码实现,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2020-06-25
- 这篇文章主要介绍了C#实现带进度条的ListView 的相关资料,需要的朋友可以参考下...2020-06-25
- 这篇文章主要介绍了SpringMVC文件上传原理及实现过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下...2020-07-15
基于BootStrap的Metronic框架实现页面链接收藏夹功能按钮移动收藏记录(使用Sortable进行拖动排序)
这篇文章主要介绍了基于BootStrap的Metronic框架实现页面链接收藏夹功能按钮移动收藏记录(使用Sortable进行拖动排序)的相关资料,非常不错,需要的朋友可以参考下...2016-09-01- 这篇文章主要介绍了C#向线程中传递多个参数的解决方法(两种)的相关资料,非常不错,具有参考借鉴价值,需要的朋友可以参考下...2020-06-25
C# MVC模式中应该怎样区分应用程序逻辑(Controller层)和业务逻辑(Model层)?
这篇文章主要介绍了C# MVC模式中应该怎样区分应用程序逻辑(Controller层)和业务逻辑(Model层)?,这也小编做.NET项目时经常思考和让人混乱的一个问题,这篇文章写的挺好,一下清晰了许多,需要的朋友可以参考下...2020-06-25基于Bootstrap的Metronic框架实现页面链接收藏夹功能
本文给大家介绍基于Metronic的Bootstrap开发框架实现页面链接收藏夹功能,非常不错,具有参考借鉴价值,感兴趣的朋友一起学习吧...2016-09-01