标准转换

  C++ 语言定义其基础类型之间的转换。 它还定义指针、引用和指向成员的指针派生类型的转换。 这些转换称为“标准转换。

1. 整型提升

  整数类型的对象可以转换为另一个更宽的整数类型(即,可表示更大的一组值的类型)。 这种扩展类型的转换称为“整型提升”。 利用整型提升,您可以在可使用其他整数类型的任何位置将以下项用于表达式:

  • char 和 short int 类型的对象、文本和常量

  • 枚举类型

  • int 位域

  • 枚举器

  C++ 提升是“值保留”。 即,提升后的值一定与提升前的值相同。 在值保留提升中,如果 char 可以表示原始类型的完整范围,较短的整数类型的对象(如 int 类型的位域或对象)将提升到 int 类型。 如果 int 无法表示完整范围的值,该对象将提升到 unsigned int 类型。 尽管此策略与 ANSI C 中使用的相同,但值保留转换不保留对象的“符号”。

  值保留提升和保留符号的提升通常会生成相同的结果。 但是,如果提升的对象是以下项之一,它们可能生成不同的结果:

  • /、%/=%=、<、<=、> 或 >= 的操作数

    这些运算符依赖于用于确定结果的符号。 因此,当值保留和符号保留提升应用于这些操作数时,它们将生成不同的结果。

  • >> 或 >>= 的左操作数

    当执行移位运算时,这些运算符会区别对待有符号的数量和无符号的数量。 对于有符号的数量,将数量右移会导致符号位传播到空出的位位置。 对于无符号的数量,空出的位位置将由零填充。

  • 重载函数的参数,或重载运算符的操作数(取决于该操作数的用于参数匹配的类型的符号)。

2. 整型转换

  整型转换在整型之间执行。 整型包括 charint 和 long(以及这些类型的 short、signed 和 unsigned 版本)

  (1)有符号转换为无符号

  有符号整数类型的对象可以转换为对应的无符号类型。 当这些转换发生时,实际位模式不会更改;但是,数据的解释会更改。

// conve__pluslang_Converting_Signed_to_Unsigned.cpp
// compile with: /EHsc
#include <iostream> using namespace std;
int main()
{
short i = -;
unsigned short u; cout << (u = i) << "\n";
}
// Output: 65533

  在前面的示例中,signed short i 被定义和初始化为负数。 表达式 (u = i) 导致 i 在为 赋值前转换为 uunsigned short。

  

  (2)无符号转换为有符号

  无符号整数类型的对象可以转换为对应的有符号类型。 但是,如果无符号对象的值在有符号类型表示的范围之外,则此类转换可能导致数据错误解释,如以下示例所示:

// conve__pluslang_Converting_Unsigned_to_Signed.cpp
// compile with: /EHsc
#include <iostream> using namespace std;
int main()
{
short i;
unsigned short u = ; cout << (i = u) << "\n";
}
//Output: -3

  在前面的示例中,u 是一个 unsigned short 整数对象,必须将其转换为有符号的数量来计算表达式 (i = u)。 由于其值无法在 signed short 中正确表示,因此数据被错误解释。

3. 浮点转换

    浮动类型的对象可以安全地转换为更精确的浮点类型,也就是说,转换不会导致基数丢失。 例如,从 float 到 double 或从 double 到 long double的转换是安全的,并且值保持不变

如果浮点类型的对象位于低精度类型可表示的范围中,则还可转换为该类型。 (有关浮点类型的范围,请参阅浮点限制。) 如果原始值不能精确地表示,则可将其转换为下一更高或更低的可表示值。 如果此类值不存在,则结果是不确定的。

4. 整型和浮点型之间的转换(有截断误差)

  某些表达式可能导致浮点型的对象转换为整型,反之亦然。 当整型对象转换为浮点型且无法正确表示原始值时,结果要么是下一个较大的可表示值,要么是下一个较小的可表示值。

  当浮点型的对象转换为整型时,小数部分将被截断。 转换过程中不会进行舍入。 截断意味着,数字 1.3 将转换为 1,–1.3 将转换为 –1。

5、 算术转换

  很多二元运算符(在带二元运算符的表达式中有讨论)会导致操作数转换并以相同的方式产生结果。 这些运算符导致转换的方式称为“常用算术转换”。 不同本机类型的操作数的算术转换按下表所示的方式执行。 Typedef 类型的行为方式基于其基础本机类型。

其中一个操作数是 long double 类型。 另一个操作数将转换为 long double 类型。
未满足上述条件,并且其中一个操作数是 double 类型。 另一个操作数将转换为 double 类型。
未满足上述条件,并且其中一个操作数是 float 类型。 另一个操作数将转换为 float 类型。
未满足上述条件(没有任何一个操作数属于浮动类型)。 整型提升按以下方式对操作数执行:

- 如果其中一个操作数是 unsigned long 类型,则另一个操作数将转换为 unsigned long 类型。
- 如果未满足上述条件,并且其中一个操作数是 long 类型,另一个操作数是 unsigned int 类型,则两个操作数都将转换为 unsigned long 类型。
- 如果未满足上述两个条件,并且其中一个操作数是 long 类型,则另一个操作数将转换为 long 类型。
- 如果未满足上述三个条件,并且其中一个操作数是 unsigned int 类型,则另一个操作数将转换为 unsigned int 类型。
- 如果上述条件均未满足,则两个操作数都将转换为 int 类型。

6. 指针转换

  在赋值、初始化、比较和其他表达式中,可以转换指针。

  (1)指向类的指针

  在两种情况下,指向类的指针可转换为指向基类的指针。

  第一种情况是指定的基类可访问且转换是明确的。

  基类是否可访问取决于派生中使用的继承的类型。 考虑下图中阐释的继承。

  

  下表显示针对该图阐释的情况的基类可访问性。

  由表中可知:

  •   直接从派生类指针转换成父类指针,只能有时Public继承,才能合法转换为父类指针;
  •   在子类内部, 直接将 (A*)this,即不管继承方式,都可以合法转换使用,且根究A的成员访问属性,以及继承方式访问特定函数。
  •   在子子类内部, 因为B private 继承了A, 则限制了再子子C中的访问,因此该情况无效。
函数的类型 派生

B* 到 A* 的转换是否合法?

外部(非类范围)函数 Private No
  Protected No
  Public
B 成员函数(在 B 范围内) Private
  Protected
  Public
C 成员函数(在 C 范围内) Private No
  Protected
  Public

  第二种情况是,在您使用显式类型转换时,指向类的指针可转换为指向基类的指针。只能访问由基类的属性。

  此类转换的结果是指向完全由基类描述的对象部分(即“子对象”)的指针。

  以下代码定义了两个类(即 A 和 B),其中 B 派生自 A。 (有关继承的详细信息,请参阅派生类。) 然后定义 bObject、类型 B 的对象和两个指向该对象的指针(pA 和 pB)。

// conve__pluslang_Pointers_to_Classes.cpp
// C2039 expected
class A
{
public:
int AComponent;
int AMemberFunc();
}; class B : public A
{
public:
int BComponent;
int BMemberFunc();
};
int main()
{
B bObject;
A *pA = &bObject;
B *pB = &bObject; pA->AMemberFunc(); // OK in class A
pB->AMemberFunc(); // OK: inherited from class A
pA->BMemberFunc(); // Error: not in class A
}

  指针 pA 的类型为 A *,它可解释为“指向类型 A 的对象的指针”。 bObject ( 的成员(如 BComponent 和 BMemberFunc)对类型 B 是唯一的,并且无法通过 pA 进行访问。 pA 指针只允许访问类 A 中定义的对象的那些特性(成员函数和数据)。

7. 指向函数的指针

  如果类型 void * 足以保留指向函数的指针,则该指针可以转换为 void * 类型。指向函数的指针可以转化成为void*

8 指向 void 的指针

  指向 void 类型的指针可以转换为指向其他任何类型的指针,但仅适合于显式类型转换(与在 C 中的情况不同)。

   指向任何类型的指针可以隐式转换为指向类型 void 的指针。指向类型的不完整对象的指针可以转换为指向 void(隐式)和 back(显式)的指针。 此类转换的结果与原始指针的值相等。 对象被视为是不完整的(如果已声明对象),但未提供足够多的可用信息,无法确定其大小或基类。

  指向不是 const 或 volatile 的任何对象的指针可以隐式转换为 void * 类型的指针。

9. 固定和可变指针

  C++ 将不会应用从 const 或 volatile 类型到不是 const 或 volatile 类型的标准转换。 但是,任何类型的转换都可以用显式类型强制转换指定(包括不安全的转换)。

  指向成员的 C++ 指针(指向静态成员的指针除外)与常规指针不同,二者具有不同的标准转换。 指向静态成员的指针是普通指针,且与普通指针具有相同的转换。

10  null 指针转换

  计算结果为零的整数常量表达式

  或到某个指针类型的此类表达式强制转换,将转换为称为“null 指针”的指针。 此指针与指向任何有效对象或函数的指针比较的结果肯定不会相等(指向基对象的指针除外,此类指针可以有相同的偏移量并且仍指向不同的对象)。

  在 C++11 中, nullptr 类型应优先于 C 样式 null 指针

11  指针表达式转换

  带数组类型的所有表达式都可以转换为同一类型的指针。 转换的结果是指向第一个数组元素的指针。 下面的示例演示了这样的转换:

char szPath[_MAX_PATH]; // Array of type char.
char *pszPath = szPath; // Equals &szPath[0].

12 引用转换

  对类的引用可在以下情况下转换为对基类的引用:

  • 指定的基类是可访问的(如指向类的指针中定义的那样)。

  • 转换是明确的。 (有关不明确的基类引用的详细信息,请参阅多个基类。)

  转换的结果为指向表示基类的子对象的指针。

13 指向成员的指针

  指向可在赋值、初始化、比较和其他语句中转换的类成员的指针。

  

14  指向基类成员的指针

  当满足以下条件时,指向基类的成员的指针可以转换为指向派生自基类的类的成员的指针:

  • 从指向派生类的指针到基类指针的反向转换可以访问。

  • 派生类并非以虚拟方式从基类继承。【因为虚拟方式继承,函数属于子类,而非父类】

  当左操作数是指向成员的指针时,右操作数必须是 pointer-to-member 类型或计算结果为 0 的常量表达式。 此赋值仅在以下情况下有效:

  • 右操作数是指向与左操作数相同的类的成员的指针。

  • 左操作数是指向以公共但不明确的方式派生自右操作数的类的成员的指针。

15. 整数常量转换

  计算结果为零的整数常量表达式将转换为名为“null 指针”的指针。 此指针与指向任何有效对象或函数的指针比较的结果肯定不会相等(指向基对象的指针除外,此类指针可以有相同的偏移量并且仍指向不同的对象)。

以下代码演示了指向类 i 中的成员 A 的指针的定义。 指针 pai 将初始化为 0,因此是 null 指针。

// conve__pluslang_Integral_Constant_Expressions.cpp
class A
{
public:
int i;
}; int A::*pai = ; int main()
{
}
因为:

endl.

C++语言定义的标准转换的更多相关文章

  1. C++标准转换运算符

    C++类型转换在实际编程中会经常使用,其实,本质上对象的类型用来解释(interpret)对象.因为,每个对象都占据一块内存空间,这块内存空间存放了一段二进制数据.通过标记该对象的类型,告诉如何看待这 ...

  2. C++标准转换运算符reinterpret_cast

    C++标准转换运算符reinterpret_cast reinterpret_cast <new_type> (expression) reinterpret_cast运算符是用来处理无关 ...

  3. C++标准转换运算符 --四种

    具体归纳如下: reinterpret_cast 函数将一个类型的指针转换为另一个类型的指针. 这种转换不用修改指针变量值存放格式(不改变指针变量值),只需在编译时重新解释指针的类型就可做到.rein ...

  4. C语言指针类型 强制转换

    关于C语言指针类型 强制转换  引用一篇文章: C语言中,任何一个变量都必须占有一个地址,而这个地址空间内的0-1代码就是这个变量的值.不同的数据类型占有的空间大小不一,但是他们都必须有个地址,而这个 ...

  5. Java语言定义的线程状态分析

    说到线程,一定要谈到线程状态,不同的状态说明线程正处于不同的工作机制下,不同的工作机制下某些动作可能对线程产生不同的影响. Java语言定义了6中状态,而同一时刻,线程有且仅有其中的一种状态.要获取J ...

  6. 自己定义View Controller转换动画

    原文链接 : Introduction to Custom View Controller Transitions and Animations 原文作者 : joyce echessa 译文出自 : ...

  7. C语言定义数组时使用枚举作为数组的下标 ——c99功能

    部分参考了https://blog.csdn.net/wq3028/article/details/76204690 同时在电脑上进行验证 //温度,电磁阀传感器序号,方便数组定位 typedef e ...

  8. Go语言系列之标准库log

    Go语言内置的log包实现了简单的日志服务.本文介绍了标准库log的基本使用. 使用Logger log包定义了Logger类型,该类型提供了一些格式化输出的方法.本包也提供了一个预定义的" ...

  9. shell编程:定义简单标准命令集

    shell是用户操作接口的意思,操作系统运行起来后都会给用户提供一个操作界面,这个界面就叫shell,用户可以通过shell来调用操作系统内部的复杂实现,而shell编程就是在shell层次上进行编程 ...

随机推荐

  1. PAT 1001 害死人不偿命的(3n+1)猜想 (15)(C++&JAVA&Python)

    1001 害死人不偿命的(3n+1)猜想 (15)(15 分) 卡拉兹(Callatz)猜想: 对任何一个自然数n,如果它是偶数,那么把它砍掉一半:如果它是奇数,那么把(3n+1)砍掉一半.这样一直反 ...

  2. redis 数据类型为string命令整理以及示例

    #设置值 SET key value [EX seconds] [PX milliseconds] [NX|XX] SET命令加上选项已经可以完全取代SETNX, SETEX, PSETEX的功能,所 ...

  3. eclipse自动添加javadoc注释

    参考文档: https://jingyan.baidu.com/article/36d6ed1f70ea9c1bce488350.html https://www.cnblogs.com/yangji ...

  4. vue 设置button disabled

    <button v-bind:disabled="dis" @click="alert">button</button> dis:'' ...

  5. connect: Address is invalid on local machine or port is not valid on remote

    idea 运行正常打成jar包运行提示“connect: Address is invalid on local machine or port is not valid on remote” , 解 ...

  6. barcode(index)

    在很多情况下,我们需要把多个样本混合在一起,在同一个通道(lane)里完成测序.像转录组测序.miRNA测序.lncRNA测序.ChIP测序等等,通常每个样本所需要的数据量都比较少,远少于HiSeq一 ...

  7. SpringBoot 多环境配置

    转载:https://www.cnblogs.com/gdpuzxs/p/7191436.html 在我们的实际开发中,一般都有三套环境,开发环境,测试环境,生产环境,三套环境的数据库连接配置也有所不 ...

  8. 关于SSH中tomcat下中文名称图片不显示的问题

    最近做一个SSH框架的项目,用tomcat发布,需要上传图片到指定路径,然后再将图片显示在页面上.有一个问题:如果是英文名称的图片,就正常显示,可如果是中文的,它就是显示不出来,于是乎,在网上各种百度 ...

  9. 【转】centos7 搭建etcd集群

    转自http://www.cnblogs.com/zhenyuyaodidiao/p/6237019.html 一.简介 “A highly-available key value store for ...

  10. Python中subprocess 模块 创建并运行一个进程

     python的subprocess模块,看到官方声明里说要尽力避免使用shell=True这个参数,于是测试了一下: from subprocess import call import shlex ...