1首先來回顧C的強制轉換ios
你們都知道,在編譯C語言中的強制轉換時,編譯器不會檢查轉換是否成功,都會編譯正確.函數
好比:spa
#include "stdio.h" struct Position { int x; int y; }; int main() { int i; struct Position *p; i=0x123456; p=(struct Position *)i; printf("px=%d,py=%d\n",p->x,p->y); }
輸出結果以下圖所示:指針
從上圖能夠看到,只有當運行代碼時,纔會出現段錯誤問題.code
當C代碼上千行時,若出現這種問題,是很是難找的.對象
2.C++的新型類型轉換blog
因此在C++中,便引入了4種強制類型轉換繼承
2.1 static_cast(靜態類型轉換)ci
- 用於基本數據類型以及對象之間的轉換(char,int,const int等)
- 不能用於基本數據類型指針之間的轉換(char *,int *等)
- 用於有繼承關係類對象指針之間的轉換
- 用於類指針之間的轉換
示例-基本數據:編譯器
int i = 0x45; char c = 'c'; c = static_cast<char>(i); //char* pc = static_cast<char*>(&i); //此行錯誤,不能用於基本指針之間轉換
示例-基本數據與對象轉換:
class Test{ public: explicit Test(int i) //只能顯示調用 { cout<<i<<endl; } }; int main() { Test t = static_cast<Test>(3.55); //等價於 : Test t(3); }
示例-有繼承關係的類對象指針轉換:
class Parent { public: int mm; Parent(int i) { mm=i; cout<<"Parent:"<<i<<endl; } }; class Child : public Parent { public: int mval; Child(int i):Parent(i) { mval=i; cout<<"Child:"<<i<<endl; } }; int main() { Parent *p =new Parent(3); //會調用父類構造函數 Child *c = static_cast <Child *> (p) ; //並不會調用子類構造函數,此時的mval成員爲隨機值 c->mval=100; cout<<"mval:"<<c->mval<<endl;
cout<<"mm:"<<c->mm<<endl; //此時的c->mm指向的對象就是p->mm
c->mm=100; //修改c->mm 等價於修改p->mm
cout<<"mm:"<<p->mm<<endl;
}
運行打印:
Parent:3 mval:100
mm:3
mm:100
2.2 const_cast(去常類型轉換)
- 經常使用於去除const類對象的只讀屬性
- 且強制轉換的類型必須是指針*或引用&
示例1:
const int x =1; //const:定義一個常量x const int& j =2; //const引用:定義一個只讀變量j int& p1= const_cast<int&>(x); //強制轉換int & int *p2 = const_cast<int*>(&j); //強制轉換int* //int p3 = const_cast<int>(j); //此行錯誤,不能轉換普通數據型 p1=3; *p2=4; printf("x=%d, j=%d\n",x,j); printf("p1=%d *p2=%d\n",p1,*p2);
輸出結果:
x=1 j=4 p1=3 *p2=4
從輸出結果,能夠看出修改p1,p2,只有j內容變換了,是由於變量j用const引用定義的,因此是個只讀變量.
示例2-去除const類對象的只讀屬性
class Test { public: int mval; Test():mval(10) { } }; int main() { const Test n1; //n1.mval = 100; //error,不能直接修改常量對象的成員 Test *n2 = const_cast<Test *>(&n1); //經過指針*轉換 Test &n3 = const_cast<Test &>(n1); //經過引用&轉換 n2->mval = 20; cout<<n1.mval<<endl; //打印20 n3.mval = 30; cout<<n1.mval<<endl; //打印30 }
2.3 dynamic_cast(動態類型轉換)
- 用於有繼承關係的類指針(引用)間的轉換
- 用於有交叉關係的類指針(引用)間的轉換
- 具備類型檢查的功能,編譯時會去檢查使用的方法是否正確,轉換是否成功只有在程序運行時才能知道
- 類中必須有虛函數的支持
- 不能用於基本數據類型指針之間的轉換(char *,int *等)
-當轉換爲指針時:
- 轉換成功 : 獲得目標類型的指針
- 轉換失敗 : 獲得一個空指針
-當轉換爲引用時:
- 轉換成功 : 獲得目標類型的引用
- 轉換失敗 : 獲得一個異常操做信息
示例-經過子類指針去指向父類:
#include <iostream> using namespace std; class Base { public: Base() { cout << "Base::Base()" << endl; } virtual ~Base() { cout << "Base::~Base()" << endl; } }; class Derived : public Base { }; int main() { Base* p = new Base; //初始化父類指針 Derived* pd = dynamic_cast<Derived*>(p); //因爲父類指針指向的是父類,沒有子類虛函數表,因此轉換失敗 cout << "pd = " << pd << endl; //轉換失敗,打印 0
delete p; p = new Derived; pd = dynamic_cast<Derived*>(p); //因爲父類指針指向的是子類,因此有子類虛函數表 cout <<"pd = " << pd <<endl; //轉換成功,打印地址值 delete p; return 0; }
示例-經過多重繼承下的類指針轉換:
class BaseA { public: virtual void funcA() { cout<<"BaseA: funcA()"<<endl; } };
class BaseB { public: virtual void funcB() { cout<<"BaseB: funcB()"<<endl; } };
class Derived : public BaseA,public BaseB { };
int main() { Derived d; BaseA *pa=&d; pa->funcA(); //打印 BaseA: funcA() /*經過強制轉換執行*/ BaseB *pb=(BaseB *)pa; pb->funcB(); //仍是打印 BaseA: funcA(), 由於pb仍是指向pa,執行的仍是pa的虛函數表 /*經過dynamic_cast執行*/ pb = dynamic_cast<BaseB *>(pa); pb->funcB(); //打印 BaseB: funcB() //編譯器會去檢測pa所在的地址,發現有多個虛函數表,而後根據 <BaseB *>來修正指針pb return 0; }
2.4 reinterpret_ cast(解讀類型轉換)
- 用於全部指針的強制轉換
(解讀是指:對要轉換的數據進行從新的解讀)
例如:
int i = 0; char j='c'; int *p1=reinterpret_cast<int *>(&i); char *p2=reinterpret_cast<char *>(&j); //int p3=reinterpret_cast<int >i; //此行錯誤,不能轉換普通數據型