类型转换函数(三十五)
我们之前在 C 语言中讲过类型转换,那么在 C++ 中是否还会有什么新特性呢?我们先来看看之前的类型转换是怎样的,标准数据类型之间会进行隐式的类型安全转换。转换规则如下
我们还是以代码为例来进行分析
#include<iostream>#include<string>usingnamespacestd;intmain(){shorts='a';unsignedintui=100;inti=-200;//safedoubled=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;return0;}
我们来试着打印下 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>usingnamespacestd;classTest{intmValue;public:Test(){mValue=0;}Test(inti){mValue=i;}Testoperator+(constTest&t){Testret(mValue+t.mValue);returnret;}intvalue(){returnmValue;}};intmain(){Testt;t=5;cout<<"t.value()="<<t.value()<<endl;Testr;r=t+10;cout<<"r.value()="<<r.value()<<endl;return0;}
我们来看看这样直接 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>usingnamespacestd;classTest{intmValue;public:Test(inti){mValue=i;}intvalue(){returnmValue;}operatorint(){returnmValue;}};intmain(){Testt(100);inti=t;cout<<"t.value()="<<t.value()<<endl;cout<<"i="<<i<<endl;return0;}
我们来试试看这样行不行呢,编译结果如下
我们看到类对象已经成功转换为普通数据类型。那么类型转换函数具有以下几个特点:a> 与转换构造函数具有相等的地位;b> 使得编译器有能力将对象转化为其它类型;c> 编译器能够隐式的使用类型转换函数。同样,编译器也会尽量尝试让源码通过编译,如下
那么便不难解释我们上面的程序了。既然这样都可以转换,类类型之间可以相互转换吗?我们来看看
#include<iostream>#include<string>usingnamespacestd;classValue{public:Value(){}};classTest{intmValue;public:Test(inti){mValue=i;}intvalue(){returnmValue;}operatorValue(){Valueret;returnret;}};intmain(){Testt(100);Valuev=t;return0;}
那么我们看到 Test 和 Value 是两个不同的类,它们能转换成功吗?我们来看看编译结果
编译通过,当然没什么输出了,我们在程序中又没有什么打印语句。那么如果我们在类 Value 中加上转换构造函数呢?编译器会作何选择?这时我们的 VAlue 类将会变成
classValue{public:Value(){}Value(Test&t){}};
我们来编译下看看结果
编译器报错了,它犯难了。这是不知道是调用 Test 类的类型转换函数还是 Value 类的转换构造函数了,像这种情况,我们在转换构造函数前加上 explicit 关键字,编译器便不会去隐式的调用转换构造函数了。我们在类型转换函数中加上一句输出,看看结果
我们可以看出调用的确实是类型转换函数。那么我们无法抑制隐式的类型转换函数调用,类型转换函数便可能与转换构造函数造成冲突,工程中以 Type toType() 的共有成员函数代替类型转换函数。
通过对类型转换函数的学习,总结如下:1、转换构造函数只有一个参数;2、转换构造函数的参数类型是其它类型,它在类型转换时被调用;3、隐式类型转换时工程中 bug 的重要来源,explicit 关键字用于杜绝隐式类型转换;4、C++ 类中可以定义类型转换函数;5类型转换函数用于将类对象转换为其它类型,它与转换构造函数具有同等的地位;6、工程中以 Type toType() 的共有成员函数代替类型转换函数。
欢迎大家一起来学习 C++ 语言,可以加我QQ:243343083。
声明:本站所有文章资源内容,如无特殊说明或标注,均为采集网络资源。如若本站内容侵犯了原著者的合法权益,可联系本站删除。