C++类型转换


前言

类型转换用于数据类型的转换,分为旧式类型转换和新式类型转换。

一、旧式类型转换

C语言中可以用(type)value进行旧式类型转换,如double(a),double(12);C++中增加了type(value)的写法,但为了兼容C,一般不用type(value)的写法。
将整型变量a转换为双精度浮点型输出:

#include<iostream>
#include<stdio.h>
using namespace std;
int main()
{
    int a;
    a=12;
    printf("%f\n",a);
    printf("%f\n",(double)a);
    printf("%f\n",double(a));
    return 0;
}

输出:
在这里插入图片描述

二、新式类型转换

本质上跟旧式类型转换没有区别,只不过将转换的数据划分得更细了,也就是A种类型的数据转换只能用A种类型的数据转换。新式类型转换一共有以下四种:

static_cast
const_cast
dynamic_cast
reinterpret_cast

在进行测试之前首先要定义三个类:

#include<iostream>
#include<stdio.h>
using namespace std;
class CFather{
public:
    int a;
};
class CSon:public CFather{
    public:
    int b;
};
class COther{
    public:
    double c;
};

1.static_cast

形式:static_cast<type>(expression)
说明:当type和expression可以互相隐式转换的时候,这个方法执行起来才是合法的

什么是隐式转换?
就是可以直接用等于号,进行赋值后会自动转换。

下面的o不能直接转化为f.
在这里插入图片描述

下面的f不能转化为s
在这里插入图片描述

下面的的s能转化为f,也就是父类指针能指向子类空间:
在这里插入图片描述

使用旧式类型转换:

int main()
{
    CFather* f;
    CSon* s=new CSon;
    COther *o=new COther;
    cout<<o->c<<endl;
    f=(CFather*)s;
    s->a=1;
    s->b=2;
    cout<<f->a<<endl;
    o=(COther*)s;
    cout<<o->c<<endl;
    return 0;
}

执行结果:
在这里插入图片描述
不报错

使用static_cast将s转换成o:
在这里插入图片描述
会报错。

int main()
{
    CFather* f=new CFather;
    CSon* s=new CSon;
    COther *o=new COther;
    s->a=1;
    s->b=2;
    f->a=3;
    s=static_cast<CSon*>(f);
    cout<<s->b<<endl;
    f=static_cast<CFather*>(s);
    s->b=5;
    s->a=6;
    cout<<s->b<<endl;
    cout<<f->a<<endl;
    return 0;
}

输出:
在这里插入图片描述
从上面的代码和运行结果可以看出:static_cast<>()可以用于父类和子类的相互转换,但不可以用在不相关类之间的转换,否则会报错。

2.const_cast

形式:const_cast<type>(expression)
说明:用于去掉表达式的const或volatile属性,仅当type和expression一样的时候,才合法。

对于指针常量来说,指针所指向的那块内存的值是不可以改变的。
在这里插入图片描述
执行结果:在这里插入图片描述

当使用不安全的类型转换时:

int main()
{
    CFather const *f=new CFather;
    CSon* s=new CSon;
    COther *o=new COther;
    s=(CSon*)f;
    s->a=5;
    cout<<f->a<<endl;
    return 0;
}

执行结果:
在这里插入图片描述
使用强制类型转换时,借助一个非指针常量可以修常指针常量的内存,破坏了const不可修改的规则。

于是就有了const_cast.
const_cast的type和expression类型不匹配时,会报错。
在这里插入图片描述
非const指针不能直接指向const内存
在这里插入图片描述
static_cast无法去掉f的const属性
在这里插入图片描述

int main()
{
    CFather  const *f=new CFather;
    CSon* s=new CSon;
    COther *o=new COther;
    CFather *f1=const_cast<CFather*>(f);
    f1->a=6;
    cout<<f->a<<endl;
    return 0;
}

在这里插入图片描述
在这里插入图片描述
用const_cast可以让非const属性的指针指向const属性的内存,并对const属性的内存修改,但是expression的const属性并没有失效.
那这种做法跟强制类型转换有什么区别呢?
本质上没有区别,但是这种做法增加了程序的可读性,而且也防止了不安全的类型转换。

3.dynamic_cast

形式:dynamic_cast<type>expression.
说明:用于父子类型的转换。子类型可以直接转换成父类型,但是父类型要转换成子类型的时候,需要符合多态条件。如果是不相关类型的转换,会报错。

子类可以直接转换成父类对象:

int main()
{
    CFather  *f=new CFather;
    CSon* s=new CSon;
    COther *o=new COther;
    f=dynamic_cast<CFather*>(s);
    s->a=11;
    cout<<f->a<<endl;
    return 0;
}

实验结果:
在这里插入图片描述

int main()
{
    CFather  *f=new CFather;
    CSon* s=new CSon;
    COther *o=new COther;
    f=dynamic_cast<CSon*>(s);
    s->a=10;
    cout<<f->a<<endl;
    return 0;
}

执行结果:
在这里插入图片描述

不相关的类型转换,会报错:
在这里插入图片描述

父类转换成子类,需要符合多态条件:
在这里插入图片描述

多态情况:1.在子类中添加一个虚函数,但父类中不添加:
class CSon:public CFather{ public: int b; virtual int add(int a,int b){return a+b;} };
在这里插入图片描述
还是会报错。

2.在父类中添加一个虚函数,但子类中不添加:
class CFather{ public: int a; virtual int add(int a,int b){return a+b;} };

在这里插入图片描述
然后下面的代码不报错了:

int main()
{
    CFather  *f=new CFather;
    CSon* s=new CSon;
    COther *o=new COther;
    s=dynamic_cast<CSon*>(f);
    s->a=12;
    cout<<f->a<<endl;
    return 0;
}

但是运行会出错:
在这里插入图片描述

修改一下代码:

int main()
{
    CFather  *f=new CFather;
    CSon* s=new CSon;
    COther *o=new COther;
    s=dynamic_cast<CSon*>(f);
    f->a=12;
    cout<<s->a<<endl;
    return 0;
}

还是运行失败:
在这里插入图片描述

再改一下:

int main()
{
    CFather  *f=new CFather;
    CSon* s=new CSon;
    COther *o=new COther;
    s=dynamic_cast<CSon*>(f);
    f->a=12;
    cout<<f->a<<endl;
    return 0;
}

运行成功:
在这里插入图片描述
使用强制类型转换:

int main()
{
    CFather  *f=new CFather;
    CSon* s=new CSon;
    COther *o=new COther;
    s=(CSon*)f;
    s->a=13;
    cout<<f->a<<endl;
    return 0;
}

运行成功:
在这里插入图片描述

int main()
{
    CFather  *f=new CFather;
    CSon* s=new CSon;
    COther *o=new COther;
    cout<<sizeof(*f)<<endl;
    cout<<sizeof(*s)<<endl;
    s=dynamic_cast<CSon*>(f);
    cout<<sizeof(*f)<<endl;
    cout<<sizeof(*s)<<endl;
    cout<<s->a<<endl;
    return 0;
}

输出结果:
在这里插入图片描述

说明了用dynamic_cast即使父类对象转换为了子类对象,子类指针也无法访问父类对象成员。

4.reinterpret_cast

形式:reinterpret_cast<type>(expression)
说明:用于危险的类型转换

struct dat{
    short a;
    short b;
};
int main()
{
    long value=0xA224B118;
    dat* p=reinterpret_cast<dat*>(&value);
    cout<<hex<<p->a<<endl;
    cout<<p->b<<endl;
    return 0;
}

执行结果:
在这里插入图片描述
缺点:不可移植。

补充

#include<iostream>
#include<stdio.h>
using namespace std;
class CFather{
    public:
    int a;
    virtual int add(int c,int d){return c+d;}
};
class CSon:public CFather{
    public:
    int b;
    int add1(int c,int d){return c+d;}
};
class COther{
    public:
    double c;
};
int main()
{
    CFather  *f=new CFather;
    CSon* s=new CSon;
    COther *o=new COther;
    s=(CSon*)f;
    cout<<s->add1(3,4)<<endl;
    return 0;
}

实验结果:
在这里插入图片描述

#include<iostream>
#include<stdio.h>
using namespace std;
class CFather{
    public:
    int a;
    virtual int add(int c,int d){return c+d;}
};
class CSon:public CFather{
    public:
    int b;
    int f;
    int add1(int c,int d){return c+d;}
};
class COther{
    public:
    double c;
};
int main()
{
    CFather  *f=new CFather;
    CSon* s=new CSon;
    COther *o=new COther;
    cout<<sizeof(*s)<<endl;
    cout<<sizeof(*f)<<endl;
    
    cout<<f<<endl;
    
    cout<<&(s->f)<<endl;
    cout<<sizeof(*f)<<endl;
    s=(CSon*)f;
    cout<<f<<endl;
    cout<<&(f->a)<<endl;
    cout<<&(s->f)<<endl;
    s->f=5;
    cout<<sizeof(*f)<<endl;
    cout<<sizeof(*s)<<endl;
    cout<<s->f<<endl;
    return 0;
}

执行结果:
在这里插入图片描述
输出解释:
&(s->a)之前有一个虚函数表指针,占八个字节。
&(s->f)和&(s->a)之间有一个&(s->b);
说明:父类对象强行转换为子类对象时,父类对象会根据子类对象的大小进行扩充


总结

static_cast相对来说比较重要,需要重点掌握。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值