C++4种cast强制类型转换

注意:尽量少使用转型操作,尤其是dynamic_cast,耗时较高,会导致性能的下降,尽量使用其他方法替代。

const_cast

定义:const_cast转换符是用来移除变量的const或volatile限定符

const int constant = 21;
const int* const_p = &constant;
int* modifier = const_cast<int*>(const_p);
*modifier = 7;

//传统方式用指针来实现,因为指针之间在类型转换的时候不会检查
//const int constant = 21;
//const int* const_p = &constant;
//int* modifier = (int*)(const_p);

//但是
cout << "constant: "<< constant <<endl;
cout << "const_p: "<< *const_p <<endl;
cout << "modifier: "<< *modifier <<endl;
//结果为
constant: 21
const_p: 7
modifier: 7

说明C++里是const,就是const,外界千变万变,我就不变。不然真的会乱套了,const也没有存在的意义了。

原因:因为我们将数据类型定义为const,自然就不会去改变他,但是,我们可能调用了一个参数不是const的函数,而我们要传进去的实际参数确实const的,但是我们知道这个函数是不会对参数做修改的。于是我们就需要使用const_cast去除const限定,以便函数能够接受这个实际参数。

void Printer (int* val,string seperator = "\n")
{
	cout << val<< seperator;
}
 
int main(void) 
{	
	const int consatant = 20;
	//Printer(consatant);//Error: invalid conversion from 'int' to 'int*'
	Printer(const_cast<int *>(&consatant));
	
	return 0;
}

另一种情况:

int variable = 21;
const int* const_p = &variable;
int* modifier = const_cast<int*>(const_p);

*modifier = 7;
cout << "variable:" << variable << endl;

我们定义了一个非const的变量,但用带const限定的指针去指向它,在某一处我们突然又想修改了,可是我们手上只有指针,这时候我们可以去const来修改了。

static_cast

相当于传统的C语言里的强制转换

  • 用于类层次结构中基类(父类)和派生类(子类)之间指针或引用的转换。
    进行上行转换(把派生类的指针或引用转换成基类表示)是安全的;
    进行下行转换(把基类指针或引用转换成派生类表示)时,由于没有动态类型检查,所以是不安全
  • 用于基本数据类型之间的转换,如把int转换成char,把int转换成enum
  • 把空指针转换成目标类型的空指针
  • 把任何类型的表达式转换成void类型

注意:static_cast不能转换掉表达式的const、volatile、或者__unaligned属性

char a = 'a';
int b = static_cast<char>(a);//正确,将char型数据转换成int型数据

double *c = new double;
void *d = static_cast<void*>(c);//正确,将double指针转换成void指针

int e = 10;
const int f = static_cast<const int>(e);//正确,将int型数据转换成const int型数据

const int g = 20;
int *h = static_cast<int*>(&g);//编译错误,static_cast不能转换掉g的const属性


class Base
{};

class Derived : public Base
{}

Base* pB = new Base();
if(Derived* pD = static_cast<Derived*>(pB))
{}//下行转换是不安全的(坚决抵制这种方法)

Derived* pD = new Derived();
if(Base* pB = static_cast<Base*>(pD))
{}//上行转换是安全的
dynamic_cast

只能用于含有虚函数的类,主要用于执行“安全的向下转型”

转换方式:

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

e的类型必须符合以下三个条件中的任何一个:
1、e的类型是目标类型type的公有派生类
2、e的类型是目标type的共有基类
3、e的类型就是目标type的类型。

如果一条dynamic_cast语句的转换目标是指针类型并且失败了,则结果为0。如果转换目标是引用类型并且失败了,则dynamic_cast运算符将抛出一个std::bad_cast异常(该异常定义在typeinfo标准库头文件中)。e也可以是一个空指针,结果是所需类型的空指针。

dynamic_cast主要用于类层次间的上行转换和下行转换,还可以用于类之间的交叉转换(cross cast)。

在类层次间进行上行转换时,dynamic_cast和static_cast的效果是一样的;在进行下行转换时,dynamic_cast具有类型检查的功能,比static_cast更安全。dynamic_cast是唯一无法由旧式语法执行的动作,也是唯一可能耗费重大运行成本的转型动作。

dynamic_cast与继承层次的指针

向上转型:永远安全,不必要使用

向下转型:

//一种是基类指针所指对象是派生类类型的,这种转换是安全的;
//另一种是基类指针所指对象为基类类型,在这种情况下dynamic_cast在运行时做检查,转换失败,返回结果为0;
#include<iostream>
using namespace std;

class Base
{
public:
    Base(){};
    virtual void Show(){cout<<"This is Base calss";}
};
class Derived:public Base
{
public:
    Derived(){};
    void Show(){cout<<"This is Derived class";}
};
int main()
{    
    //这是第一种情况
    Base* base = new Derived;
    if(Derived *der= dynamic_cast<Derived*>(base))
    {
        cout<<"第一种情况转换成功"<<endl;
        der->Show();
        cout<<endl;
    }
    //这是第二种情况
    Base * base1 = new Base;
    if(Derived *der1 = dynamic_cast<Derived*>(base1))
    {
        cout<<"第二种情况转换成功"<<endl;
        der1->Show();
    }
    else 
    {
        cout<<"第二种情况转换失败"<<endl;
    }

    delete(base);
    delete(base1);
    
    return 0;
}
dynamic_cast和引用类型

与指针不同的是,并不存在空引用,所以引用的dynamic_cast检测失败时会抛出一个bad_cast异常

向上转型:永远安全,不必要使用

向下转型

int main()
{    
    //第一种情况,转换成功
    Derived b ;
    Base &base1= b;
    Derived &der1 = dynamic_cast<Derived&>(base1);
    cout<<"第一种情况:";
    der1.Show();
    cout<<endl;

    //第二种情况
    Base a ;
    Base &base = a ;
    cout<<"第二种情况:";
    try{
        Derived & der = dynamic_cast<Derived&>(base);
    }
    catch(bad_cast)
    {
        cout<<"转化失败,抛出bad_cast异常"<<endl;
    }
    system("pause");
}
reinterpret_cast

用来处理无关类型之间的转换;它会产生一个新的值,这个值会有与原始参数(expressoin)有完全相同的比特位。

注意:严禁随意使用

获取元素类型
#include<typeinfo>
typeid(ss).name()
    
//typeof()是gnu++11自己添加的

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值