显式转换:显式将一种类型转换为另一种类型。

References:

C++中的显示数据类型转换

与命名的强制类型转换相比,旧式的强制类型转换从表现形式上来说不那么清晰明了,容易被看漏,所以一旦转换过程出现问题,追踪起来也更加困难。

C++ 引入新的强制类型转换机制,主要是为了克服C语言强制类型转换的以下三个缺点:

  1. 没有从形式上体现转换功能和风险的不同。

例如,将 int 强制转换成 double 是没有风险的,而将常量指针转换成非常量指针,将基类指针转换成派生类指针都是高风险的,而且后两者带来的风险不同(即可能引发不同种类的错误),C语言的强制类型转换形式对这些不同并不加以区分。

  1. 将多态基类指针转换成派生类指针时不检查安全性,即无法判断转换后的指针是否确实指向一个派生类对象。

  2. 难以在程序中寻找到底什么地方进行了强制类型转换。

一、static_cast

是一种静态的转换,在编译期就能确定的转换,可以完成C语言中的强制类型转换中的大部分工作,但需要注意的是,它不能转换掉表达式的 const、volitale 或者 __unaligned 属性。

  1. 将较大的算术类型转换为较小的算术类型

double slope = static_cast<double>(j)/i;

相当于 (double)j/i

#include <iostream>
using namespace std;
class A
{
public:
operator int() { return 1; }
operator char*() { return NULL; }
};
int main()
{
A a;
int n;
char* p = "New Dragon Inn";
n = static_cast <int> (3.14); // n 的值变为 3
n = static_cast <int> (a); //调用 a.operator int,n 的值变为 1
p = static_cast <char*> (a); //调用 a.operator char*,p 的值变为 NULL
n = static_cast <int> (p); //编译错误,static_cast不能将指针转换成整型
p = static_cast <char*> (n); //编译错误,static_cast 不能将整型转换成指针
return 0;
}

一般来说,如果编译器发现一个较大的算术类型试图赋值给较小的类型,就会给出警告信息;但是当我们执行了显式的类型转换后,警告信息就会被关闭了。

  1. 添加const: 将非const转换为const。

  2. 将表达式转换成void类型,并将转换后的结果丢弃

int val = 110;
static_cast<void>(val);
  1. static_cast对于编译器无法自动执行的类型转换也非常有用, 可以用于void*和其他指针类型之间的转换。例如,我们可以使用static_cast找回存在于void*指针中的值。

void* p = &d; //任何非常量对象的地址都能存入void*
double* dp = static_cast<double*>(p);
  1. static_cast 不能用于在不同类型的指针之间(如char*与int*之间)互相转换,也不能用于整型和指针之间的互相转换,当然也不能用于不同类型的引用之间的转换。因为这些属于风险比较高的转换。

  2. 可以用于类继承结构中基类和派生类之间指针或引用的转换向上转型安全,向下转型由于没有动态类型检查,是不安全的。

  3. 如果涉及左值到右值、数组到指针或函数到指针的转换,也可以通过static_cast显式执行

std::move()的实现

二、dynamic_cast

适用于以下情况:我们想使用基类对象的指针或引用执行某个派生类操作并且该操作不是虚函数。

相比于 static_cast 的编译时转换, dynamic_cast 的转换还会在运行时进行类型检查,转换的条件也比较苛刻,必须有继承关系的类之间才能转换,并且在基类中有虚函数才可以,有一种特殊的情况就是可以把类指针转换成 void* 类型。

不能用于基本类型。

  1. RTTI:

实现运行时类型识别。运行时类型识别(run-time type identification,RTTI)的功能由两个运算符实现:

  • typeid运算符,用于返回表达式的类型。
  • dynamic_cast运算符,用于将基类的指针或引用安全地转换成派生类的指针或引用。
  1. dynamic_cast 用于在类的继承层次之间进行类型转换,它既允许向上转型(Upcasting),也允许向下转型(Downcasting)。 ** 可用于将基类的指针或引用安全地转换成派生类的指针或引用**。

  2. 有三种使用形式:

type通常应该是一个类类型,通常情况下应该含有虚函数。

e的类型必须符合以下三个条件中的任意一个:e的类型是目标type的公有派生类、e的类型是目标type的公有基类或者e的类型就是目标type的类型。如果符合,则类型转换可以成功。否则,转换失败。

  • dynamic_cast<type*>(e) //e必须是一个有效的指针;
  • dynamic_cast<type&>(e) //e必须是一个左值;
  • dynamic_cast<type&&>(e) //e不能是左值;
  1. 在横向转换时指针发生了变化,可以看出 dynamic_cast 不是简单的数据强转,还进行了指针的偏移。

三、const_cast

将常量对象转换为非常量对象的行为:cast away the const. 实现有时需要对const对象进行修改。

  1. const_cast 比较好理解,它用来去掉表达式的 const 修饰或 volatile 修饰。换句话说,const_cast 就是用来将 const/volatile 类型转换为非 const/volatile 类型。只有const_cast可以改变常量表达式的常量属性。

  2. const_cast 不能去除变量的常量性,只能用来去除指向常数对象的指针或引用的常量性,且去除常量性的对象必须为指针或引用。

#include <iostream>
using namespace std; int main(void) {
const int d = 2;
int* a = const_cast<int*>(&d);
*a = 3;
cout<<d<<endl;
return 0;
}

输出为:

2

这是因为使用变量d的语句在编译期就被替换为了2。

  1. 将 const 引用转换为同类型的非 const 引用,将 const 指针转换为同类型的非 const 指针时可以使用 const_cast 运算符
#include <iostream>
using namespace std; int main(void) {
int d = 2;
const int* a = &d;
int* b = const_cast<int*>(a);
cout<<*a<<endl;
cout<<*b<<endl;
*b = 3;
cout<<*a<<endl;
cout<<*b<<endl;
return 0;
}

输出:

2
2
3
3

四、 reinterpret_cast

  1. reinterpret_cast被用于不同类型指针或引用之间的转换,或者指针和整数之间的转换, 是对运算对象的二进制位的重新解释。
  • 不同基础类型指针类型之间转换
int* ip;
char* pc = reinterpret_cast<char*>(ip);

我们必须牢记pc所指的真实对象是一个int而非字符,如果把pc当成普通的字符指针使用就可能在运行时发生错误。

  • 基础类型指针与类对象指针之间的转换

  • 将地址值转换成整数

  1. reinterpret_cast本质上依赖于机器。要想安全地使用reinterpret_cast必须对涉及的类型和编译器实现转换的过程都非常了解。

summary

  1. C/C++中不同数据类型进行运算或者赋值的时候会发生数据转换,这种转换有些是自动进行的,有些需要进行显示的强制类型转换
  2. 在C语言中强制类型转换写成(new_type_name) expression的形式,new_type_name 是要转换的目标类型,expression 是待转换的表达式
  3. 在C++中强制类型转换通过更明显的关键字来完成,分别是static_cast、 dynamic_cast, const_cast、 和 reinterpret_cast
  4. static_cast 是静态转换,在编译期完成完成转换,与C语言中的强制类型转换重合度最高
  5. dynamic_cast 是动态转换,在运行时转换会进行检查,必须用在有继承关系的多态结构中
  6. const_cast 是常量转换,用于取出指针或引用的常量属性,但是尽量通过设计杜绝它的使用场景
  7. reinterpret_cast 是一种内存数据的重新解释,比较原始,开发者使用它的时候应该明确的知道自己在做什么

    ————————————————

版权声明:本文为CSDN博主「AlbertS」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/albertsh/article/details/118663176

c++ 命名的强制类型转换的更多相关文章

  1. C++ Primer 有感(命名的强制类型转换)

    C++四种强制类型转换的方法以及其应用场合,之前有看过这个知识点,但是,面试的时候怎么想也就没有写的很全面,于是,这里整理一下: C++中的四种强制类型转换除了具有C语言强制类型转换的功能外,还可提供 ...

  2. C++的几种强制类型转换

    有时我们希望显式地将对象强制类型转换成另外一种类型.例如,如果想在下面的代码中执行浮点数除法: int i, j; double slope = i / j; 就要使用某种方法将i和/或j显式地转换成 ...

  3. 小猪猪逆袭成博士之C++基础篇(一)数据精度、强制类型转换、变量命名规则

    小猪猪逆袭成博士之C++基础篇(一) 关键词: 数据精度.强制类型转换.变量命名规则 综述: 1.大多数编程语言通过两种方式来进一步补充其特征:一是赋予程序员自定义数据类型的权利(C++中的类):二是 ...

  4. 【JAVA】笔记(1)---JVM内存图;方法重载条件;输入方法;转义字符;强制类型转换;变量分类及区别;Java命名规范;

    Java命名规范: 1.包:全部字母小写: 2.类+接口:所有单词的首字母大写: 3.变量+方法:第一个单词的首字母小写,其余单词首字母大写: 3.常量名:所有字母均大写,且用下划线" _ ...

  5. C++开发必看 四种强制类型转换的总结 [转]

    一.C风格的强制类型转换(Type Cast)很简单,不管什么类型的转换统统是:     TYPE b = (TYPE)a 二.C++风格的类型转换提供了4种类型转换操作符来应对不同场合的应用. co ...

  6. C++开发必看 四种强制类型转换的总结

    C风格的强制类型转换(Type Cast)很简单,不管什么类型的转换统统是: TYPE b = (TYPE)a C++风格的类型转换提供了4种类型转换操作符来应对不同场合的应用. const_cast ...

  7. c++的四种强制类型转换

    http://hb.qq.com/a/20110722/001452.htm ...... C风格的强制类型转换(Type Cast)很简单,不管什么类型的转换统统是:TYPE b = (TYPE)a ...

  8. 四种强制类型转换的总结(const_cast、static_cast、dynamic_cast、reinterpreter_cast)

    四种强制类型转换的总结(const_cast.static_cast.dynamic_cast.reinterpreter_cast) 转载 2011年10月03日 23:59:05 标签: stru ...

  9. C++中的关键字用法--- 四种强制类型转换的总结

    四种强制类型转换的总结(const_cast.static_cast.dynamic_cast.reinterpreter_cast 1. C风格的强制类型转换(Type Cast)很简单,不管什么类 ...

  10. 040_字符串连接符 041_条件运算符目 042_运算符优先级_逻辑与或优先问题 043_自动类型转化 044_强制类型转换 045_基本类型常见错误_溢出_L问题

    040_字符串连接符 package test_package; /** * 字符串运算符 * @author * */public class TestOperator05 { public sta ...

随机推荐

  1. SpringBoot Maven查看依赖树

    dependency:tree -f pom.xml

  2. Oracle 触发器 before insert update

    场景,往A表插入数据时,A表和B表是同一类型的状态下,A表中累计的值,不能超过B表中的值(注:往数据库插入时,不能批量执行事务!),利用触发器before insert update,监控状态,若超过 ...

  3. PowerBuilder编程新思维10.5:外传2(PowerPlume下一代开发解决方案)

    万里归来年愈少 PB编程新思维10.5:外传2(PowerPlume下一代解决方案) 前言 今天我们就来盘点一下,PB下一代开发的所有技术可能性.所谓下一代开发技术,就是指脱离或半脱离PBVM的应用开 ...

  4. 说说RabbitMQ延迟队列实现原理?

    使用 RabbitMQ 和 RocketMQ 的人是幸运的,因为这两个 MQ 自身提供了延迟队列的实现,不像用 Kafka 的同学那么苦逼,还要自己实现延迟队列.当然,这都是题外话,今天咱们重点来聊聊 ...

  5. Doris failed to initialize storage reader. tablet=106408, res=[NOT_IMPLEMENTED_ERROR]to be implemented

    Apache Doris 2.3 以下的版本会存在一个 bug,导致数据在合并时存在异常,在后续查询该字段数据时会提示 [1105] [HY000]: errCode = 2, detailMessa ...

  6. 那些血淋淋的教训——math

    1. 方程的解要写 x= 2023.12.10 晚上周测填空题第 \(2\) 题,方程的解写成了 \(7\) 而不是 \(x=7\). 2. 分类讨论 选填的最后一题. 3. 去绝对值看清楚符号(某个 ...

  7. OpenGL之ShadowMap

    流程:先创建一个RenderTexture,然后用灯光的视口渲染. 然后切换到正常相机,进行渲染,使用RenderTexture中的深度或者颜色纹理,然后还原当前顶点在灯光中的深度,两者对比,比缓存中 ...

  8. 基于Hive的大数据分析系统

    1.概述 在构建大数据分析系统的过程中,我们面对着海量.多源的数据挑战,如何有效地解决这些零散数据的分析问题一直是大数据领域研究的核心关注点.大数据分析处理平台作为应对这一挑战的利器,致力于整合当前主 ...

  9. 【WSDL】02 四种客户端调用方式

    WSDL概念和一些语法内容: https://www.w3school.com.cn/wsdl/index.asp SOAP概念: https://www.runoob.com/soap/soap-t ...

  10. 【Linux】真机安装CentOS8

    先制作启动U盘 https://www.cnblogs.com/mindzone/p/12961506.html 插入电脑,开机[这里我是把电脑硬盘格式化了,不会在电脑磁盘上找到任何系统,直接跳到启动 ...