C++语言定义的标准转换

标准转换

  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 = -3;
    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 = 65533;  

 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 = 0;  

int main()
{
}  因为: 

endl.

原文地址:https://www.cnblogs.com/icmzn/p/9162073.html

时间: 2024-11-05 18:29:01

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

阶段1 语言基础+高级_1-2 -面向对象和封装_18定义一个标准的类

做一个综合的练习 如何定义一个标准的学生类 向下选择getter和setter 选中这两个 这样就自动出现了get和set的方法 生成构造方法 无参的 运行测试 全参的方式 set修改年龄 原文地址:https://www.cnblogs.com/wangjunwei/p/11198197.html

C语言---整型字符串转换

C语言提供了几个标准库函数,能够将随意类型(整型.长整型.浮点型等)的数字转换为字符串.下面是用itoa()函数将整数转 换为字符串的一个样例: # include <stdio.h>    # include <stdlib.h> void main (void)    {    int num = 100;    char str[25];    itoa(num, str, 10);    printf("The number ’num’ is %d and the

C++标准转换运算符dynamic_cast

dynamic_cast <new_type> (expression) dynamic_cast运算符,应该算是四个里面最特殊的一个,因为它涉及到编译器的属性设置,而且牵扯到的面向对象的多态性跟程序运行时的状态也有关系,所以不能完全的使用传统的转换方式来替代.但是也因此它是最常用,最不可缺少的一个运算符. 与static_cast一样,dynamic_cast的转换也需要目标类型和源对象有一定的关系:继承关系. 更准确的说,dynamic_cast是用来检查两者是否有继承关系.因此该运算符实

C语言 字符串和数字转换函数

atof(将字符串转换成浮点型数) 相关函数 atoi,atol,strtod,strtol,strtoul 表头文件 #include <stdlib.h> 定义函数 double atof(const char *nptr); 函数说明 atof()会扫描参数nptr字符串,跳过前面的空格字符,直到遇上数字或正负符号才开始做转换,而再遇到非数字或字符串结束时('\0')才结束转换,并将结果返回.参数nptr字符串可包含正负号.小数点或E(e)来表示指数部分,如123.456或123e-2.

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

说到线程,一定要谈到线程状态,不同的状态说明线程正处于不同的工作机制下,不同的工作机制下某些动作可能对线程产生不同的影响. Java语言定义了6中状态,而同一时刻,线程有且仅有其中的一种状态.要获取Java线程的状态可以使用 java.lang.Thread类中定义的 getState()方法,获取当前线程的状态就可以使用Thread.currentThread().getState()来获取.该方法返回的类型是一个枚举类型,是Thread内部的一个枚举,全称为“java.lang.Thread

C语言定义一个整型变量转换为2进制数并输出出来

#include<stdio.h> int main() {     int a=12;       //定义一个需要转换的整型     char b[50];    //保存转化后到数组里面     _itoa_s(a,b,50,2);//转化为二进制     printf("%s\n",b);      //输出字符串 } 

语言定义的其他示例

在本章的以后部分,我们会看到有关如何解析简单的算术语言的两个扩展示例.第一个用fslex.exe 和 fsyacc.exe 实现,第二个用开源的解析库 FParsec.这种语言与前一章的非常相似,语言规范完全相同,有四则运算,只是不再使用连接符(combinator),语言本身有文字格式 *.+./.- 来表示运算.扩展的巴氏范式(Extended Backus–Naur Form,EBNF),用下面的代码定义这种语言: digit     = "1"| "2"|

自己定义隐式转换和显式转换c#简单样例

自己定义隐式转换和显式转换c#简单样例 (出自朱朱家园http://blog.csdn.net/zhgl7688) 样例:对用户user中,usernamefirst name和last name进行转换成合成一个限定长度为10个字符新name. 自己定义隐式转换: namespace transduction { public partial class transductionForm : Form { public transductionForm() { InitializeCompon

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

shell是用户操作接口的意思,操作系统运行起来后都会给用户提供一个操作界面,这个界面就叫shell,用户可以通过shell来调用操作系统内部的复杂实现,而shell编程就是在shell层次上进行编程,如Linux中的脚本编程. shenll运行原理:由消息接收.解析.执行构成的死循环. 命令行shell:该死循环包含3个模块(命令接收.命令解析.命令执行),命令行有一个标准命令集,用户输入的命令若不是标准命令,则提示用户这不是一个合法命令行,然后重新回到命令行让用户输入下一个命令. 常见的sh