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

前言

一说起强制类型转换大家都很熟悉,相信很多学习完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;
} 

总结

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

(0)

相关推荐

  • Go语言到底有没有引用传参(对比 C++ )

    C++ 中三种参数传递方式 值传递: 最常见的一种传参方式,函数的形参是实参的拷贝,函数中改变形参不会影响到函数外部的形参.一般是函数内部修改参数而又不希望影响到调用者的时候会采用值传递. 指针传递 形参是指向实参地址的一个指针,顾名思义,在函数中对形参指向的内容操作,实参本身会被修改. 引用传递 在 C++ 中,引用是变量的别名,实际上是同一个东西,在内存中也存在同一个地址.换句话说,不管在哪里对引用操作,都相当直接操作被引用的变量. 下面看 demo: #include <iostream>

  • C++ 实现哈希表的实例

    C++ 实现哈希表的实例 该散列表的散列函数采用了除法散列函数.乘法散列函数.全域散列函数,每一个槽都是使用有序单向链表实现. 实现代码: LinkNode.h #include<iostream> using namespace std; class Link; class LinkNode { private: int key; LinkNode* next; friend Link; public: LinkNode():key(-1),next(NULL){} LinkNode(int

  • C++ 中cerr和cout的区别实例详解

    C++ 中cerr和cout的区别实例详解 前言: cerrThe object controls unbuffered insertions to the standard error output as a byte stream. Once the object is nstructed, the expression cerr.flags & unitbuf is nonzero. Example // iostream_cerr.cpp // compile with: /EHsc /

  • 关于C++中void*的小作用浅析

    本文主要给大家分享了关于C++中void*的一些你可能不了解的小作用,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧. 先来看一段代码: #include <iostream> #include <string> using namespace std; void o(int* x, void* y){ cout << *x << endl; cout << x << endl; cout << *(int

  • C++面向对象之多态的实现和应用详解

    前言 本文主要给大家介绍的是关于C++面向对象之多态的实现和应用的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧. 多态 大家应该都听过C++三大特性之一多态,那么什么多态呢?多态有什么用?通俗一点来讲-> 多态性可以简单地概括为"一个接口,多种方法",程序在运行时才决定调用的函数,它是面向对象编程领域的核心概念.当多态应用形参类型的时候,可以接受更多的类型.当多态用于返回值类型的时候,可以返回更多类型的数据.多态可以让你的代码拥有更好的扩展性. 多态分

  • C++中继承与多态的基础虚函数类详解

    前言 本文主要给大家介绍了关于C++中继承与多态的基础虚函数类的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧. 虚函数类 继承中我们经常提到虚拟继承,现在我们来探究这种的虚函数,虚函数类的成员函数前面加virtual关键字,则这个成员函数称为虚函数,不要小看这个虚函数,他可以解决继承中许多棘手的问题,而对于多态那他更重要了,没有它就没有多态,所以这个知识点非常重要,以及后面介绍的虚函数表都极其重要,一定要认真的理解~ 现在开始概念虚函数就又引出一个概念,那就是重写(覆

  • C/C++实现控制台输出不同颜色字体的方法

    本文实例讲述了C/C++实现控制台输出不同颜色字体的方法.分享给大家供大家参考,具体如下: 在控制台输出不同颜色的字 效果 代码: #include "stdio.h" #include "windows.h" int main(int argn, char **argv) { SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_GREEN); printf("Hello&q

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

    前言 一说起强制类型转换大家都很熟悉,相信很多学习完C++的朋友还在使用C语言的强制类型的方式 (类型)变量. C++其实也具有自己的一套强制类型转换它们分明是:static_cast  reinterpret_cast  const_cast  dynamic_cast四种类型. 那么肯定会有人好奇C++是不是闲,C语言的强制类型用的舒舒服服的,为什么要新推出来这几个? 新类型的强制转换可以提供更好的控制强制转换过程,允许控制各种不同种类的强制转换.C++中风格是static_cast<typ

  • Javascript Boolean、Nnumber、String 强制类型转换的区别详细介绍

    下面就来详细说一说 Javascript 中 Boolean.Nnumber.String 强制类型转换的区别. 我们知道 Boolean(value) 是把值转换成Boolean类型,Nnumber(value) 是把值转换成数字(整型或浮点数),而 String(value) 是把值转换成字符串. 先来分析下Boolean,Boolean在转换值为"至少有一字符的字符串"."非0的数字"或"对象"的情况下返回true:在转换值为"空

  • 浅谈PHP强制类型转换,慎用!

    PHP是一门弱类型的语言.这是它的优势和特点,但是有的时候你又不得不对类型进行相应的转换. 这个时候问题就来了.因为很多情况下,你会发现转换类型之后得到的数据和预期的值相差老大一截. 这里我以强制转换为整形作为例子. 看下面的代码,可以说你绝对不可能说出正确的答案.echo (int) 123.999999999999999; echo (int)   -1.999999999999999;echo (int)   -1.9999999999999999; echo (int)   -0.999

  • 函数指针的强制类型转换实现代码

    废话不多少,直接上代码 复制代码 代码如下: /********************************************************************************* 程序名称:函数指针的强制类型转换 ** 程序描述:** 性能提升:** 程序版本:V1.0*******************************************************************************/#include <stdio.h>

  • 解析C++中四种强制类型转换的区别详解

    C++的四种强制类型转换,所以C++不是类型安全的.分别为:static_cast , dynamic_cast , const_cast , reinterpret_cast为什么使用C风格的强制转换可以把想要的任何东西转换成合乎心意的类型.那为什么还需要一个新的C++类型的强制转换呢?新类型的强制转换可以提供更好的控制强制转换过程,允许控制各种不同种类的强制转换.C++中风格是static_cast<type>(content).C++风格的强制转换其他的好处是,它们能更清晰的表明它们要干

  • 浅谈Java中强制类型转换的问题

    为了更好的理解我们先看下面的例子: package com.yonyou.test; import java.util.ArrayList; import java.util.Iterator; import java.util.List; /** * 测试类 * @author 我们 * @创建日期 2016-5-31 */ public class Test{ public static void main(String[] args) { List<String> list=new Ar

  • SQL SERVER中强制类型转换cast和convert的区别详解

    SQL SERVER中强制类型转换cast和convert的区别 在SQL SERVER中,cast和convert函数都可用于类型转换,其功能是相同的, 只是语法不同. cast一般更容易使用,convert的优点是可以格式化日期和数值. select CAST('123' as int) -- 123 select CONVERT(int, '123') -- 123 select CAST(123.4 as int) -- 123 select CONVERT(int, 123.4) --

  • php foreach 参数强制类型转换的问题

    所以,为了防止这样的信息出现,我使用foreach的时候,都会把参数进行强制类型转换,形势如下: foreach((array)$arr as $key => $value); 这样做一直相安无事,就在前几天,突然出现了问题.我强制类型转换以后不能正常的调用object的方法了. 复制代码 代码如下: <?php class service implements Iterator{ function __construct($service_define,$filter=null){ $thi

  • JS在if中的强制类型转换方式

    众所周知,JS在很多情况下会进行强制类型转换,其中,最常见两种是: 1.使用非严格相等进行比较,对==左边的值进行类型转换 2.在if判断时,括号内的值进行类型转换,转化为布尔值 今天,我就来聊一聊JS在if中的强制类型转换. 其实,如果详细要讨论哪些值在if中强制转换为true,哪些值在if中强制转换为false,这很困难,因为,情况太多了.但是,我们可以轻松记住强制类型转换结果,为什么?因为,大多数情况下,都是转换为true,只有四种情况会转换为false.此时,我们只需要记住转换为fals

  • C#自动类型转换与强制类型转换的讲解

    自动类型转换 隐式类型转换 - 这些转换是 C# 默认的以安全方式进行的转换, 不会导致数据丢失.例如,从小的整数类型转换为大的整数类型,从派生类转换为基类. 转换规则 从存储范围小的类型到存储范围大的类型. 整数具体规则为: byte→short(char)→int→long→float→double 也就是说byte类型的变量可以自动转换为short类型,示例代码: byte b = 10; short sh = b; 在类型转换时可以跳跃.示例代码: byte b1 = 100; int

随机推荐