5.C++裏的4種新型類型轉換

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內容變換了,是由於變量jconst引用定義的,因此是個只讀變量.

 

示例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; //此行錯誤,不能轉換普通數據型
相關文章
相關標籤/搜索