C++的類型轉換

C++的類型轉換

類型轉換4大金剛:c++

  • static_cast --- 執行基礎轉換
  • const_cast ---- (添加或者)移除 const
  • dynamic_cast ---- 執行已檢查的多態轉換,沿着繼承層次結構安全地將指針和引用轉換爲向上、向下和橫向的類
  • reinterpret_cast --- 執行通常的低級轉換

static_cast使用場景

使用隱式轉換和用戶定義轉換的組合在類型之間進行轉換安全

語法:
static_cast < new_type > ( 表達式 )
返回type的值new_type架構

如下總結常使用static_cast的場景函數

1. 初始化時轉換

//1.initializing conversion
    int n = static_cast<int>(3.14159);
    cout << "n = "<<n<<"\n"; //n=3

    std::vector<int> v = static_cast<std::vector<int>>(10);
    cout << "size of v is "<<v.size()<<"\n"; //10

打印值在註釋中,經過static_cast將某些類型作「靜態」轉變後成爲咱們但願的類型,並能正確初始化。this

2. static downcast

struct B{
    static const int m = 0;
    void hello() const {
        cout <<"hello ,this is B"<<"\n";
    }
};

struct D:B
{
    void hello() const{
        cout << "hello,this is D"<<"\n";
    }
};

//2. static downcast
    D d;
    B& br = d;
    br.hello(); //hello ,this is B
    D& anther_d = static_cast<D&>(br);
    anther_d.hello();//hello ,this is D

br經過隱式類型轉換後做爲d的引用,雖然d是D類型的,可是調用的hello還是B的hello函數,使用static_cast顯式downcast後,調用D的hello。這裏有一個問題是,hello並非虛函數,即時D繼承B,B和D都有一個hello,可是這裏的hello函數並非動態綁定的,仍在編譯期綁定this的類型。所以br是B類型,而anther_d是D類型的(這裏有疑問!!?)
若是hello是虛函數,那麼怎麼解釋呢?指針

3. 隱式轉換翻轉

void* nv = &n;
    int* ni = static_cast<int*>(nv);
    std::cout << "*ni = " << *ni << '\n';

這算是static_cast 最經常使用的用法了,經過void指針將類型反轉賦值。void能夠經過static_cast轉變爲任意指針類型。code

4. enum類型轉換

enum E{ONE = 1,TWO,THREE};
E e = E::ONE;
int one = static_cast<int>(e);
cout << "one : "<<one <<"\n";

const_cast使用場景

1. 通常的const移除

int i = 4;
const int& rci = i ;
const_cast<int&>(rci) = 8;

const int j = 33;
int*pj = const_cast<int*>(&j);
//DO not use like below !
// *pj = 333;
// cout << "const int j = "<< j <<"\n";

2. 在類的const成員函數中:

struct type{
    int i ;

    type() :i(3){}
    void f(int v) const{
    //if we want to modify i 
    //we cannot use this->i = v; directly;
    //becuse this pointer is const ,
    //we shall use const_cast this pointer
    const_cast<type*>(this)->i = v;
    }
};

type t;
t.f(40) ;
cout << "type i = "<<t.i <<"\n";

使用const修飾的成員函數,咱們將沒法經過this指針,修改其成員變量,由於咱們能夠將this指針使用const_cast轉換爲non-const的,只是,你真的肯定要這麼作麼?!繼承

dynamic_cast 使用場景

必須是多態場景,存在基類與派生類的類型轉換;若是轉換成功,dynamic_cast返回類型爲new_type的值。若是轉換失敗,而new_type是指針類型,則返回該類型的空指針。若是轉換失敗,而且new_type是引用類型,它將拋出一個異常,該異常與類型std::bad_cast的處理程序匹配。內存

struct Base {
    virtual ~Base() {}
};
 
struct Derived: Base {
    virtual void name() {}
};

void testDynamic_cast()
{
    Base *b1 = new Base;
    if(Derived*d = dynamic_cast<Derived*>(b1)){
        cout << "downcast from b1 to d successful\n";
        d->name();
    }

    Base *b2 = new Derived;
    if(Derived*d = dynamic_cast<Derived*>(b2)){
        cout << "downcast from b2 to d successful\n";
        d->name();
    }

    delete b1;
    delete b2;
}

輸出
downcast from b2 to d successfulci

可見b1的dynamic_cast轉換是失敗的。緣由是顯而易見的 ,此時的b1指針並無指向其派生類,天然不能進行動態轉換。可是,在C類型的轉換中,這樣的轉換是沒有任何提示和預見性的,因此,C類型的轉換應該被全線禁止掉。

reinterpret_cast的使用場景

標準文檔上的解釋是:經過從新解釋底層位模式在類型之間進行轉換

與static_cast不一樣,但與const_cast類似,reinterpret_cast表達式不會編譯成任何CPU指令(除非在整數和指針之間進行轉換,或者在指針表示依賴於其類型的模糊架構上進行轉換)。

它純粹是一個編譯時指令,指示編譯器將表達式視爲具備new_type類型

unsigned int i = 0x12345678;

char* p1 = reinterpret_cast<char*>(&i);
if(p1[0] == '\x78')
    cout << "This system is little-endian\n";
else 
    cout << "This system is big-endian\n";

p1指針將i的地址重現解釋爲char*類型。這裏順便複習下大小端的知識,78是i的低字節位,若是它位於unsigned int內存的低地址區域則說明系統爲小端,不然爲大端。

以上,說明了四種C++類型轉換表達式的使用場景,按我我的理解小結下:

  • 若是但願在內存指針層面對指針從新解釋,也是就讓編譯器認爲這個指針是某個類型,則須要使用reinterpret_cast,
  • 若是涉及到基類和派生類指針的動態轉換,則使用dynamic_cast;
  • 若是須要移除const屬性,則須要使用const_cast;
  • 其他狀況就使用static_cast吧。
相關文章
相關標籤/搜索