我们之前在 C 语言中讲过类型转换,那么在 C++ 中是否还会有什么新特性呢?我们先来看看之前的类型转换是怎样的,标准数据类型之间会进行隐式的类型安全转换。转换规则如下

我们还是以代码为例来进行分析

#include <iostream>
#include <string>using namespace std;int main()
{short s = 'a';unsigned int ui = 100;int i = -200;   // safedouble d = i;   // safecout << "d = " << d << endl;cout << "ui = " << ui << endl;if( (ui + i) > 0 ){cout << "Positive" << endl;}else{cout << "Negative" << endl;}cout << "sizeof(s + 'b') = " << sizeof(s + 'b') << endl;return 0;
}

我们来试着打印下 d 和 ui 的值,如果 ui + i > 0,则打印 Positive,否则打印 Negative。最后看看 short 和 char 类型会转换成 short 吗?看看编译结果

我们看到打印的是 Positive,也就说 ui + i > 0。根据数学知识,怎么可能呢?我们一会再来打印下他们相加的值看看,最后一个竟然打印的是 4,short 类型不是 2 吗?再看看我们上面的隐式类型转换规则,short 和 char 都会转换成 int 类型。而 int 也会隐式转换成 unsigned int,所以结果并不惊奇,我们来看看他们相加的值是多少?

我们看到他们相加是个那么大的随机数,这肯定大于 0 啦。那么在 C++ 中问题来了:普通类型与类类型之间能否进行类型转换?类类型之间能否进行类型转换?下来我们来看看示例代码

#include <iostream>
#include <string>using namespace std;class Test
{int mValue;
public:Test(){mValue = 0;}Test(int i){mValue = i;}Test operator + (const Test& t){Test ret(mValue + t.mValue);return ret;}int value(){return mValue;}
};int main()
{Test t;t = 5;cout << "t.value() = " << t.value() << endl;Test r;r = t + 10;cout << "r.value() = " << r.value() << endl;return 0;
}

我们来看看这样直接 t = 5,和 r = t + 10;可以通过吗?看看编译结果

我们看到编译通过了,并且也执行成功。下来我们来分析下为什么会支持这样的写法,在构造函数中可以定义不同类型的参数,参数满足这三个条件时便称之为转换构造函数:a> 有且仅有一个参数;b> 参数是基本类型;c> 参数是其它类类型。那么我们从 C 的角度来看看强制类型转换:int i = int(1.5);Test t = Test(100);这样便不难解释了,为了显示编译器的强大,编译器会尽力尝试让源码通过编译,如下

编译尽力尝试的结果便是隐式类型转换,使用转换构造函数来进行转换。但是隐式类型的转换会让程序以意想不到的方式进行工作,是工程中的 bug 的重要来源。如果在那块我们只是手误写成那样了,编译器却让它通过了,我们看到运行结果不对,bug 却无从查起。。。

所以为了解决这个问题,我们便在工程中通过 explicit 关键字来杜绝编译器的转换尝试,转换构造函数被 explicit 修饰时只能进行显示转换,转换方式是:a> static_cast <ClassName>(value);b> ClassName(value);c> (ClassName)value;但是在 C++ 中我们推荐的是第一种写法,最后一种往往是不推荐的。下来我们就来试试 explicit 关键字,在 Test(int i) 成员函数前加上,看看编译器还会不会进行隐式类型转换

那么编译器直接报错了,我们再来试试手动的进行类型转换,我们将第 37 和 43 行改为下面那样

    t = static_cast<Test>(5);r = t + static_cast<Test>(10);

我们来看看编译结果

结果和我们之前的是一样的。那么从普通类型能够转换到类类型,类类型能否转换到普通类型呢?我们在 C++ 类中可以定义类型转换函数,类型转换函数用于将类对象转换为其它类型,语法规则如下

下来我们来试试编写类型转换函数

#include <iostream>
#include <string>using namespace std;class Test
{int mValue;
public:Test(int i){mValue = i;}int value(){return mValue;}operator int (){return mValue;}
};int main()
{Test t(100);int i = t;cout << "t.value() = " << t.value() << endl;cout << "i = " << i << endl;return 0;
}

我们来试试看这样行不行呢,编译结果如下

我们看到类对象已经成功转换为普通数据类型。那么类型转换函数具有以下几个特点:a> 与转换构造函数具有相等的地位;b> 使得编译器有能力将对象转化为其它类型;c> 编译器能够隐式的使用类型转换函数。同样,编译器也会尽量尝试让源码通过编译,如下

那么便不难解释我们上面的程序了。既然这样都可以转换,类类型之间可以相互转换吗?我们来看看

#include <iostream>
#include <string>using namespace std;class Value
{
public:Value(){}
};class Test
{int mValue;
public:Test(int i){mValue = i;}int value(){return mValue;}operator Value (){Value ret;return ret;}
};int main()
{Test t(100);Value v = t;return 0;
}

那么我们看到 Test 和 Value 是两个不同的类,它们能转换成功吗?我们来看看编译结果

编译通过,当然没什么输出了,我们在程序中又没有什么打印语句。那么如果我们在类 Value 中加上转换构造函数呢?编译器会作何选择?这时我们的 VAlue 类将会变成

class Value
{
public:Value(){}Value(Test& t){}
};

我们来编译下看看结果

编译器报错了,它犯难了。这是不知道是调用 Test 类的类型转换函数还是 Value 类的转换构造函数了,像这种情况,我们在转换构造函数前加上 explicit 关键字,编译器便不会去隐式的调用转换构造函数了。我们在类型转换函数中加上一句输出,看看结果

我们可以看出调用的确实是类型转换函数。那么我们无法抑制隐式的类型转换函数调用,类型转换函数便可能与转换构造函数造成冲突,工程中以 Type toType() 的共有成员函数代替类型转换函数。

通过对类型转换函数的学习,总结如下:1、转换构造函数只有一个参数;2、转换构造函数的参数类型是其它类型,它在类型转换时被调用;3、隐式类型转换时工程中 bug 的重要来源,explicit 关键字用于杜绝隐式类型转换;4、C++ 类中可以定义类型转换函数;5类型转换函数用于将类对象转换为其它类型,它与转换构造函数具有同等的地位;6、工程中以 Type toType() 的共有成员函数代替类型转换函数。

欢迎大家一起来学习 C++ 语言,可以加我QQ:243343083。

转载于:https://blog.51cto.com/12810168/2120481

类型转换函数(三十五)相关推荐

  1. 第三十五章 SQL函数 CURRENT_DATE

    文章目录 第三十五章 SQL函数 CURRENT_DATE 大纲 描述 示例 第三十五章 SQL函数 CURRENT_DATE 日期/时间函数,返回当前本地日期. 大纲 CURRENT_DATE 描述 ...

  2. NeHe OpenGL第三十五课:播放AVI

    NeHe OpenGL第三十五课:播放AVI 在OpenGL中播放AVI: 在OpenGL中如何播放AVI呢?利用Windows的API把每一帧作为纹理绑定到OpenGL中,虽然很慢,但它的效果不错. ...

  3. Python编程基础:第三十五节 文件删除Delete a File

    第三十五节 文件删除Delete a File 前言 实践 前言 我们这一节来介绍如何删除一个文件,这里需要用到函数os.remove(path)用于删除指定路径下的文件,os.rmdir(path) ...

  4. [Python从零到壹] 三十五.图像处理基础篇之OpenCV绘制各类几何图形

    欢迎大家来到"Python从零到壹",在这里我将分享约200篇Python系列文章,带大家一起去学习和玩耍,看看Python这个有趣的世界.所有文章都将结合案例.代码和作者的经验讲 ...

  5. 零基础带你学习MySQL—日期函数(十五)

    零基础带你学习MySQL-日期函数(十五) 一.CURRENT_DATE ( ) 当前日期 二.CURRENT_TIME() 当前时间 三.CURRENT_TIMESTAMP()当前时间戳 四.练习

  6. JAVA之旅(三十五)——完结篇,终于把JAVA写完了,真感概呐!

    JAVA之旅(三十五)--完结篇,终于把JAVA写完了,真感概呐! 这篇博文只是用来水经验的,写这个系列是因为我自己的java本身也不是特别好,所以重温了一下,但是手比较痒于是就写出了这三十多篇博客了 ...

  7. 【正点原子Linux连载】第三十五章 Linux内核顶层Makefile详解 -摘自【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.0

    1)实验平台:正点原子阿尔法Linux开发板 2)平台购买地址:https://item.taobao.com/item.htm?id=603672744434 2)全套实验源码+手册+视频下载地址: ...

  8. stm32 读取sd卡图片显示_「正点原子STM32Mini板资料连载」第三十五章 汉字显示实验...

    1)实验平台:正点原子STM32mini开发板 2)摘自<正点原子STM32 不完全手册(HAL 库版)>关注官方微信号公众号,获取更多资料:正点原子 第三十五章 汉字显示实验 汉字显示在 ...

  9. Java学习笔记(三十五)

    在完成对C语言的学习后,我最近开始了对C++和Java的学习,目前跟着视频学习了一些语法,也跟着敲了一些代码,有了一定的掌握程度.现在将跟着视频做的笔记进行整理.本篇博客是整理Java知识点的第三十五 ...

  10. C语言笔记 第三十五课 数组参数和指针参数分析

    第三十五课 数组参数和指针参数分析 思考:为什么C语言中的数组参数会退化为指针? 退化的意义 C语言中只会以值拷贝的方式传输参数 当向函数传递数组时:(错误的,设计当初的思路) 将整个数组拷贝一份传入 ...

最新文章

  1. C# 对ListT取交集、连集及差集
  2. SQLite FTS5使用小技巧
  3. linux redhat 下命令行全部乱码解决
  4. spoj SUBLEX (Lexicographical Substring Search) RE的欢迎来看看
  5. python读取sql_从python读取sql的实例方法
  6. GDI+ 应用,Release没有错误,Debug很多。
  7. pca主成分分析结果解释_主成分分析(PCA)原理精讲 | 统计学专题
  8. JDBC_ResultSet类_结果集对象
  9. 域控服务器降级失败,降级域控制器时出错 - Windows Server | Microsoft Docs
  10. 基于二进制粒子群算法的背包问题求解- 附代码
  11. dva开发一个cnode网站(1)
  12. PHP开发工资条短信通知
  13. php怎么黑admin管理员密码是什么,tplink管理员密码是什么?
  14. arm mali 天梯图_电视盒子CPU天梯图:原来这些处理器都在这个档位
  15. Spring框架基础(2)----Bean的创建及标签属性
  16. 白帽专访丨大家好,我们是渊龙Sec安全团队
  17. Git安装包(win版)
  18. 《黑客帝国》电影里满屏幕代码的“数字雨”
  19. pda输出模式设置,在pda手持设备上,文本框的输入监听焦点受输出模式影响
  20. 电脑清灰,笔记本电脑如何清灰尘 笔记本电脑清灰方法【详细介绍】

热门文章

  1. 动态验证码制作(RandomCodeImage )
  2. 分享mac磁盘清理的方法
  3. The number of Oracle redo threads (2) is not the same as the number of checkpoint threads (1)
  4. 网络资源(9) - TDD视频
  5. RAC 实例 迁移到 单实例 -- 使用导出导入
  6. ASP.NET 应用程序生命周期概述
  7. jar打包混淆上传全自动日志
  8. json字符串拼接 json_encode 数组带有花括号{}和中括号[]
  9. DAY11-MYSQL之ORM框架SQLAlchemy
  10. SharePoint REST API - 同步SharePoint列表项