强制类型转换

C++强制类型转换

C++中有四种强制类型转换操作符:static_cast,dynamic_cast,const_cast,reinterpret_cast,下面分别介绍。

1.static_cast

只完成编译时期的转换检查,主要有几个应用场合,安全性由程序员自己保证。

  1. 用于基类和子类之间指针或引用的转换
  2. 任何类型指针与void指针转换
  3. 空指针转换成目标指针
  4. 基本数据类型的转换,安全性由程序员保证,不做检查,一般将小转大(例如intdouble)能够保证不丢失数据

2.dynamic_cast

将一个基类对象指针(或引用)转换成派生类指针(或引用),dynamic_cast会根据基类指针是否真正指向派生类对象来做相应处理。

dynamic_cast<typename>(expression)

该运算符将expression转换成typename类型。注意:typename必须是类的指针、类的引用或者void*,并且expressiontypename类型保持一致,同为指针、引用或void*

dynamic_cast运算符可以在执行期决定真正的类型。如果 downcast 是安全的(也就说,如果基类指针或者引用确实指向一个派生类对象)这个运算符会传回适当转型过的指针。如果 downcast 不安全,这个运算符会传回空指针(也就是说,基类指针或者引用没有指向一个派生类对象)。转换引用时失败,会抛出std::bad_cast异常,需要catch该异常,做相应处理
dynamic_cast主要用于类层次间的上行转换和下行转换,还可以用于类之间的交叉转换。
在类层次间进行上行转换时,dynamic_caststatic_cast的效果是一样的;
在进行下行转换时,dynamic_cast具有类型检查的功能,比static_cast更安全。

#include"stdlib.h" 
#include<tchar.h> //工程文件中可直接使用,无需定义
#include<iostream>
using namespace std;
 
class Base
{
public:
    virtual void f() {cout << "Base::f" << endl;}
    void f1() {cout << "Base::f1" << endl;}
private:
    double x;
    double y;
};
 
class Derived : public Base
{
public:
    virtual void f() {cout << "Derived::f" << endl;}
    virtual void k() {cout << "Derived::k" << endl;}
private:
    double z;
};
 
class Base1
{
public:
    virtual void g() {cout << "Base1::g" << endl;}
    void g1() {cout << "Base1::g1" << endl;}
};
 
class Derived1 : public Base, public Base1
{
public:
    virtual void f() {cout << "Derived1::f" << endl;}
    virtual void h() {cout << "Derived1::h" << endl;}
};
 
void Test1()
{
    //对于单继承,
    //如果pD真的指向Derived,用dynamic_cast和static_cast效果相同
    Base* pD = new Derived;
     
    Derived* pD1 = dynamic_cast<Derived*>(pD);
    pD1->f();
    pD1->k();
    pD1->f1();
     
    Derived* pD2 = static_cast<Derived*>(pD);
    pD2->f();
    pD2->k();
    pD2->f1();
     
    //但是如果pB不是真的指向Derived,则用dynamic_cast则返回NULL,能够更早的禁止error的发生,
    //如果用static_cast虽然返回的不为NULL,但是运行时可能抛出exception。
    /**/////Errorcode
    //Base* pB = new Base();
    //Derived* pD3 = static_cast<Derived*>(pB);
    //pD3->f();
    //pD3->k();
    //pD3->f1();
    //Derived*pD4 = dynamic_cast<Derived*>(pB);
    //pD4->f();
    //pD4->k();
    //pD4->f1();
}
 
void Test2()
{
    //对于多重继承,
    //如果pD真的指向的是Derived1,使用dynamic_cast和static_cast都可以转化为Derived1,
    //但是如果要转化为Base的兄弟类Base1,必须使用dynamic_cast,使用static_cast不能编译。
    Base* pD = new Derived1;
    Derived1* pD1 = dynamic_cast<Derived1*>(pD);
    pD1->f();
    pD1->h();
    pD1->f1();
     
    Derived1* pD2 = static_cast<Derived1*>(pD);
    pD2->f();
    pD2->h();
    pD2->f1();
     
    Base1* pB1 = dynamic_cast<Base1*>(pD);
    pB1->g();
     
    /**/////errorcannotcompiler
    //Base1* pB2 = static_cast<Base1*>(pD);
    //pB2->g();
    //当然对于pB不是真的指向Derived1,想要转化为Derived1或Base的兄弟类Base1,情况与Test1中的error情况相同。
}
 
int _tmain(int argc, _TCHAR*argv[])
{
    Test1();
    Test2();
    return 0 ;
}

3.const_cast

const_cast主要作用是:修改类型的constvolatile属性。使用该运算方法可以返回一个指向非常量的指针(或引用)指向b1,就可以通过该指针(或引用)对它的数据成员任意改变。

int const & i = 100;
int & m = const_cast<int&>(i);
m=200;
cout<<i<<endl;

//输出结果:
//200

4.reinterpret_cast

所有指针的值都是一个表示地址的数值,值本身的转换是没有任何问题的。“再解释”是指对指针指像的哪段内存重新解释。

可以实现不同类型指针之间的相互转换,同时也支持将指针与数字之间的转换

float f = 0;
float* pf = &f;
int* pi = reinterpret_cast<float*>(pf);

//pi重新“解释”了pf,

以上内容引自:https://zouzhongliang.com/index.php/2019/03/12/c类型转换/

posted @ 2021-04-27 17:04  bear-Zhao  阅读(157)  评论(0编辑  收藏  举报