IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> C++ 运算符重载(二) | 类型转换运算符,二义性问题 -> 正文阅读

[C++知识库]C++ 运算符重载(二) | 类型转换运算符,二义性问题


类型转换运算符

概念

类型转换运算符(conversion operator)是类的一种特殊成员函数。负责将一个类类型的值转换成其他类型。

operator type() const ;

其中 type 表示某种类型。类型转换运算符可以面向任意类型(除了 void 之外)进行定义,只要该类型能作为函数的返回类型。因此,我们不允许转换成数组或者函数类型,但允许转换成指针(包括数组指针及函数指针)或者引用类型。

一个类型转换函数必须是类的成员函数;它不能声明返回类型,形参列表也必须为空。类型转换函数通常不应该改变待转换对象的内容,因此,应该是const。

运用实例,定义一个简单的类,令其表示 0~255 之间的一个整数:
在这里插入图片描述
构造函数将算术类型的值转换成 SmallInt 对象,而类型转换运算符将 SmallInt 对象转换成 int

SmallInt si;
si = 4; // 将 4 隐式转换成 SmallInt,然后调用 SmallInt::operator=
si + 3; // 首先将 si 隐式地转换成 int,然后执行整数的加法

尽管编译器一次只能执行一个 我们定义的类型转换(如上面的构造函数/类型转换运算符),但可以将其搭配 内置类型转换(如double可以转换成int) 实现二次转换。

// 内置类型转换将 doulbe 实参转换成 int
SmallInt si = 3.14; // 调用 SmallInt(int) 构造函数,然后调用拷贝构造函数
// SmallInt 的类型转换运算符将 si 转换成 int
si + 3.14// 内置类型将所得的 int 继续转换成 double

尽管类型转换函数不负责指定返回类型,但实际上每个类型转换函数都会返回一个对应类型的值:
在这里插入图片描述


避免过度使用类型转换函数

  1. 类型转换可能具有误导性

例如,假设某个类表示 Date,我们也许会为它添加一个从 Dateint 的转换。然而,类型转换函数的返回值应该是什么?

  • 一种可能的解释是,函数返回一个十进制数,依次表示年、月、日,例如,July 30,1989 可能转换为 int19890730
  • 同时还存在另外一种合理的解释,即类型转换运算符返回的 int 表示的是从某个时间节点(比如 January 1,1970)开始经过的天数。

问题在于 Date 类型的对象和 int 类型的值之间不存在明确的一对一映射关系。因此在此例中,不定义该类型转换运算符也许会更好。作为替代的手段,类可以定义一个或多个普通的成员函数以从各种不同形式中提取所需的信息。

  1. 类型转换运算符可能产生意外结果

对于类来说,定义向 bool 的类型转换还是比较普遍的现象。

int i = 42;
cin << i; // 如果向 bool 的类型转换不是显式的,则该代码在编译器看来是合法的

因为 istream 本身并没有定义 <<,所以本来代码应该产生错误。然而,该代码能使用 istreambool类型转换运算符cin 转换成 bool ,而这个 bool值 接着会被提升成 int 并用作内置的左移运算符的左侧运算对象。这样一来,提升后的 bool值(1或0) 最终会 被左移42个位置。 这一结果显然与我们的预期大相径庭。


解决上述问题的方法

转换为 bool

  • 标准库的早期版本中,IO 类型定义了向 void* 的转换规则,以求避免上述问题。
  • C++11 标准中,IO 标准库通过定义一个向 bool 的显式类型转换实现同样的目的。

其实我们在编程中经常用到 IO 类型定义的 operator bool

while(std::cin >> value)

为了对条件求值,cinistream operator bool 类型转换函数隐式地执行了转换。如果 cin 的条件状态是 good,则该函数返回为真;否则该函数返回为假。(这部分知识可以看我之前的博客

bool 的类型转换通常用在条件部分,因此 operator bool 一般定义成 explicit 的。


显式的类型转换运算符

为了防止上面第二点这样的异常情况发生,我们可以使用 explicit 关键字。
在这里插入图片描述

SmallInt  si = 3; // 正确:SmallInt 的构造函数不是显式的
si + 3; // 错误:explicit阻止隐式类型转换
static_cast<int>(si) + 3; // 正确:显式地请求类型转换

当类型转换运算符是显式的时,我们也能执行类型转换,不过必须通过显式的强制类型转换才可以。

该规定存在一个例外,即,如果表达式被用作条件,则编译器会将显式的类型转换自动应用于它。 换句话说,当表达式出现在下列位置时,显式的类型转换将被隐式地执行:

  • ifwhiledo 语句的条件部分
  • for 语句头的条件表达式
  • 逻辑非运算符(!)、逻辑或运算符(||)、逻辑与运算符(&&)的运算对象
  • 条件运算符(? :)的条件表达式。

类型转换二义性

如果类中包含一个或多个类型转换,则必须确保在类类型和目标类型之间只存在唯一一种转换方式。否则的话,我们编写的代码将很可能会具有二义性。

在两种情况下可能产生多重转换路径:

  1. 第一种情况是 两个类提供相同的类型转换: 例如,当 A类 定义了一个接受 B类 对象的转换构造函数,同时 B类 定义了一个转换目标是 A类 的类型转换运算符。
  2. 第二种情况是 类定义了多个转换规则,而某些转换规则可以通过其他类型转换实现。 这种情况多出现在算术运算符上。

通常情况下,不要为类定义相同的类型转换,也不要在类中定义两个及两个以上转换源或转换目标是算术类型的转换。

第一种情况举例:

在这里插入图片描述

解决方法是显式调用:

A a1 = f(b.operator A());
A a2 = f(A(b));

第二种情况举例:

在这里插入图片描述
我们使用两个用户定义的类型转换时,如果转换函数之前或之后存在标准类型转换,则标准类型转换将决定最佳匹配到底是哪个:

short s = 42;
// 把 short 提升成 int 优于 提升成 double
// 上面的 long 则没有int和double谁优于谁的规则,因此会有二义性
A a3(s); // A::A(int)

重载函数与类型转换结合导致的二义性

有时会出现这种情况:
在这里插入图片描述

或这种情况:
在这里插入图片描述

虽然我们可以通过显式地构造正确的类型而消除二义性:

manip(C(10)); // 调用 manip(const C&)
manip2(E(double(10))); // 调用 manip2(const E&)

但意味着程序的设计存在不足。


重载运算符与类型转换结合导致的二义性

重载的运算符也是重载的函数。因此也遵从通用的函数匹配规则。例如,如果 a 是一种类类型,则表达式 a sym b 可能是:

a.operatorsym(b); // a 有一个 operatorsym 成员函数
operatorsym(a, b); // operatorsym 是一个普通函数

和普通函数不同,我们无法通过调用的形式区分当前调用的是成员函数还是非成员函数。

举个例子:
在这里插入图片描述

  • 第一条加法语句接受两个 SmallInt 值并执行 + 运算符的重载版本。
  • 第二条加法语句具有二义性:因为我们可以把 0 转换成 SmallInt,然后使用 SmallInt+;或者把 s3 转换成 int,然后对于两个 int 执行内置的加法运算。

如果我们对同一个类既提供了转换目标是算术类型的类型转换,也提供了重载的运算符,则将会遇到重载运算符与内置运算符的二义性问题。

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-09-18 09:54:07  更:2021-09-18 09:58:33 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 -2024/12/28 13:10:45-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码
数据统计