关于C++的强制类型转换浅析

 更新时间:2020年4月25日 17:29  点击:2113

前言

一说起强制类型转换大家都很熟悉,相信很多学习完C++的朋友还在使用C语言的强制类型的方式 (类型)变量.

C++其实也具有自己的一套强制类型转换它们分明是:static_cast  reinterpret_cast  const_cast  dynamic_cast四种类型.

那么肯定会有人好奇C++是不是闲,C语言的强制类型用的舒舒服服的,为什么要新推出来这几个?

新类型的强制转换可以提供更好的控制强制转换过程,允许控制各种不同种类的强制转换。C++中风格是static_cast<type>。C++风格的强制转换其他的好处是,它们能更清晰的表明它们要干什么。程序员只要扫一眼这样的代码,就能立即知道一个强制转换的目

的。

static_cast                                                                                              

static_cast用于非多态类型的转换(静态转换),任何标准转换都可以用它,但它不能用于两个不相关的类型进行转换.

何为不相关类型? 比如int 和 double char short就是相关类型. 和int*就是不相关类型.

我们来看一看static_cast的用法.  例如,通过将一个运算对象强制转换成double类型就能使表达式执行浮点数除法:

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

当static_cast需要把一个较大的算术类型赋值给较小的类型时,static_cast非常有用。此时,强制类型转换告诉程序的读者和编译器:我们知道并且不在乎潜在的精度损失。一般来说,如果编译器发现一个的算术类型试图赋值给较小的类型,就会给出警告信息;但是当我们执行了显式的类型转换后,警告信息就会被关闭了。

reinterpret_cast                                                                                        

reinterpret_cast有着和C风格的强制转换同样的能力。它可以转化任何内置的数据类型为其他任何的数据类型,也可以转化任何指针类型为其他的类型。它甚至可以转化内置的数据类型为指针,无须考虑类型安全或者常量的情形。不到万不得已绝对用。

因为reinterpret_cast是一个蛮bug的操作,下面我来演示一下.

typedef void (* FUNC)(); 
int DoSomething (int i) 
{ 
  cout<<"DoSomething" <<endl; 
  return 0; 
} 
void Test () 
{ 
  // reinterpret_cast可以编译器以FUNC的定义方式去看待 DoSomething函数 
  // 所以非常的BUG,下面转换函数指针的代码是不可移植的,所以不建议这样用 
  // C++不保证所有的函数指针都被一样的使用,所以这样用有时会产生不确定的结果 
  FUNC f = reinterpret_cast< FUNC>(DoSomething ); 
  f(); 
} 

当你这样运行的时候,你会发现通过函数指针没有传参数调用这个有参数的函数居然可以调用,这就很尴尬了,所以我告诉你不到万不得已就不要使用reinterpret_cast

const_cast

对于将常量对象转化为非常量对象的行为,我们一般称之为“去掉const性质”。一旦我们去掉了某个对象的const性质,编译器就不再阻止我们对该对象进行写操作了。如果对象本身不是一个常量,使用强制类型转换获得写权限是合法的行为。然而如果对象是一个常量,再使用const_cast执行写操作就会产生未定义的后果。

举个例子:

#include<iostream> 
#include<Windows.h> 
#include<assert.h> 
 
using namespace std; 
 
int main() 
{ 
 const int a = 2; 
 int *p = const_cast<int*>(&a); 
 *p = 3; 
 cout << a << endl; 
 system("pause"); 
 return 0; 
} 

我们有理由的认为在内存当中a的值被修改为3,但是结果呢? 我们来看一看

这不科学啊?? 我们再打开监视窗口看一下a的值.

我们都知道监视窗口看到的都是从内存当中拿到的,但是为什么内存当中为3,打印出来就是2呢? 我来解释一下.

C++编译器具有优化功能,当你定一个const的常量的时候,系统觉得它不会被改变了,于是做一个优化把该常量存到寄存器当中,下次访问的过程更快速一点. 所以当显示窗口读取数据的时候,他会直接去寄存器当中读取数据.而不是去内存,所以导致我们明明该掉了a的值,却打印不出来,但是如何解决这个问题呢??

c++有一个关键字: volatile 该关键字的作用防止编译器优化,这个时候要输出a就会老老实实的回内存去查看.

#include<iostream> 
#include<Windows.h> 
#include<assert.h> 
 
using namespace std; 
 
int main() 
{ 
 volatile const int a = 2; 
 int *p = const_cast<int*>(&a); 
 *p = 3; 
 cout << a << endl; 
 system("pause"); 
 return 0; 
} 

dynamic_cast                                                                                           

前三种的强制类型转换,他们能做到的C语言的强制类型转换也大多能做到,最后一种C语言的强制类型转换就没有办法了.

在类的转换时,在类层次间进行上行转换时,dynamic_cast和static_cast的效果是一样的。在进行下行转换时,dynamic_cast具有类型检查的功能,比static_cast更安全。当用于多态类型时,它允许任意的隐式类型转换以及相反过程. 不过,与static_cast不同,在后一种情况里(注:即隐式转换的相反过程),dynamic_cast 会检查操作是否有效. 也就是说, 它会检查转换是否会返回一个被请求的有效的完整对象。检测在运行时进行. 如果被转换的指针不是一个被请求的有效完整的对象指针,返回值为NULL. 对于引用 类型,会抛出bad_cast异常

你说这个强转有啥用,其实对于我这种菜鸟还真的没用过,不过我知道一个问题可以使用这样的方法解决. 给你两个类让你分辨那个是子类那个是父类,我们来看看是如何解决的.

#include<iostream> 
#include<Windows.h> 
#include<assert.h> 
 
using namespace std; 
 
class AA 
{ 
public: 
 
 virtual void fun1() 
 { 
  cout << "hehe" << endl; 
 } 
public: 
 int a; 
}; 
 
class BB :public AA 
{ 
public: 
 
 virtual void fun1() 
 { 
  cout << "heh2e" << endl; 
 } 
public: 
 int c; 
}; 
int main() 
{ 
 AA* q = new AA(); 
 BB* p = new BB(); 
 AA* a; 
 BB* b; 
 
 b = dynamic_cast<BB*>(q); 
 if (b == NULL) 
 { 
  cout << "AA为基类" << endl; 
 } 
 else{ 
  cout << "AA为子类" << endl; 
 } 
 
 a = dynamic_cast<AA*>(p); 
 if (a == NULL) 
 { 
  cout << "BB为基类" << endl; 
 } 
 else 
 { 
  cout << "BB为子类" << endl; 
 } 
 system("pause"); 
 return 0; 
} 

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对猪先飞的支持。

[!--infotagslink--]

相关文章

  • C++ STL标准库std::vector的使用详解

    vector是表示可以改变大小的数组的序列容器,本文主要介绍了C++STL标准库std::vector的使用详解,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2022-03-06
  • C++中取余运算的实现

    这篇文章主要介绍了C++中取余运算的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-02-23
  • 详解C++ string常用截取字符串方法

    这篇文章主要介绍了C++ string常用截取字符串方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-04-25
  • C++调用C#的DLL程序实现方法

    本文通过例子,讲述了C++调用C#的DLL程序的方法,作出了以下总结,下面就让我们一起来学习吧。...2020-06-25
  • C++中四种加密算法之AES源代码

    本篇文章主要介绍了C++中四种加密算法之AES源代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考。...2020-04-25
  • C++ 整数拆分方法详解

    整数拆分,指把一个整数分解成若干个整数的和。本文重点给大家介绍C++ 整数拆分方法详解,非常不错,感兴趣的朋友一起学习吧...2020-04-25
  • C++中 Sort函数详细解析

    这篇文章主要介绍了C++中Sort函数详细解析,sort函数是algorithm库下的一个函数,sort函数是不稳定的,即大小相同的元素在排序后相对顺序可能发生改变...2022-08-18
  • C++万能库头文件在vs中的安装步骤(图文)

    这篇文章主要介绍了C++万能库头文件在vs中的安装步骤(图文),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-02-23
  • 详解C++ bitset用法

    这篇文章主要介绍了C++ bitset用法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-04-25
  • 浅谈C++中的string 类型占几个字节

    本篇文章小编并不是为大家讲解string类型的用法,而是讲解我个人比较好奇的问题,就是string 类型占几个字节...2020-04-25
  • C++ Eigen库计算矩阵特征值及特征向量

    这篇文章主要为大家详细介绍了C++ Eigen库计算矩阵特征值及特征向量,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2020-04-25
  • C++ pair的用法实例详解

    这篇文章主要介绍了C++ pair的用法实例详解的相关资料,需要的朋友可以参考下...2020-04-25
  • VSCode C++多文件编译的简单使用方法

    这篇文章主要介绍了VSCode C++多文件编译的简单使用方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-03-29
  • C++中的循环引用

    虽然C++11引入了智能指针的,但是开发人员在与内存的斗争问题上并没有解放,如果我门实用不当仍然有内存泄漏问题,其中智能指针的循环引用缺陷是最大的问题。下面通过实例代码给大家介绍c++中的循环引用,一起看看吧...2020-04-25
  • C++随机点名生成器实例代码(老师们的福音!)

    这篇文章主要给大家介绍了关于C++随机点名生成器的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-04-25
  • C++如何删除map容器中指定值的元素详解

    map容器是C++ STL中的重要一员,删除map容器中value为指定元素的问题是我们经常与遇到的一个问题,下面这篇文章主要给大家介绍了关于利用C++如何删除map容器中指定值的元素的相关资料,需要的朋友可以参考借鉴,下面来一起看看吧。...2020-04-25
  • C++ 约瑟夫环问题案例详解

    这篇文章主要介绍了C++ 约瑟夫环问题案例详解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下...2021-08-15
  • C++中cin的用法详细

    这篇文章主要介绍了C++中cin的用法详细,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-04-25
  • 基于C++中常见编译错误的总结详解

    本篇文章是对C++中的常见编译错误进行了详细的分析介绍,需要的朋友参考下...2020-04-25
  • C++实现递归函数的方法

    在本篇内容里小编给大家分享了关于C++实现递归函数的教学步骤,需要的朋友跟着参考下。...2020-04-25