C++ day34类型转换运算符dynamic_cast,const_cast,static_cast,reinterpret_cast

背景

在这里插入图片描述

看几个C语言允许的类型转换示例:
在这里插入图片描述
在这里插入图片描述

C++的创始人看不下去这种没有意义的类型转换,更不能容忍他们在C语言中竟然被接受。。。他觉得C语言太宽松了。于是,他提出要更严格地限制允许的类型转换把类型转换规范化,于是添加了4个类型转换运算符。

这四个运算符,相比于通用类型转换,更加明确,更加安全

const_cast:用于移除变量的const或volatile限定符

对volatile限定符的移除不了解,不说。

只可以移除const,即把const转为非const,不可以把非const转为const

const_cast <type_name> (expression)//type_name和expression的类型必须相同

原来非const可以直接称呼为volatile,我以前还一直称呼为非const 。
这个理解对吗???

示例:

High bar;
const High * pbar = &bar;
High * pb = const_cast<High *> (pbar);//const High *->High *,删除const标签

如果还想做别的,const_cast就做不到了,它只能改变值为const或volatile。

const Low * pl = const_cast<const Low *>(pbar);//无效,因为pbar是High *,这个操作想要把pbar转换为const,同时还要转换为Low *

用通用类型转换(可能会同时改变类型,即不只是修改const)

High bar;
const High * pbar = &bar;
High * pb = (High *) (pbar);//const High * ->  High * 
Low * pl = (Low *) (pbar); //const High * ->  Low * ,不只修改了const,还改了类型

正是这种同时改变类型的操作,很危险,所以尽量使用const_cast运算符

示例:const_cast只可以用于自己本身不是const的类型

//const_cast.cpp
#include <iostream>
using std::cout;
using std::endl;
void change(const int * pt, int n);

int main()
{
	int pop1 = 38383;
	const int pop2 = 2000;
	cout << "pop1, pop2: " << pop1 << ", " << pop2 << endl;
	change(&pop1, -100);
	change(&pop2, -100);
	cout << "pop1, pop2:" << pop1 << ", " << pop2 << endl;
	return 0;
}
void change(const int * pt, int n)
{
	int * pc;
	pc = const_cast<int *>(pt);//pc是int *
	*pc += n;//传入的值加上n
}

可以看到,第一个值pop1成功被修改了,但是pop2却没有被修改。这是因为,pop1本身不是const的,传入change函数后,成为了const形参

相当于是,const_cast通过这种方式打破了形参的const的保护,把原本是非const的数值还是成功修改了。但是如果数据本身就是货真价实的非const,即不允许改变的 ,则const_cast不会再造作,而是会很配合编译器,不允许转换为非const的,所以const_cast是有一个识别判断规则的,不是傻乎乎转,而要看看到底能不能转,转了安不安全,如果不安全,比如人家本来就是const的,他就不会把人家转为非const的,它不会同意这种不安全的转换。

pop1, pop2: 38383, 2000
pop1, pop2:38283, 2000

这个示例展示了const_cast的真正的用武之地:本身不是const的变量传给了一个形参设置为const引用类型的函数,这时候可以在函数内部用const_cast实现对原变量的修改。除此之外,其实用处好像很少,毕竟我们已经证明,不可能通过const_cast修改真正的const变量的值

再加一个示例:说明同一个问题

int main()
{
   const int a = 10;
   int * b = &a;//C,C++的所有标准都报错
   cout << a << endl;
   *b = 20;
   cout << a << endl;
    return 0;
}

下面的代码编译可以通过,但是a的值不会被改变,所以非常安全

int main()
{
   const int a = 10;
   cout << a << endl;
   int * c = const_cast<int *> (&a);
   *c = 20;
   cout << a << endl;
    return 0;
}

这个示例说明,C++里面,const就是const,你不管什么招数办法,都改不了const变量的值,所以非常安全。

10
10

static_cast(可以向下转换downcast)

static_cast和dynamic_cast主要是解决类的继承层次中类型转换的安全性。static_cast是在编译时检查,不再运行时进行类型检查,所以是静态的;而dynamic_cast是在运行时进行类型检查,所以保证了安全性。

static_cast <type_name> (expression)//type_name和expression的类型必须相同
  • 可以向上转换,即把派生类指针或引用转换为基类的指针或引用,这是百分百安全的。
  • 可以向下转换:把基类指针和引用转换为派生类的指针和引用,这99%都是不安全的,因为基类指针指向的对象根本没有派生类的方法和数据,如果你转换后调用派生类的方法,就会出错。static_cast虽然可以实现向下转换,但是是不安全的。
  • 可以把整型转为枚举变量。
  • 把double转为int,把float转为long等数值转换。
    示例:
High bar;
Low blow;//Low是从High继承来的
High * pb = static_cast<High *> (&blow);//upcast,向上转换
Low * pl = static_cast<Low *> (&bar);//downcast,向下转换
Pond * pmer = static_cast<Pond *> (&blow);//无效,因为Pond是无关的类

第一种是派生类转为基类,属于向上转换,可以,用不用static_cast都行。

其中第二种转换是把High *转为Low *,基类转为派生类,是向下的转换,如果不用static_cast,是根本不允许的

向下转换只有用static_cast才允许。

dynamic_cast:只可用于有虚函数的类;只可以转指针或引用;

用于类层次间的向上和向下转化,static_cast可以实现类层次的向下转换但是不安全,所以不要用。

上一篇文章说过了。它用来把一种类型的指针转换为另一种类型的指针,如果可以实现安全转换的话就转,不能安全转换就不转,而返回一个空指针。

向下转化时,如果是非法的对于指针返回NULL对于引用抛异常。要深入了解内部转换的原理。

向上转换:指的是子类向基类的转换

向下转换:指的是基类向子类的转换

dynamic_cast <type_name> (expression)
pl = dynamic_cast<Low *> ph;//如果ph可以转换为Low类型的指针,则会把转换得到的Low指针赋给pl,否则赋空指针

那什么叫做能安全转换呢?

在类层次中向上转换(is-a继承关系),就是安全的转换。

reinterpret_cast(用于各种危险的类型转换,尽量少用)

reinterpret_cast <type_name> (expression)//type_name和expression的类型必须相同
  • 几乎什么都可以转,比如将int转指针,可能会出问题,尽量少用;相当于是明明可能有错,但是你还是非要转就用这个,当然是尽量不要用了

  • 不允许删除const

  • 但会执行其他令人生厌的操作(有时候程序员必须得做这种依赖于实现的令人生厌的操作)

  • 不支持所有的类型转换

  • 不可以把指针转换为更小的整型和浮点型
    在这里插入图片描述
    在这里插入图片描述

但在C语言,这些转换都可以。。所以C++的类型转换限制比C严格很多。

  • 不可以把函数指针转换为数据指针,也不可以把数据指针转换为函数指针

总结

  • C的强制转换表面上看起来功能强大什么都能转,但是转化不够明确,不能进行错误检查,容易出错。而C++专门提供了这四种类型转换运算符,为的就是提高转换的安全性。
  • 我感觉dynamic_cast最重要,其次是static_cast,然后是const_cast,最后是reintrpret_cast
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值