上次说了关于表达式的一些内容,说到还有一些关于数据类型转换的内容,今天我们接着八一八C++中的数据类型转换。

一、隐式类型转换

  在表达式中,有些操作符可以对多种类型的操作数进行操作, 例如 + 操作符的操作数可以同时有int型,也可以有float型, 这就引入了一个问题到底应该由什么

决定表达式的值的类型。 例如:

  3.1415926 + ;   //double类型  + 整型, 结果为什么类型呢??

  3.1415926 *   *   ; //double类型 * 整型  * 整型; 得到的表达式的值为什么类型呢??

   * 4UL;   // 整型 * 无符号整型  , 得到的表达式的值的类型为什么呢??

  在C++中,为了解决这类问题引入了类型转换的机制。

  

1、什么时候会发生类型转换

  A:  在具有混合类型的表达式中,会发生类型转换, 如上面的例子。

    3.14 * 4;   在计算的时候会发生类型转换,会将4转换为 4.0 然后与3.14 相乘。

  B:用作条件的表达式会被转换为bool类型

    int  iVar;
    .......
    if(iVar)
      .......

  这里当做if语句的条件表达式的 iVar 会发生类型转换,  当iVar 非零时转换为 true,  当 iVar 为0时转换为false。

  C: 当bool类型的变量、值不是 !、&&、|| 操作符的操作数时会发生类型转换

    bool  bVar;

    .......
    int iVar;
    int iResult;
    iResult = iVar + bVar; //这里bool量bVar会转换为整型

  如上所示,  bool量bVar会发生类型转换, 当bVar为真True时转换为1, 当bVar为假false时会转换0,  这样就可以参与计算。

  D:当赋值操作符的左右操作数的类型不一致时会发生类型转换

    int   iVar;

    iVar =3.1415926; //double类型的3.1415926会被转换为int型赋值给iVar;

  这里讲double类型的值转换为int型赋值给int型

  E:当其他类型的值初始化变量时会发生类型转换

  int  iVar = 3.1415926;  //赋值初始化,
或者
  int iVar(3.1415926); //直接初始化

  这里进行初始化时会将3.1415926 转换为int型,然后初始化iVar。

2、算术转换

  C++为内置的操作符和数据类型提供了一套默认的数据类型转换机制,其中最为常见的就是算术转换。 算术操作符 + 、- 、* 、/ 两个操作数的类型不一致时

就会发生数据类型转换, 在程序执行前,会将算术操作符两边的操作数转换为同一数据类型后才能进行算术操作。算术转换的基本原则就是在转换后要能保证计算的

精度。 例如如果算术操作符的操作数有一个为long double 那么就会将另外一个操作数转换为long double类型然后进行计算。

  在C语言中,会有如下基本的类型转换特点:

  注意的是float类型不会自动转换为double类型,这一点需要特别的注意。在C++中大体保持了这样一个转换规则,我们可以通过sizeof操作符来看看操作结果。

Exp:

int main()
{
cout<<"sizeof(3.14L * 2) is:"<<sizeof(.14L * )<<endl;
cout<<"sizeof(3.14 * 2 ) is:"<<sizeof(3.14 * )<<endl;
cout<<"sizeof(3.14f * 2) is:"<<sizeof(3.14f *)<<endl;
cout<<endl;
cout<<"sizeof(long int) is"<<sizeof(long int)<<endl;
cout<<"sizeof('a'*'a') is:"<<sizeof('a'*'a')<<endl;
cout<<"sizeof(2L * 2) is:"<<sizeof(2L * )<<endl; return ;
}

程序的执行结果为:

[root@localhost cpp_src]# g++ test.cpp
[root@localhost cpp_src]# ./a.out
sizeof(.14L * ) is:
sizeof(3.14 * ) is:
sizeof(3.14f * ) is: sizeof(long int) is4
sizeof('a'*'a') is:
sizeof(2L * ) is:

  总结一句就是:

    1、对于所有比int类型小的整型,在计算的过程中都会转换为int型,如果其值都包含在int内,则会将操作数转换为int型然后进行计算, 如果其值

超过了int型的表示范围,则会转换为 unsigned int型进行计算。 如果操作数中有long 型,则会转换为long类型进行计算。

    2、对于浮点型,如果有long double则会转换为long double进行计算, 如果有double类型,则会转换为double类型进行计算, 如果有float则

会转换为float类型进行计算。

  对于这个需要特别注意的就是float类型不会自动提升为double类型,这个是与整型不一样的地方。

3、关于有符号和无符号数之间的转换

  讨论的是整型的无符号数和有符号数直接的转换, 这个是C/C++语言当中的一大难点, 前面我有一篇文章讨论过这个问题。这里再重新的描述一下。

  A:  两个操作数为 unsigned short int 和 int

    如果int足够保存unsigned short int 的值,那么就会转换int进行计算,如果不能保存,那么就会转换为unsigned int 进行计算。

  B: 两个操作数为 unsigned int  和 long int

    如果long int足够保存所有的unsigned int类型的值,那么就会转换为long int进行计算,否则就转换为unsigned long  int 进行计算。

  C: 两个操作数为int 和unsigned int 

    这个地方有点需要注意,int会转换为unsigned int 后进行计算, 计算的结果为unsigned int类型,然后如果赋值给int 类型的话,那么可能出现溢出

的情况, 通过截断高位部分将unsigned int 类型的值赋值给int类型。

  这个地方一般也不太需要特别的注意,但是在一些特殊的地方则需要引起特别的关注。

4、关于指针和数组

  在我的以前的一篇随笔中曾经描述过这个问题,那就是在一般的情况下,数组(名)都可以转换为指针。例如:

  int    iArray[];

  int   *pInt = iArray;   //数组(名)转换为指针类型,然后初始化指针变量pInt

  这种转换基于下面的理念: 数组名一个数组的首地址,并且是个常量,不可改变,不可对数组名进行赋值。

  要点:

    1、sizeof(iArray) ;  这个地方,不会将数组名转换为指针。

    2、定义引用的时候,不会将数组名转换为指针

Exp:

int main()
{
int iArray[] = {,,,,};
int (& refArray)[] = iArray; cout<<"iArray[0]="<<refArray[]<<endl; return ;
}

程序的执行结果如下:

[root@localhost cpp_src]# g++ test.cpp
[root@localhost cpp_src]# ./a.out
iArray[]=

5、关于bool类型的转换规则

  其他非bool类型的内置类型如果要转换为bool值,则非零转换为真True, 0转换为假false。

  bool类型会转换int类型, true转为1, false转为0

6、枚举类型转换规则

  枚举类型是一种自定义的数据类型,通过关键字 enum来定义。枚举类型通常用来定义一些属性或者状态,比方说定义一些值表示星期, 定义一些值表示文件的

打开、关闭状态, 定义一些值表示忙、闲等等。

  A: 定义枚举类型

  语法:  enum   枚举类型名 {枚举类型可以取的值};

Exp:

  enum   open_mode  {input, output , append }  // 定义了枚举类型 Week, 这种类型的变量可以取的值为: input、output、append

   enum    open_mode  status = input;  //定义枚举类型变量 status,并初始化为input

  要注意的是定义枚举类型的变量时,关键字 enum不能省略,除非用typedef为枚举类型定义了别名。

  B:枚举类型值

  默认定义枚举类型的时候,其第一个值默认取值为0, 后面的值其值会默认增加1,

例如:

  enum  file_status  {close, open};   // 这里默认close的值为0 , open的值为1

  还可以指定这些值,

例如:

  enum  file_status  {close = 10 ,  open};   //这里 close = 10 , 而open的值为11

  

要点:

  指定枚举的值时可以有两个值相等。

  enum  Points {point2d = , point2w,

          point3d= ,   point3w};  //这一点需要引起注意, 但是一般不会这么定义枚举数据类型

  C:枚举类型的转换规则

  枚举类型可以参与计算, 可以将其值转换为int型的值, 其转换后的值,根据枚举类型的值确定。

  typedef enum open_mode  {input, output,append}  OPENMODE;

  OPENMODE eVar = input;

  int iVar =  + eVar ;  // 则eVar 转换为int型的值0 ,然后计算表达式的值

二、显示类型转换

  显示类型转换就是在程序中明确的指出类型转换规则, 这样可以覆盖系统默认的隐式转换规则。隐式转换有: dynamic_cast、static_cast、const_cast、

reinterpret_cast.

1、dynamic_cast

  支持运行时识别指针或引用执行的对象,待后续专门随笔进行介绍。

2、const_cast

  const_cast 就是将const对象的const属性强制的取消,使我们可以显示的修改对象的值。这里没有搞清楚, 不知道哪位大神,对这里理解比较透彻,请

不吝指教。

3、static_cast

  static_cast和C语言中强制类型转换一样, 只是表示方法不一样而已。 当然C++也支持C语言风格的强制类型转换。

  char  chVar = static_cast<char>();  //显示的将1234转换为char类型。

  这里要注意的static_cast后面用<> 将要转换为的数据类型表示出来,而用( )操作符将要转换的操作数括起来。

  C语言风格的强制类型转换:

  char chVar = (char);

  这里不进行过多的讨论。

4、reinterpret_cast

  reinterpret_cast通常为操作数的位模式提供重新解释的机制。

例如:

  int  iVar;

  int *pInt = &iVar;

  *pInt = ;

  char *pCh = reinterpret_cast<char *>(pInt);

  这里我们如果我们通过pCh访问内存的话, 那么系统就会将变量 iVar占用的内存 4个字节(32bit的系统)解释为char型数组;值得注意的是iVar 和 *pInt 访问

这一块内存区域的时候,还是会将这一块区域解释为int型, 就是说强制的 reinterpret_cast 并不能改变原指针指向的数据类型或者原变量的数据类型。这里特别需要

注意。

  关于类型转换暂时就这么多的内容,其他内容待续...........

C++_系列自学课程_第_11_课_类型转换_《C++ Primer 第四版》的更多相关文章

  1. C++_系列自学课程_第_7_课_数组_《C++ Primer 第四版》

    说到数组,大家应该都很熟悉,在C.Pascal.Java等语言中,都有数组的概念.在C++中也提供了对数组的支持.数组简单来说就是一堆相同 数据类型对象的集合. 这里要把握住两个要点: 相同的数据类型 ...

  2. C++_系列自学课程_第_6_课_bitset集_《C++ Primer 第四版》

    在C语言中要对一个整数的某一个位进行操作需要用到很多的技巧.这种情况在C++里面通过标准库提供的一个抽象数据类型 bitset得到了改善. 一.标准库bitset类型 1.bitset的作用 bits ...

  3. C++_系列自学课程_第_5_课_vector容器_《C++ Primer 第四版》

    再一次遇到 vector 这个单词; 每一次见到这个单词都感觉这个单词非常的 "高大上"; 数字遇到vector马上就可以360度旋转: 当 "电" 遇到vec ...

  4. C++_系列自学课程_第_3_课_变量和基本类型_《C++ Primer 第四版》

    最近复习C++相关内容,决定在这里记录自己复习的过程. 以前写过部分文字,但是没有坚持连续写,因此学完后 基本又忘光啦,主要是没有实践,这一次决定自学完后,在这里在复习一遍增强自己的记忆和理解程度. ...

  5. C++_系列自学课程_第_12_课_结构体

    #include <iostream> #include <string> using namespace std; struct CDAccount { double bal ...

  6. C++_系列自学课程_第_12_课_语句_《C++ Primer 第四版》

    前面的文章说完了表达式和类型转换的部分内容,在我参考的书里面,接下来讨论的是各种语句,包括:顺序语句.声明语句.复合语句(块语句).语句作用域 .if语句.while语句.for语句.do...whi ...

  7. C++_系列自学课程_第_10_课_表达式_《C++ Primer 第四版》

    程序设计语言中大部分程序都在进行表达式的求值操作, 例如求两个数的和,求一个表达式的逻辑结果,或者通过输入输出表达式语句进行输入和输出. 这里我们对表达式进行讨论. 一.表达式 1.表达式 表达式由一 ...

  8. C++_系列自学课程_第_9_课_C语言风格字符串_《C++ Primer 第四版》

    前面说了写关于数组和指针的内容,这次在这里讨论一下字符串,讨论一下C语言风格的字符串. 在C语言里面我们利用字符数组来对字符串进行处理, 在C++里面我们前面说过一种类类型string可以对字符串进行 ...

  9. C++_系列自学课程_第_8_课_指针和引用_《C++ Primer 第四版》

    C语言最富有迷幻色彩的部分当属指针部分,无论是指针的定义还是指针的意义都可算是C语言中最复杂的内容.指针不但提供给了程序员直接操作硬件部分的操作接口,还提供给了程序员更多灵活的用法.C++继承这一高效 ...

随机推荐

  1. C++标准库实现WAV文件读写

    在上一篇文章RIFF和WAVE音频文件格式中对WAV的文件格式做了介绍,本文将使用标准C++库实现对数据为PCM格式的WAV文件的读写操作,只使用标准C++库函数,不依赖于其他的库. WAV文件结构 ...

  2. 搭建QQ聊天通信的程序:(1)基于 networkcomms.net 创建一个WPF聊天客户端服务器应用程序 (1)

    搭建QQ聊天通信的程序:(1)基于 networkcomms.net 创建一个WPF聊天客户端服务器应用程序 原文地址(英文):http://www.networkcomms.net/creating ...

  3. Spring aop应用之实现数据库读写分离

    Spring加Mybatis实现MySQL数据库主从读写分离 ,实现的原理是配置了多套数据源,相应的sqlsessionfactory,transactionmanager和事务代理各配置了一套,如果 ...

  4. enote笔记法使用范例(2)——指针(1)智能指针

    要知道什么是智能指针,首先了解什么称为 “资源分配即初始化” what RAII:RAII—Resource Acquisition Is Initialization,即“资源分配即初始化” 在&l ...

  5. 移动BPM解决方案分享

    畅通开放  无边界的渠道 效率倍增  更高效的处理方式 即时共享  更强大的决策能力 各种终端应用 帮您实现:新任务通知.任务预警.催办.任务审批.任何数据汇总提醒消息通知...... 短信 客户端: ...

  6. 如何从本地导入.nupkg文件

    买了本asp.net mvc4高级编程 里面的源码下载下来是.nupkg后缀的文件,不知道怎么引入到项目中, baidu无果,只好google,可怜我英语四级都难的人,不过所幸还是找到了方法: htt ...

  7. Win下最爱效率利器:AutoHotKey

    AutoHotkey是一个windows下的开源.免费.自动化软件工具.它由最初旨在提供键盘快捷键的脚本语言驱动(称为:热键),随着时间的推移演变成一个完整的脚本语言.但你不需要把它想得太深,你只需要 ...

  8. [转]Fiddler抓取Android真机上的HTTPS包

    此篇文章转载自:http://blog.csdn.net/roland_sun/article/details/30078353 工作中经常会需要对一些app进行抓包, 但是每次默认都是只抓http请 ...

  9. Atitit 图像处理 调用opencv 通过java  api   attilax总结

    Atitit 图像处理 调用opencv 通过java  api   attilax总结 1.1. Opencv java api的支持 opencv2.4.2 就有了对java api的支持1 1. ...

  10. SQL Server 系列文章快速导航(SWF版)

    一.前言 在博客园写博客不自不觉已经有5个年头了,一开始只是为了记录工作中遇到的问题和解决办法,后来写的文章不自不觉的侧重在SQL Server方面的技术文章,在2014年1月终于鼓起勇气申请了微软S ...