static_cast和dynamic_cast

本文总结了C++中的static_cast和dynamic_cast两种类型转换方式。static_cast允许在有继承关系的对象间进行转换,但不安全,可能会导致NULL指针。dynamic_cast则需要多态性(至少一个虚函数),转换时会检查安全性,转换失败会返回NULL。下行转换时,从基类指针转换到子类指针必须确保实际类型匹配。
摘要由CSDN通过智能技术生成

static_cast和dynamic_cast总结

class A {}
class B {}

注意: 若继承 A为基类 B为派生类

代码class A { };









class B:public A { };
class A
{
public:
virtual void Test(){}
virtual ~A(){}
};
class B:public A
{ public:
//virtual void Test(){}
//virtual ~B(){}
};
class A
{ public:
virtual void Test(){}
virtual ~A(){}
};
class B:public A
{
public:
virtual void Test(){}
virtual ~B(){}
};
继承关系有继承关系 父无虚函数有继承关系 父有虚函数 子无有继承关系 父子有虚函数
static_cast//right 基类指针指向子类
pObjA = static_cast<A*>(pObjB);
//right强制转换 OK 基类到子类
pObjB = static_cast<B*>(pObjA);
均不为NULL

//转换为基类引用
objA = static_cast<A&>(objB);
objA = static_cast(objB);

//right 基类指针指向子类对象
pObjA = pObjB;
//right 基类指向子类
objA = objB;
//right 转换为基类引用
objB = static_cast<B&>(objA);







//error 基类不可转换为子类
//objB = static_cast(objA);
//error 子类指针指向父类对象
//pObjB = pObjA;
//error 无赋值操作符
//objB = objA;
//right 基类指针指向子类
pObjA = static_cast<A*>(pObjB);


//强制转换 OK 基类到子类
pObjB = static_cast<B*>(pObjA);
均不为NULL











//强制转换 OK 基类到子类
pObjA = &objB;
pObjB = static_cast<B*>(pObjA);
if (pObjB)
{
cout << “B Succ” << endl;
}
else
{
cout << “B NULL” << endl;
}
//right 基类指针指向子类
pObjA = static_cast<A*>(pObjB);


//强制转换 OK 基类到子类
pObjB = static_cast<B*>(pObjA);
均不为NULL











//强制转换 OK 基类到子类
pObjA = &objB;
pObjB = static_cast<B*>(pObjA);
if (pObjB)
{
cout << “B Succ” << endl;
}
else
{
cout << “B NULL” << endl;
}
dynamic_cast//right 基类指针指向子类
pObjA = dynamic_cast<A*>(pObjB);
且pObjA不为NULL








// ERROR 继承关系 父类无虚函无多态
pObjB = dynamic_cast<B*>(pObjA);
//right 基类指针指向子类
//上行一般没问题
pObjA = dynamic_cast<A*>(pObjB);

// warning 继承关系
pObjB = dynamic_cast<B*>(pObjA);
pObjB = NULL

//下行转换成功事例
pObjA = &objB;
pObjB = dynamic_cast<B*>(pObjA);
pObjB SUCCSESS
//right 基类指针指向子类
//上行一般没问题
pObjA = dynamic_cast<A*>(pObjB);

// warning 继承关系
pObjB = dynamic_cast<B*>(pObjA);
pObjB = NULL

//下行转换成功事例
pObjA = &objB;
pObjB = dynamic_cast<B*>(pObjA);
pObjB SUCCSESS

向上转换,即为子类指针指向父类指针(一般不会出问题);A = dynamic_cast(B)


向下转换,即将父类指针转化子类指针。B = dynamic_cast(A) (不报错,编译通过,但是转换失败NULL)


向下转换的成功与否还与将要转换的类型有关,即要转换的指针指向的对象的实际类型与转换以后的对象类型一定要相同,否则转换失败。

代码class A
{
public:
virtual void Test(){}
virtual ~A(){}
};
class D
{
};
class A { };







class D { };
继承关系无继承关系 有多态无继承关系 无多态
static_cast// ERROR
pObjD = static_cast<D*>(pObjA);
// ERROR
pObjA = static_cast<A*>(pObjD);
// ERROR
pObjD = static_cast<D*>(pObjA);
// ERROR
pObjA = static_cast<A*>(pObjD);
dynamic_cast//warning
pObjD = dynamic_cast<D*>(pObjA);
cout << “D NULL” << endl;
// ERROR
pObjD = dynamic_cast<D*>(pObjA));

static_cast

  1. 有继承都 ok 但是 B=static_cast(A) 不安全
  2. 无继承 一般不 ok 若想成功

只可对象转换

class A
{
public:
	virtual void test(){}
	virtual ~A(){}
};
class D
{
	public:
	D(){}
	D(A& a){}
	//virtual ~D(){}
};

A objA;
D objD;
objD = static_cast<D>(objA); 

如果让非继承关系通过编译,那么D类必须含有以A类的对象(或对象的引用)为参数的构造函数

dynamic_cast

  1. 编译 通过 必须有多态 有虚函数 可以没有继承 但存在 NULL
  2. 转换成功,必须多态,继承,

基类指向子类 ok (子类转换为基类 ok A = dynamic_cast(B)

子类指向基类 ok (基类转换为子类 ok B = dynamic_cast(A) 必须 基类引用或者指向子类 否则 NULL成功实例如下

dynamic_cast 下行转换

#include <iostream>
#include <string>
#include <vector>
using namespace std;

class Base{

public:
    Base() :str(nullptr){}
    Base(string s) :str(s){}
    virtual void print()
    {
        cout << str << "  ";
    }
private:
    string str;
};

class Derived:public Base

{
public:
    Derived(){}
    Derived(string s,int i) :Base(s),ival(i){}
    void print()
    {
        Base::print();
        cout << ival << endl;
    }
    void print_ival()
    {
        cout << "ival:" << ival << endl;
    }
private:
    int ival;
};


int main()
{
    Base base("aaa");
    Derived de("xxx", 111);
    //指针dynamic_cast
    Base* pb = &de;
    if (Derived* pd1 = dynamic_cast<Derived*>(pb))
    {
        pd1->print_ival();
    }
    else
    {
        //转换失败返回空指针
        cout << "type error..." << endl;
    }
    //引用dynamic_cast
    Base& rf = de;
    try
    {
        Derived& d = dynamic_cast<Derived&>(rf);
        d.print_ival();
    }
    catch (const std::bad_cast& ex)
    {
        //转换失败,抛出std::bad_cast异常
        cout << ex.what();
    }
    // system("pause");
}

完整测试代码

#include <iostream>
#include <string>
#include <vector>
using namespace std;

class A
{
public:
	virtual void foo(){}
};
class B
{
public:
	virtual void foo(){}
};

class C : public A, public B
{
public:
	virtual void foo(){}
};



class D {};
class E : public D {};
class F : public D {};
class G {};

void bar1(A *pa)
{
    if (B *pb = dynamic_cast<B *>(pa))//无继承关系 但是存在多态//为空
    {
        cout << "bar1 pb succ..." << endl;
    }
    else
    {
        //转换失败返回空指针
        cout << "bar1 pb error..." << endl;
    }
    B* pb=new B();
    if (A *pa1 = dynamic_cast<A *>(pb))//无继承关系 但是存在多态//为空
    {
        cout << "bar1 pa1 succ..." << endl;
    }
    else
    {
        //转换失败返回空指针
        cout << "bar1 pa1 error..." << endl;
    }
    delete pb;
    // B *pb = static_cast<B *>(pa);   //error A B不存在继承关系

    if (C *pc = static_cast<C *>(pa))
    {
        cout << "bar1 pc succ..." << endl;
    }
    else
    {
        //转换失败返回空指针
        cout << "bar1 pc error..." << endl;
    }

    //C *pc = static_cast<C *>(pa);   //ok
    // C *pc1 = static_cast<C *>(pb);  //ok
}
void bar1_2(A *pa,C *pc)
{
    if (A *pa1 = static_cast<A *>(pc))
    {
        cout << "bar1_2 pa1 succ..." << endl;
    }
    else
    {
        //转换失败返回空指针
        cout << "bar1_2 pa1 error..." << endl;
    }


    if (C *pc1 = static_cast<C *>(pa))//ok   //No   safe
    {
        cout << "bar1_2 pc1 succ..." << endl;
    }
    else
    {
        //转换失败返回空指针
        cout << "bar1_2 pc1 error..." << endl;
    }

    // C *pc1 = static_cast<C *>(pa);   //ok   //No   safe

    if (C *pc2 = dynamic_cast<C *>(pa))
    {
        cout << "bar1_2 pc2 succ..." << endl;
    }
    else
    {
        //转换失败返回空指针
        cout << "bar1_2 pc2 error..." << endl;
    }

    if (A *pa2 = dynamic_cast<A *>(pc))
    {
        cout << "bar1_2 pa2 succ..." << endl;
    }
    else
    {
        //转换失败返回空指针
        cout << "bar1_2 pa2 error..." << endl;
    }
    // A a;
    // B b;
    // b = static_cast<B>(a);
}

void bar2()
{
    C c;
    A *pa = &c;
    B *pc = static_cast<B *>(static_cast<C *>(pa));//A->C转换不安全 C->B安全

    if (pc)
    {
        cout << "bar2 pc succ..." << endl;
    }
    else
    {
        //转换失败返回空指针
        cout << "bar2 pc error..." << endl;
    }
}

void bar3(D* pD) {
    // E* pb1 = dynamic_cast<E*>(pD);   //error    //无多态类型//dynamic_cast不可转换

    E* pE = static_cast<E*>(pD);        //ok NOt safe    //基类指针指向子类
    if (pE)
    {
        cout << "bar3 pE succ..." << endl;
    }
    else
    {
        //转换失败返回空指针
        cout << "bar3 pE error..." << endl;
    }

    D* pd3= static_cast<D *>(pE);    //right    //基类指针指向子类
    if (pd3)
    {
        cout << "bar3 pd3 succ..." << endl;
    }
    else
    {
        //转换失败返回空指针
        cout << "bar3 pd3 error..." << endl;
    }
    E* pd4 = static_cast<E *>(pD);   //right    //强制转换 OK 基类指针到子类指针
                                                //但是不安全  若pd4调用E有而D没有的,则访问越界


    E* pE2;
    // F* pF = static_cast<F*>(pE2);    //error 继承于统一类的派生指针之间转换 
    // E* pF3 = static_cast<E*>(pF);    //error 继承于统一类的派生指针之间转换

    F* pF2;
    // G* pG = static_cast<G*>(pF2);    //error 两个无关联之间转换
}

void bar4()
{
    D objd;
    E obje;
    G objg;

    objd = static_cast<D&>(obje);     //转换为基类引用    
    objd = static_cast<D>(obje);        
    // obje = static_cast<E>(objd);      //error 不能进行转换 不能讲D赋值给E
    // objg = static_cast<G&>(objd);    //error 不能进行转换 不能讲D赋值给E
    // objg = static_cast<G>(objd); 
    
    /*
        所以,如果让以上代码通过编译,
        那么B类必须含有以A类的对象(或对象的引用)为参数的构造函数。
        如下:

        B(A& a)
        {
            // ...
        }
    */
}


int main()
{
    A *pa = new A();
    B *pb = new B();
    bar1(pa);
    C *pc = new C();
    bar1_2(pa,pc);

    bar2();

    D *pd = new D();
    bar3(pd);
    bar4();
    return 0;
}

[1] https://www.cnblogs.com/larry-xia/p/10325643.html
[2] https://blog.csdn.net/zhouwei1221q/article/details/44978361
[3] https://www.cnblogs.com/pigerhan/archive/2013/02/26/2933590.html

吐槽: Markdown真难用

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值