![类型及类型转换_第1页](http://file4.renrendoc.com/view/e25eb1e8292ab52617ec7bf2f86819ac/e25eb1e8292ab52617ec7bf2f86819ac1.gif)
![类型及类型转换_第2页](http://file4.renrendoc.com/view/e25eb1e8292ab52617ec7bf2f86819ac/e25eb1e8292ab52617ec7bf2f86819ac2.gif)
![类型及类型转换_第3页](http://file4.renrendoc.com/view/e25eb1e8292ab52617ec7bf2f86819ac/e25eb1e8292ab52617ec7bf2f86819ac3.gif)
![类型及类型转换_第4页](http://file4.renrendoc.com/view/e25eb1e8292ab52617ec7bf2f86819ac/e25eb1e8292ab52617ec7bf2f86819ac4.gif)
![类型及类型转换_第5页](http://file4.renrendoc.com/view/e25eb1e8292ab52617ec7bf2f86819ac/e25eb1e8292ab52617ec7bf2f86819ac5.gif)
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
-.z.第九章类型及类型转换C/C++作为强类型语言,类型及类型转换的重要性在JAVA课中已做过介绍〔JAVA也是强类型语言〕。这一章集中讲一下C/C++的类型及类型转换,内容包括:C语言类型C++类型C/C++中根本的类型转换C++对象的类型转换类型转换函数一、C语言类型C语言的根本类型以及struct等复合类型,同学们已经很熟悉了,不再赘述,下面讨论几个课本中讲得不多的类型。1枚举enumC语言提供了一种称为"枚举〞的类型。在"枚举〞类型的定义中列举出所有可能的取值,而且被说明为该"枚举〞类型的变量取值不能超过定义的范围。枚举类型定义的一般形式为:enum枚举名{枚举值表};
在枚举值表中应罗列出所有可用值。这些值也称为枚举元素。
例如:enumweekday{sun,mou,tue,wed,thu,fri,sat};枚举元素本身由系统定义了一个表示序号的数值,从0开场顺序定义为0,1,2…。如在weekday中,sun值为0,mon值为1,…,sat值为6。枚举类型是一种根本数据类型,而不是一种复合类型,因为它不能再分解为任何根本类型。枚举变量的使用如下例所示:main(){
enumweekday
{
sun,mon,tue,wed,thu,fri,sat
}a,b,c,d;
a=sun;//
b=mon;//c=2;//错。枚举类型不等同于整数d=(enumweekday)3;//需要强制类型转换}枚举的语法不多做介绍,主要讲一下它在实际编程中怎么用:有些可以定义为整型的变量,取值被限定在一个有限的范围内,可取的值都有一个熟知的名字。例如,一个星期内的七天,一年的十二个月等。如果把这些量说明为字符串,则对这些变量进展关系运算或算术运算不方便〔比方比拟大小〕,而说明为整型每个值又没有名字也不太方便。这时后可考虑将其定义为枚举。使用枚举的好处是:不仅帮助程序员和用户记忆,而且使程序可靠,可以防止变量取非法取值。枚举在实际编程中非常常见,比方JAVA线程库中线程的状态〔wait,start,run…,〕等等就是用枚举〔而不是整型或字串〕,还有很多C程序对设备状态、存放器状态等往往也用枚举标识。Q1:在什么情况下使用枚举enum类型?好处是什么?2存放器变量registerregisterinti;按语法的意思,是把i放到存放器内,这比放到内存中快得多,如果i频繁使用的话,会提高效率。问题是C语言是可移值的—*种程度上有跨平台的特性,不同平台编译registerinti时会有不同的处理,为了防止副作用,有的C编译器可能不把i放到存放器内。大多数C语言编译器都含有优化器,对常使用的局部变量等等进展优化,有时没有声明为register的变量也会放到存放器中,所以没必要使用registerinti这种可移值性不好的代码。3typedef见"第四章预处理指令〞4共同体union在C语言里,union可以看作是一种特殊的struct,而在C++里,struct和union可以看作是特殊的类,它们可以有构造函数。无论如何,union的根本特性是:使假设干变量共享一段内存。比方:unionmyunion{int*;charch;floaty;}a,b//定义类型myunion。*、ch、y共享其中类型最宽的字节的内存。最后定义了myunion类型变量a,ba.*;b.ch;b.y;//引用共同体成员union在实际编程中有什么用?下面例举几种用途;〔1〕有人认为:不同类型变量共用一段内存,类型转换时不用强制转换。确实如此,但这绝不是好的编程风格,如果只是为了类型转换方便,最好不要用union。〔2〕有时需要操作几个固定字节数、固定地址的硬件或软件接口〔比方设备I/O端口〕,这个接口对不同代码的访问需要呈现不同的界面〔比方有时是字符串,有时是整数,有时是控制字〕,可以使用union让几个成员共享该界面。比方:unionport*{lontint*;//4字节端口,I/O整数charstr[4];//同一个4字节端口,I/O字串charc_word[4];//同一个4字节端口,I/O控制字}myPort(3)节约内存,在一些微小系统里,确实需要使用union节约内存,比方让多个数组共享一段内存。在C++中,union用作类的成员变量,由于类的构造函数的问题,可能会有一些需要特殊处理的问题,略过不讲。其它有关union语法的问题也略过不讲,我们只强调该怎么用它。在一些微小系统和底层程序中,union的出镜率还是挺高的。5volatileC语言关键字volatile〔易变的〕表示不经过赋值,其值也可能被改变〔例如,表示时钟的变量、表示端口的变量等〕。声明为volatile的变量会阻止编译器对其优化〔有时编译器会把变量优化到我们不希望的地方〕,在与硬件很密切的编程中使用较多。比方以下声明:volatileinta;a在运行期间不经过赋值也可能被改变。下面例举volatile变量的几种用途;
1)设备的硬件存放器〔如:状态存放器〕
2)一个中断效劳子程序中会访问到的非自动变量3)多线程应用中被几个任务共享的变量volatile还可以用来修饰常量:volatileconstinta;这是什么意思?a不允许程序员修改,但会在程序运行过程中被系统修改,比方只读的状态存放器。以前讲过,const真正的含义是"只读〞,而不是"常数〞。对嵌入式编程或对硬件直接编程感兴趣的同学应注意volatile。6浮点数的判等和比拟浮点数采用科学计数法,其值的精度不是100%准确,因此用于判等和比拟时要特别小心。常用判等的方法是,两个浮点数相减的绝对值小于一个很小很小的数就认为相等。Q2:浮点数在判断是否为0时会出现什么问题?原因是什么?二、C++类型C++主要增加了类、泛型等类型,对struct也作了面向对象的升级。1C++的class与structQ3:C++类与构造体区别?在C++里,struct可以看作是一个特殊的类,区别在于:class中默认的成员访问权限是private的,而struct中则是public的。从class继承默认是private继承,而从struct继承默认是public继承。
例:#include
<cstdlib>
#include
<iostream>
usingnamespace
std;
struct
ST{
ST()
{……}
//构造体可以有构造函数和其它成员函数
int
a;
int
b;//默认的成员访问权限是public
};
//构造体成员函数实现的语法与类一样
intmain(int
argc,char*argv[])
{
STst1();//定义构造体栈对象ST*st2=newST();//定义构造体堆对象……}
2.C++的bool类型C++的bool类型可取值为false和true,而旧式方式是0表示false,非0表示true.三、C/C++根本的类型转换这一小节主要是复习性质的,大多数内容在C语言中学过。C/C++允许在一个表达式中参与运算的操作数的数据类型不一致,即支持不同数据类型的数据之间的混合运算。在对这样的表达式求值时,C++语言需要对其中的一些操作数进展类型转换。表达式中的类型转换有两种方式:自动转换和强制转换。1自动转换一般地,双目运算中的算术运算符、关系运算符、逻辑运算符和位操作运算符组成的表达式,要求两个操作数的类型一致,如果操作数类型不一致,则自动将低类型转换为高的类型。各种类型的上下顺序如下所示:高double←←float↑↑↑long↑↑↑unsigned↑↑低int←←char,short自动转换的特点:自动转换由编译系统自动完成。自动转换是一种保值映射,即在转换中数据的精度不受损失。自动类型转换相当于"类型升级〞,如果原来的数是无符号数,则在扩展的时候,高位填充的是0;如果是有符号数,则高位填充的是符号位。可以自动转换的类型是"类型兼容〞的,它们反过来可以进型强制转换。自动转换一般只发生在算术表达式的运算中,因此,一般类型转换都应该用强制类型转换。2强制转换分为显式强制转换和隐式强制转换。〔1〕显式强制转换有两种格式,例如:doublef=3.55;inth;h=int(f);//第一种格式,函数风格h=(int)f;//第二种格式,C风格这两种格式的作用一是通知编译器,二是告诉程序的阅读者这里有类型转换,有些程序员把可以自动转换的类型也写成上述两种风格之一,这是好习惯。比方:doublef;inth=5;f=double(h);本来是可以自动转换的,但写成强制转换对程序的阅读者有更强的提示作用。(2)隐式强制转换主要有两种情况:在赋值表达式中,右值类型可以隐式强制转换为左值类型。例如:doublef=3.55;inth1;h=f;//隐式强制转换另为在函数返回类型中,可以隐式强制转换,例如:intf1(){return36.8;},实际返回36。但上述两种情况的有些类型转换必需进展显式强制转换,比方:int*p=100;//不能隐式强制转换,编译器会报错,应改为:int*p=〔int*〕100;强制类型转换是不平安的,因为将高类型转为低类型会造成丧失小数局部精度损失或整数局部。这种情况只有程序员自已小心,在写强制类型转换代码时,最好不要写成隐式的,因为这会让程序阅读者忽略转换可能带来的潜在危险,应该试一试可不可以写成显式的,对自动类型转换最好也试试可不可以写成显式的。强制类型转换是"临时性〞或"副本转换〞的,比方:doublef=3.55;inth1;h=(int)f;//f"临时性〞转换为3,转换完后f仍为3.55。Q4:为什么说强制类型转换是不平安的?3.函数形参有类型转换功能函数实参传给形参,相当于赋值,所以只要形参和实参满足隐式强制转换条件〔或自动转换条件〕,都能进展隐式强制转换〔或自动转换〕。比方:Fun(int,int);//实参为float时可进展隐式强制转换Fun(float,float);//实参为int时可进展自动转换上述特性在C语言中就有,在C++中的成员函数和构造函数也具有这些特性。但是,有时这种隐式类型转换可能带来一些问题,这时可用到C++关键字e*plicit,将类的构造函数声明为"显示",也就是在声明构造函数的时候,前面添加上e*plicit即可,这样就可以防止这种转换操作。e*plicit只对C++构造函数有效。Q5:了解函数形参的类型转换功能四、C++对象的类型转换这一小节介绍C++特有的类型转换。C++的类型转换首先兼容C,也做了很多扩大,比C语言更准确,因此也更复杂。C++有了类和对象的概念,对象的形式是指针,因此C++对象的类型转换具有指针的一般特性,但是远比指针复杂,很少有一本编程书能介绍完整。1RTTIQ6:什么是RTTI?学习C++类型转换,要知道一个概念:RTTI(Run-TimeTypeIdentification,运行时刻类型识别)。RTTI是面向对象一项重要技术,标准的C++以及很多编译器厂商的C++都实现了这项技术,另外JAVA/C#等也实现了这项技术,比方JAVA关键字instanceof需要RTTI支持。通过使用RTTI,程序可以在运行时通过基类指针或者引用来得到所指对象的实际类型。C++的RTTI主要有两个操作:〔1〕typeid操作符:返回指针或者引用所指对象的实际类型。〔2〕dynamic_cast操作符:将基类类型的指针或引用平安地转换为派生类型的指针或者引用。2C++新增的typecasting类型转换,英语也叫typecasting。C++新增了几个与typecasting有关的操作符:static_castdynamic_castreinterpret_castconst_casttypeid〔1〕static_cast〔不使用RTTI〕用法:static_cast<TypeName>(e*pression)
该运算符把e*pression转换为TypeName类型,它是在编译时进展类型检查,而不使用RTTI。它主要有如下几种用法:
①用于类层次构造中基类和子类之间指针或引用的转换。
进展上行转换〔把子类的指针或引用转换成基类表示〕是平安的;
进展下行转换〔把基类指针或引用转换成子类表示〕时,由于没有动态类型检查,所以是不平安的。
②用于根本数据类型之间的转换,如把int转换成char,把int转换成enum。相当于C语言的强制类型转换,是不平安的。比方:doubled;
inta=static_cast<int>(d);③把*类型的空指针转换成目标类型的空指针。
④把任何类型的表达式转换成void类型。〔2〕dynamic_cast〔使用RTTI〕用法:dynamic_cast<TypeName>(e*pression)
该运算符把e*pression转换成TypeName类型的对象。TypeName必须是类的指针、类的引用或者void*;
如果TypeName是类指针类型,则e*pression也必须是一个指针,如果TypeName是一个引用,则e*pression也必须是一个引用。dynamic_cast主要用于类层次间的上行转换和下行转换,还可以用于类之间的穿插转换。
在类层次间进展上行转换时,dynamic_cast和static_cast的效果是一样的;
在进展下行转换时,dynamic_cast具有类型检查的功能,比static_cast更平安。下面的例子说明dynamic_cast,static_castclassA{
public:inta;virtualvoidfun();};classB:publica{
public:floatb;};voidfunc(A*pa){//形参是RTTI要求的基类指针B*pb1=static_cast(pa);//不用RTTIB*pb2=dynamic_cast(pa);//使用RTTI
}讨论一下上面的代码段:〔a〕如果func形参pa指向一个子类B的对象,则转换后pb1和pb2是一样的,并且对这两个指针执行B类型的任何操作都是平安的。〔b〕如果func形参pb指向一个父类A的对象,则转换后:pd1是将父类A对象pa转换来的子类B对象,对它进展B类型的操作将是不平安的〔比方不能访问B的成员floatb〕,这是static_cast的特点,它类似于C语言的强制类型转换,是不平安的。pd2也是将父类A对象pa转换来的子类B对象,但RTTI知道这种转换不平安,将pd2设为B类型的NULL,而不是指向一个B对象,也就是说pd2有类型而无对象,这是dynamic_cast的特点,它更平安,它可以防止程序继续访问不该访问的成员〔比方访问B的成员floatb〕。[注意:]上例中基类A一定要有虚函数,否则dynamic_cast时会编译出错;RTTI要求基类必需有至少有一个虚函数才能进展dynamic_cast。static_cast则没有这个限制。这是由于运行时类型检查需要运行时类型信息,而这个信息存储在类的虚函数表中,只有定义了虚函数的类才有虚函数表。上例中的dynamic_cast是父类子类间的转换,dynamic_cast还支持穿插转换。如下代码所示:classA{
public:inta;
virtualvoidf(){}};classB:publicA{};classD:publicA{};voidfoo(){
B*pb=newB;
pb->a=100;D*pd1=static_cast(pb);//pileerror
D*pd2=dynamic_cast(pb);//pd2isNULL
deletepb;
}在函数foo中,使用static_cast进展转换是不被允许的,将在编译时出错,因为语法上不允许static_cast穿插转换;而使用dynamic_cast的转换则是允许的,结果是空指针,这是dynamic_cast的特点,它更平安,它可以防止程序继续访问不该访问的成员〔比方访问B的特有成员〕。Q7:static_cast和dynamic_cast主要区别是什么?(3)reinpreter_cast
用法:reinpreter_cast<TypeName>(e*pression)<TypeName>必须是一个指针、引用、算术类型、函数指针或者成员指针。
reinterpret_cast可以把一个指针转换成一个整数,也可以把一个整数转换成一个指针。Reinterpret的含义就是"重新解释〞。reinterpret_cast"通常为操作数的位模式提供较低层的重新解释〞,也就是说将数据以二进制存在形式的重新解释。比方:
char
*p
=
"This
is
a
e*ample.";
int
i
=
reinterpret_cast<int>(p);
此时结果,i与p的二进制值是完全一样的,但解释不同:reinterpret_cast的作用是说将字符指针p的值以二进制〔位模式〕的方式被解释为整型,并赋给i,一个明显的现象是在转换前后没有数位损失。实际编程中,不推荐使用reinterpret_cast。〔4〕const_cast
用法:const_cast<TypeName>(e*pression)
该运算符用来去除e*pression中的const或volatile属性。常见的转换是:常量指针被转化成非常量指针,并且仍然指向原来的对象;常量引用被转换成非常量引用,并且仍然指向原来的对象;常量对象被转换成非常量对象。例如:
classB{
public:inta;}
voidfoo(){
constBb1;
b1.a=100;//ileerror
Bb2=const_cast(b1);//fine
b2.a=200;}
上面的代码编译时会报错,因为b1是一个常量对象,不能对它进展改变;但使用const_cast把它转换成一个非常量对象,就可以对它的数据成员任意改变。C++另一个不常用的关键字mutalbe有时可以替代const_cast的作用,mutalbe的中文意思是"可变的,易变的〞,跟constant〔const〕是反义词。在C++中,mutable也是为了突破const的限制而设置的。被mutable修饰的变量,将永远处于可变的状态量。mutalbe常用在以下的成员函数内:classA{private:inta;public:voidfun()const//{//含有修改类成员a的代码}}以前讲过,voidfun()const这种形式的函数,内部不允许修改类的成员变量,但有时又确实需要,这时可把inta声明为mutalbeinta。5.typeid操作符〔使用RTTI〕typeid可以在运行时进展类型判断,表达式形如:
typeid(e*pression);e*pression是任意表达式或者类型名。如果表达式的类型是类类型且至少包含有一个虚函数〔可以RTTI〕,则typeid操作符返回表达式的动态类型,需要在运行时计算;否则,typeid操作符返回表达式的静态类型,在编译时就可以计算。
typeid操作符的返回结果是名为type_info的标准库类型的对象的引用〔在头文件typeinfo中定义〕。C++标准并没有确切定义type_info,它确实切定义是与编译器相关的,但是标准却规定了其实现必需提供如下四种操作:
t1==t2
如果两个对象t1和t2类型一样,则返回true;否则返回false
t1!=t2
如果两个对象t1和t2类型不同,则返回true;否则返回false
()
返回类型的C-style字符串,类型名字用系统相关的方法产生
t1.before(t2)
返回指出t1是否出现在t2之前的bool值type_info类提供了public虚析构函数,以使用户能够用其作为基类。它的默认构造函数和拷贝构造函数及赋值操作符都定义为private,所以不能定义或复制type_info类型的对象。程序中创立type_info对象的唯一方法是使用typeid操作符〔由此可见,如果把typeid看作函数的话,其应该是type_info类的友元〕。type_info的name成员函数返回C-style的字符串,用来表示相应的类型名。下面看一个例子〔同学们可以自已上机看运行结果,不同的编译器运行结果可能不同〕:#include<iostream>usingnamespacestd;classBase{};classDerived:publicBase{};intmain(){
cout<<typeid(int).name()<<endl
<<typeid(unsigned).name()<<endl
<<typeid(long).name()<<endl
<<typeid(unsignedlong).name()<<endl
<<typeid(char).name()<<endl
<<typeid(unsignedchar).name()<<endl
<<typeid(float).name()<<endl
<<typeid(double).name()<<endl
<<typeid(string).name()<<endl
<<typeid(B
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 二零二五年度财务会计人员劳动合同规范(含财务报表分析)2篇
- 个人技术入股合同
- 地房购房合同范本
- 商铺租赁免租合同范例
- 企业仓储运输合同范例
- 劳动合同范本化工
- 公司借贷英文合同范本
- 卖小产权合同范例
- 地暖回填合同范本
- 商铺委托经营合同范本
- 2023年菏泽医学专科学校单招综合素质模拟试题及答案解析
- 铝合金门窗设计说明
- 常见食物的嘌呤含量表汇总
- 小学数学-三角形面积计算公式的推导教学设计学情分析教材分析课后反思
- 人教版数学八年级下册同步练习(含答案)
- SB/T 10752-2012马铃薯雪花全粉
- 2023年湖南高速铁路职业技术学院高职单招(英语)试题库含答案解析
- 秦晖社会主义思想史课件
- 积累运用表示动作的词语课件
- 机动车登记证书英文证书模板
- 质量管理体系基础知识培训-2016
评论
0/150
提交评论