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
- 有繼承都 ok 但是 B=static_cast(A) 不安全
- 無繼承 一般不 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
- 編譯 通過 必須有多态 有虛函數 可以沒有繼承 但存在 NULL
- 轉換成功,必須多态,繼承,
基類指向子類 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真難用