C++四种强制转换总结介绍

目录

1)static_cast

2)const_cast

3)reinterpret_cast

4)dynamic_cast

参考:


1)static_cast

        静态类型转换,是良性的,一般不会有风险。

用法:static_cast <类型说明符> (变量或表达式)

int b = 2;
double a = static_cast<double>(b);

主要有以下几种用法:

        ①、用于基本类型的转换,这种转换类似于C语言里面的强制转换。

        ②、任何表达式的类型转换为void。

        ③、父类和子类指针之间的转换。如果父类指针指向一个对象,此时将父类指针转换为子类指针是不安全的,子类指针转换为父类指针是安全的。

        ④、把空指针转换成目标类型的指针

注意:static_cast不能转换掉expression的const、volitale或者_unaligned属性,在类的类型转换中,只适用于有相互联系的类才可以相互转换,不一定保护虚函数

2)const_cast

        const_cast主要用来强制去掉不能修改的常量特性(常量对象的指针或者引用,不是常量对象)。

 用法:cosnt_cast <类型说明符> (变量或表达式)

#include<iostream>
using namespace std;
 
int main()
{
    const int a = 10;
    const int * p = &a;
    int *q;
    q = const_cast<int *>(p);
    *q = 20;    //fine
    cout <<a<<" "<<*p<<" "<<*q<<endl;
        cout <<&a<<" "<<p<<" "<<q<<endl;
    return 0;
}
输出结果:
10 20 20
002CFAF4 002CFAF4 002CFAF4

        可以看到q p和a地址一样的,但打印的内容不一样,这是因为c++对常量的处理更像是编译期的define,是一个值替换的过程,cout << 被修改为cout<<10。

        在上图中我们称“*q=20”语句为未定义行为语句,所谓的未定义行为是指在标准的C++规范中并没有明确规定这种语句的具体行为,该语句的具体行为由编译器来自行决定如何处理。对于这种未定义行为的语句我们应该尽量予以避免!
        从上图中我们可以看出我们是不想修改变量a的值的,既然如此,定义一个const_cast关键字强制去掉指针的常量性到底有什么用呢?我们接着来看下面的例子。

#include<iostream>
using namespace std;
 
const int * Search(const int * a, int n, int val);
 
int main()
{
    int a[10] = {0,1,2,3,4,5,6,7,8,9};
    int val = 5;
    int *p;
    p = const_cast<int *>(Search(a, 10, val));
    if(p == NULL)
        cout<<"Not found the val in array a"<<endl;
    else
        cout<<"hvae found the val in array a and the val = "<<*p<<endl;
    return 0;
}
 
const int * Search(const int * a, int n, int val)
{
    int i;
    for(i=0; i<n; i++)
    {
        if(a[i] == val)
            return &a[i];
    }
    return  NULL;
}

        引用也类似,使用 const_cast 进行强制类型转换可以突破 C/C++ 的常数限制,修改常数的值,因此有一定的危险性。

3)reinterpret_cast

    在使用reinterpret_cast强制转换过程仅仅只是比特位的拷贝,因此在使用过程中需要特别谨慎,可以认为是static_cast的补充。

用法:reinterpret_cast <类型说明符> (变量或表达式)

int *a = new int;
double *d = reinterpret_cast<double *>(a)

 主要有以下几种用法:

        ①、改变指针或者引用类型

        ②、将指针或者引用转换为一个足够长度的整型

        ③、将整型转换为指针或者引用类型。

4)dynamic_cast

        dynamic_cast 用于在类的继承层次之间进行类型转换,它既允许向上转型(Upcasting),也允许向下转型(Downcasting)。向上转型是无条件的,不会进行任何检测,所以都能成功;向下转型的前提必须是安全的,要借助 RTTI 进行检测,所有只有一部分能成功。

        dynamic_cast 与 static_cast 是相对的,dynamic_cast 是“动态转换”的意思,static_cast 是“静态转换”的意思。dynamic_cast 会在程序运行期间借助 RTTI 进行类型转换,这就要求基类必须包含虚函数;static_cast 在编译期间完成类型转换,能够更加及时地发现错误。

 用法:dynamic_cast <类型说明符> (变量或表达式)

demo1:

#include<iostream>
using namespace std;
 
class base
{
public :
    void m(){cout<<"m"<<endl;}
};
 
class derived : public base
{
public:
    void f(){cout<<"f"<<endl;}
};
 
int main()
{
    derived * p;
    p = new base;
    p = static_cast<derived *>(new base);
    p->m();
    p->f();
    return 0;
}

        本例中定义了两个类:base类和derived类,这两个类构成继承关系。在base类中定义了m函数,derived类中定义了f函数。在前面介绍多态时,我们一直是用基类指针指向派生类或基类对象,而本例则不同了。

        本例主函数中定义的是一个派生类指针,当我们将其指向一个基类对象时,这是错误的,会导致编译错误。

        但是通过强制类型转换我们可以将派生类指针指向一个基类对象,p = static_cast<derived *>(new base);语句实现的就是这样一个功能,这样的一种强制类型转换时合乎C++语法规定的,但是是非常不明智的,它会带来一定的危险。

        在程序中p是一个派生类对象,我们将其强制指向一个基类对象,首先通过p指针调用m函数,因为基类中包含有m函数,这一句没有问题,之后通过p指针调用f函数。一般来讲,因为p指针是一个派生类类型的指针,而派生类中拥有f函数,因此p->f();这一语句不会有问题,但是本例中p指针指向的确实基类的对象,而基类中并没有声明f函数,虽然p->f();这一语句虽然仍没有语法错误,但是它却产生了一个运行时的错误。换言之,p指针是派生类指针,这表明程序设计人员可以通过p指针调用派生类的成员函数f,但是在实际的程序设计过程中却误将p指针指向了一个基类对象,这就导致了一个运行期错误。

        产生这种运行期的错误原因在于static_cast强制类型转换时并不具有保证类型安全的功能,而C++提供的dynamic_cast却能解决这一问题,dynamic_cast可以在程序运行时检测类型转换是否类型安全。

        当然dynamic_cast使用起来也是有条件的,它要求所转换的操作数必须包含多态类类型(即至少包含一个虚函数的类)。

demo2:

#include<iostream>
using namespace std;
 
class base
{
public :
    void m(){cout<<"m"<<endl;}
};
 
class derived : public base
{
public:
    void f(){cout<<"f"<<endl;}
};
 
int main()
{
    derived * p;
    p = new base;
    p = dynamic_cast<derived *>(new base);
    p->m();
    p->f();
    return 0;
}

           在本例中利用dynamic_cast进行强制类型转换,但是因为base类中并不存在虚函数,因此p = dynamic_cast<derived *>(new base);这一句会编译错误。为了解决本例中的语法错误,我们可以将base类中的函数m声明为虚函数,virtual void m(){cout<<"m"<<endl;}

        dynamic_cast还要求<>内部所描述的目标类型必须为指针或引用。

demo3:

#include<iostream>
#include<cstring>
 
using namespace std;
 
class A
{
   public:
   virtual void f()
   {
       cout<<"hello"<<endl;
       };
};   
class B:public A
{
    public:
    void f()
    {
        cout<<"hello2"<<endl;
        };
  
};   
class C
{
  void pp()
  {
      return;
  }
};  
int fun()
{
    return 1;
} 
int main()
{
    A* a1=new B;//a1是A类型的指针指向一个B类型的对象
    A* a2=new A;//a2是A类型的指针指向一个A类型的对象
    B* b;
    C* c;
    b=dynamic_cast<B*>(a1);//结果为not null,向下转换成功,a1之前指向的就是B类型的对象,所以可以转换成B类型的指针。
    if(b==NULL)
    {
        cout<<"null"<<endl;
    }
 
    else
    {
        cout<<"not null"<<endl;
    }
 
    b=dynamic_cast<B*>(a2);//结果为null,向下转换失败
    if(b==NULL)
    {
        cout<<"null"<<endl;
    }
 
    else
    {
        cout<<"not null"<<endl;
    }
 
    c=dynamic_cast<C*>(a);//结果为null,向下转换失败
    if(c==NULL)
    {
        cout<<"null"<<endl;
    }
 
    else
    {
        cout<<"not null"<<endl;
    }
 
    delete(a);
    return 0;
}

参考:

        C++四种类型转换运算符:static_cast、dynamic_cast、const_cast和reinterpret_cast_C语言中文网

        C++ 四种强制类型转换 - 静悟生慧 - 博客园

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值