C++四种强制类型转换:static_cast、const_cast、reinterpret_cast和dynamic_cast

2024-04-17 05:32

本文主要是介绍C++四种强制类型转换:static_cast、const_cast、reinterpret_cast和dynamic_cast,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

C风格的强制转换

在C++基本的数据类型中,可以分为四类:整型,浮点型,字符型,布尔型。其中数值型包括 整型与浮点型;字符型即为char。

(1)将浮点型数据赋值给整型变量时,舍弃其小数部分。
(2)将整型数据赋值给浮点型变量时,数值不变,整型提升。
(3)将double型数据赋值给float型变量时,注意数值范围溢出。
(4)字符型数据可以赋值给整型变量,此时存入的是字符的ASCII码。
(5)将一个int,short或long型数据赋值给一个char型变量,只将低8位原封不动的送到char型变量中。
(6)将有符号型数据赋值给长度相同的无符号型变量,连同原来的符号位一起传送。

C++强制类型转换

在C++语言中新增了四个关键字static_cast、const_cast、reinterpret_cast和dynamic_cast。这四个关键字都是用于强制类型转换的。新类型的强制转换可以提供更好的控制强制转换过程,允许控制各种不同种类的强制转换。
C++中风格是static_cast(content)。C++风格的强制转换其他的好处是,它们能更清晰的表明它们要干什么。程序员只要扫一眼这样的代码,就能立即知道一个强制转换的目的。

1.static_cast:相干类型之间的转换
在C++语言中static_cast用于数据类型的强制转换,强制将一种数据类型转换为另一种数据类型。例如将整型数据转换为浮点型数据。
[例]C语言所采用的类型转换方式:

int a = 10;
int b = 3;
double result = (double)a / (double)b;

将整型变量a和b转换为双精度浮点型,然后相除。在C++语言中,我们可以采用static_cast关键字来进行强制类型转换,如下所示。

int a = 10;
int b = 3;
double result = static_cast<double>(a) / static_cast<double>(b);

2.const_cast:强制去掉这种不能被修改的常属性,但需要特别注意的是const_cast不是用于去除变量的常量性,而是去除指向常数对象的指针或引用的常量性,其去除常量性的对象必须为指针或引用。
[例]一个错误的例子:

const int a = 10;
const int * p = &a;
*p = 20;                  //compile error
int b = const_cast<int>(a);  //compile error

在本例中出现了两个编译错误,第一个编译错误是*p因为具有常量性,其值是不能被修改的;另一处错误是const_cast强制转换对象必须为指针或引用,而例3中为一个变量,这是不允许的!

#include<iostream>
using namespace std;int main()
{const int a = 10;const int * p = &a;int *q;q = const_cast<int *>(p);*q = 20;    //finecout <<a<<" "<<*p<<" "<<*q<<endl;cout <<&a<<" "<<p<<" "<<q<<endl;return 0;
}

在本例中,我们将变量a声明为常量变量,同时声明了一个const指针指向该变量(此时如果声明一个普通指针指向该常量变量的话是不允许的,Visual Studio 2010编译器会报错)。之后我们定义了一个普通的指针*q。将p指针通过const_cast去掉其常量性,并赋给q指针。之后我再修改q指针所指地址的值时,这是不会有问题的。

最后将结果打印出来,运行结果如下:
10 20 20
002CFAF4 002CFAF4 002CFAF4

3.reinterpret_cast:不相干类型的转换
reinterpret_cast主要有三种强制转换用途:改变指针或引用的类型、将指针或引用转换为一个足够长度的整形、将整型转换为指针或引用类型。
[例].将整型指针通过reinterpret_cast强制转换成了双精度浮点型指针。

//将整型指针通过reinterpret_cast强制转换成了双精度浮点型指针。
int *a = new int;
double *d = reinterpret_cast<double *>(a);

4. dynamic_cast:它要求所转换的操作数必须包含多态类类型(即至少包含一个虚函数的类);<>内部所描述的目标类型必须为指针或引用。
这里提出一个概念RTTI(运行时类型信息):通过运行时类型信息程序能够使用基类的指针或引用来检查这些指针或引用所指的对象的实际派生类型。
(1)其他三种都是编译时完成的,dynamic_cast是运行时处理的,运行时要进行类型检查。
(2)不能用于内置的基本数据类型的强制转换。
(3)dynamic_cast转换如果成功的话返回的是指向类的指针或引用,转换失败的话则会返回NULL。
(4)使用dynamic_cast进行转换的,基类中一定要有虚函数,否则编译不通过。 Base类中需要检测有虚函数的原因:类中存在虚函数,就说明它有想要让基类指针或引用指向派生类对象的情况,此时转换才有意义。
(5)在类的转换时,在类层次间进行上行转换时,dynamic_cast和static_cast的效果是一样的。在进行下行转换时,dynamic_cast具有类型检查的功能,比static_cast更安全。

    向上转换,即为子类指针指向父类指针(一般不会出问题);向下转换,即将父类指针转化子类指针。向下转换的成功与否还与将要转换的类型有关,即要转换的指针指向的对象的实际类型与转换以后的对象类型一定要相同,否则转换失败。

在C++中,编译期的类型转换有可能会在运行时出现错误,特别是涉及到类对象的指针或引用操作时,更容易产生错误。Dynamic_cast操作符则可以在运行期对可能产生问题的类型转换进行测试。

[例]一个错误的例子

#include<iostream>
using namespace std;class base
{
public :void m(){cout<<"m"<<endl;}
};class derived : public base
{
public:void f(){cout<<"f"<<endl;}
};int main()
{derived * p;p = new base;p = dynamic_cast<derived *>(new base);p->m();p->f();return 0;
}

在本例中利用dynamic_cast进行强制类型转换,但是因为base类中并不存在虚函数,因此p = dynamic_cast<derived *>(new base);这一句会编译错误。

为了解决本例中的语法错误,我们可以将base类中的函数m声明为虚函数,virtual void m(){cout<<“m”<<endl;}。

[例]正确示范

#include<iostream>
#include<cstring>using namespace std;class A
{public:virtual void f(){cout<<"hello"<<endl;};
};class B:public A
{public:void f(){cout<<"hello2"<<endl;};};class C
{void pp(){return;}
};int fun()
{return 1;
}int main()
{A* a1=new B;//a1是A类型的指针指向一个B类型的对象A* a2=new A;//a2是A类型的指针指向一个A类型的对象B* b;C* c;//结果为not null,向下转换成功,a1之前指向的就是B类型的对象,// 所以可以转换成B类型的指针。b=dynamic_cast<B*>(a1);if(b==NULL){cout<<"null"<<endl;}else{cout<<"not null"<<endl;}b=dynamic_cast<B*>(a2);//结果为null,向下转换失败if(b==NULL){cout<<"null"<<endl;}else{cout<<"not null"<<endl;}c=dynamic_cast<C*>(a);//结果为null,向下转换失败if(c==NULL){cout<<"null"<<endl;}else{cout<<"not null"<<endl;}delete(a);return 0;
}

这篇关于C++四种强制类型转换:static_cast、const_cast、reinterpret_cast和dynamic_cast的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/910905

相关文章

c++ 类成员变量默认初始值的实现

《c++类成员变量默认初始值的实现》本文主要介绍了c++类成员变量默认初始值,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录C++类成员变量初始化c++类的变量的初始化在C++中,如果使用类成员变量时未给定其初始值,那么它将被

C++中NULL与nullptr的区别小结

《C++中NULL与nullptr的区别小结》本文介绍了C++编程中NULL与nullptr的区别,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编... 目录C++98空值——NULLC++11空值——nullptr区别对比示例 C++98空值——NUL

C++ Log4cpp跨平台日志库的使用小结

《C++Log4cpp跨平台日志库的使用小结》Log4cpp是c++类库,本文详细介绍了C++日志库log4cpp的使用方法,及设置日志输出格式和优先级,具有一定的参考价值,感兴趣的可以了解一下... 目录一、介绍1. log4cpp的日志方式2.设置日志输出的格式3. 设置日志的输出优先级二、Window

MySQL 中的 CAST 函数详解及常见用法

《MySQL中的CAST函数详解及常见用法》CAST函数是MySQL中用于数据类型转换的重要函数,它允许你将一个值从一种数据类型转换为另一种数据类型,本文给大家介绍MySQL中的CAST... 目录mysql 中的 CAST 函数详解一、基本语法二、支持的数据类型三、常见用法示例1. 字符串转数字2. 数字

SQL Server配置管理器无法打开的四种解决方法

《SQLServer配置管理器无法打开的四种解决方法》本文总结了SQLServer配置管理器无法打开的四种解决方法,文中通过图文示例介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的... 目录方法一:桌面图标进入方法二:运行窗口进入检查版本号对照表php方法三:查找文件路径方法四:检查 S

从入门到精通C++11 <chrono> 库特性

《从入门到精通C++11<chrono>库特性》chrono库是C++11中一个非常强大和实用的库,它为时间处理提供了丰富的功能和类型安全的接口,通过本文的介绍,我们了解了chrono库的基本概念... 目录一、引言1.1 为什么需要<chrono>库1.2<chrono>库的基本概念二、时间段(Durat

C++20管道运算符的实现示例

《C++20管道运算符的实现示例》本文简要介绍C++20管道运算符的使用与实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录标准库的管道运算符使用自己实现类似的管道运算符我们不打算介绍太多,因为它实际属于c++20最为重要的

Visual Studio 2022 编译C++20代码的图文步骤

《VisualStudio2022编译C++20代码的图文步骤》在VisualStudio中启用C++20import功能,需设置语言标准为ISOC++20,开启扫描源查找模块依赖及实验性标... 默认创建Visual Studio桌面控制台项目代码包含C++20的import方法。右键项目的属性:

c++中的set容器介绍及操作大全

《c++中的set容器介绍及操作大全》:本文主要介绍c++中的set容器介绍及操作大全,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录​​一、核心特性​​️ ​​二、基本操作​​​​1. 初始化与赋值​​​​2. 增删查操作​​​​3. 遍历方

解析C++11 static_assert及与Boost库的关联从入门到精通

《解析C++11static_assert及与Boost库的关联从入门到精通》static_assert是C++中强大的编译时验证工具,它能够在编译阶段拦截不符合预期的类型或值,增强代码的健壮性,通... 目录一、背景知识:传统断言方法的局限性1.1 assert宏1.2 #error指令1.3 第三方解决