C++基础知识-------类型转换

前言

在C语言中,我们,就知道强制类型转换和隐式类型的转换,但是这种转换其实是不太安全的,既然我们学了C++,那么我们就应该尽量使用c++的类型转换,为什么呢?
因为 c++ 中类型转换的方式,他们都是通过类模板的方式实现,安全性得到保证,通过不同的用途使用不同的显示类型转换模板

C语言的强制类型转换

C风格的强制转换(Type Cast)容易理解,不管什么类型的转换都可以使用使用下面的方式.

TypeName b = (TypeName)a;

c++版本 四种强制转换类型函数
const_cast

主要作用是移除变量的const限定符从而改变表达式的常量属性。不能改变其他属性,如把一个变量int变为double,这是未定义的行为。

const_cast(expression); //type,转换的目的类型

这里我们需要注意,const_cast只能改变运算对象的底层const,换句话来说,就是服务于指针和引用。

•常量指针转化为非常量的指针,并且仍然指向原来的对象
•常量引用转化为非常量的引用,并且仍然指向原来的对象

补充:如果对象本身不是一个常量,使用强制类型转换获得写权限是合法的行为;然而如果是对象是一个常量,再使用const_cast执行写操作就会产生未定义的后果,不执行写操作就没事!

  char p[123]="123";
  const char* s = p;
  char* h = const_cast<char*>(s);
  h[3] = '4';

  const char* s = "1235";
  char* h = const_cast<char*>(s);
  h[3] = '4';    //发生错误

const_cast经常用在函数重载上,主要就是用来去掉变量的const属性



static_cast(静态转换)

1、static_cast 作用和C语言风格强制转换的效果基本一样,由于没有运行时类型检查来保证转换的安全性,所以这类型的强制转换和C语言风格的强制转换都有安全隐患。 也就是说,当需要把一个较大的算术类型赋值给较小的类型时,就可以用上static_cast, 这里的精度损失是程序员事先已经明确的

2、用于类层次结构中基类(父类)和派生类(子类)之间指针或引用的转换。注意:进行上行转换(把派生类的指针或引用转换成基类表示)是安全的;进行下行转换(把基类指针或引用转换成派生类表示)时,由于没有动态类型检查,所以是不安全的。
补充:当然也可以转换父类子类对象,但是这时候会发生切割现象,并且上行转换时不安全的,如果父类对象转子类对象,子类中还必须有个构造函数且参数是父类的类型,才能编译成功

3、用于基本数据类型之间的转换,如把int转换成char,把int转换成enum。这种转换的安全性需要开发者来维护。

4、static_cast不能转换掉原有类型的const、volatile、或者 __unaligned属性。(前两种可以使用const_cast 来去除)

5、在c++ primer 中说道:c++ 的任何的隐式转换都是使用 static_cast 来实现。

注:static_cast对于编译器无法自动执行的类型转换也非常有用。例如,我们可以使用static_cast找回存在于void*指针中的值:
#include <iostream>
#include <fstream>
using namespace std;
void change( int  pt, int n);
int main()
{
    double p = 15;
    void *y =  &p;  //任何非常量对象的地址都可以存入void*
    double *t = static_cast<double*>(y);   //将void*转换回初始的指针类型
     //这里值得注意一下,只能强制转回原来的double类型指针,类型一旦不符合,将产生未定义的后果或者出现不符的值
    cout<<(*t)<<endl;
	return 0;
}

针对上述补充的的第二点(代码演示):

class father{
  public:
    void func(){
      std::cout<<"Father"<<std::endl;
    }
    
};

class son:public father{
  public:
    son(father& fa){}
    son(){}
    void func(){
      std::cout<<"son"<<std::endl;
    }
    void add(){
      std::cout<<"No"<<std::endl;
    }
};


  father s;
  son fa = static_cast<son>(s);

  fa.func();
  fa.add();
dynamic_cast (动态转换)

dynamic_cast< type* >(e)
type必须是一个类类型且必须是一个有效的指针

dynamic_cast< type& >(e)
type必须是一个类类型且必须是一个左值

dynamic_cast< type&& >(e)
type必须是一个类类型且必须是一个右值

通常情况下,type应该含有虚函数

注意:e的类型必须符合以下三个条件中的任何一个

1、e的类型是目标类型type的公有派生类
2、e的类型是目标type的共有基类
3、e的类型就是目标type的类型。

如果符合以上三种条件之一,类型转换成功。否则,转换失败。如果dynamic_cast语句的转换目标是指针类型并且失败了,则结果为0。如果转换目标是引用类型并且失败了,将会抛出bad_cast类型异常(意味着我们可以用异常处理)
————————————————————————————————————————————————————

reinterpret_cast (不常用)

reinterpret_cast 主要有三种强制转换用途:
  1、改变指针或引用的类型
  2、将指针或引用转换为一个足够长度的整形
  3、将整型转换为指针或引用类型。
  用法为 reinterpret_cast (expression)。
  type-id 必须是一个指针、引用、算术类型、函数针或者成员指针。它可以把一个指针转换成一个整数,也可以把一个整数转换成一个指针(先把一个指针转换成一个整数,在把该整数转换成原类型的指针,还可以得到原先的指针值)。
  我们映射到的类型仅仅是为了故弄玄虚和其他目的,这是所有映射中最危险的。(这句话是C++编程思想中的原话)。因此, 你需要谨慎使用 reinterpret_cast。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值