c++中的類型轉換(dynamic_cast, reinterpret_cast, static_cast ,const_cast)

在c++中提供瞭如下方式的類型轉換:

dynamic_cast <new_type> (expression)
reinterpret_cast <new_type> (expression)
static_cast <new_type> (expression)
const_cast <new_type> (expression)

dynamic_cast

dynamic_cast只處理指針和對象的引用。其目的是確保類型轉換的結果是一個有效的完整的對象。

因此,dynamic_cast總是能成功地一個類轉換到它的一個基類。

class CBase { };
class CDerived: public CBase { };
CBase b; CBase* pb;
CDerived d; CDerived* pd;
pb = dynamic_cast<CBase*>(&d);     // ok: derived-to-base
pd = dynamic_cast<CDerived*>(&b);  // wrong: base-to-derived 

第二個轉換是錯誤的,除非基類是多態(polymorphic)。

當一個類是多態,dynamic_cast在運行時會執行一個特殊檢查,以確保表達式產生了一個有效的完整的對象:

// dynamic_cast
#include <iostream>
#include <exception>
using namespace std;

class CBase { virtual void dummy() {} };
class CDerived: public CBase { int a; };

int main () {
  try {
    CBase * pba = new CDerived;
    CBase * pbb = new CBase;
    CDerived * pd;

    pd = dynamic_cast<CDerived*>(pba);
    if (pd==0) cout << "Null pointer on first type-cast" << endl;

    pd = dynamic_cast<CDerived*>(pbb);
    if (pd==0) cout << "Null pointer on second type-cast" << endl;

  } catch (exception& e) {cout << "Exception: " << e.what();}
  return 0;
}

儘管兩者都是指針的類型CBase *,pba指向一個CDerived類型的對象,而從CDerived指向一個CBase類型的對象。因此,當他們各自的類型鑄件執行使用dynamic_cast,pba指向一個完整的CDerived類對象的類,而pbb指向一個不完整的CDerived類的對象。

兼容性注意:dynamic_cast需要運行時類型信息(RTTI)跟蹤動態類型。一些編譯器支持這個特性作爲一個選項,默認情況下是禁用的。這必須啓用運行時類型檢查使用dynamic_cast正常工作。.

dynamic_cast也可以轉換空指針甚至不相關的類之間的指針,也可以把任何類型的指針轉換到空指針(void *)。

reinterpret_cast

reinterpret_cast可以完成從任何指針類型到任何其他指針類型的轉換,甚至是不相關的類。

reinterpret_cast但不是static_cast的轉換在c++是低級操作,其解釋結果通常是系統相關的,因此不可移植的。

class A {};
class B {};
A * a = new A;
B * b = reinterpret_cast<B*>(a);
雖然b指向了一個不完整的對象,但是上面的語句是合法的,只不過,當b解引用可能時會產生運行時錯誤。

static_cast

static_cast可以執行相關類指針之間的轉換,可以從派生類到基類,也可以從基類到派生類。這將確保至少類是兼容的,如果適當的對象被轉換,但是在運行時沒有執行安全檢查,以檢查是否被轉換的對象實際上是一個完整的對象類型的目的地。

因此,程序員,以確保轉換是安全的。但另一方面,dynamic_cast避免的類型安全檢查的開銷。

class CBase {};
class CDerived: public CBase {};
CBase * a = new CBase;
CDerived * b = static_cast<CDerived*>(a);
雖然b指向了一個不完整的對象,但是上面的語句是合法的,只不過,當b解引用可能時會產生運行時錯誤。

此外,static_cast還可以完成基本類型之間的轉換。但是不能轉換const, volatile__unaligned等屬性。

const_cast

const_cast維護對象的常量屬性,可以設置或者去掉對象的常量屬性:

// const_cast
#include <iostream>
using namespace std;

void print (char * str)
{
  cout << str << endl;
}

int main () {
  const char * c = "sample text";
  print ( const_cast<char *> (c) );
  return 0;
}


typeid

typeid可以檢查變量的類型,並用name()加以輸出:

// typeid, polymorphic class
#include <iostream>
#include <typeinfo>
#include <exception>
using namespace std;

class CBase { virtual void f(){} };
class CDerived : public CBase {};

int main () {
  try {
    CBase* a = new CBase;
    CBase* b = new CDerived;
    cout << "a is: " << typeid(a).name() << '\n';
    cout << "b is: " << typeid(b).name() << '\n';
    cout << "*a is: " << typeid(*a).name() << '\n';
    cout << "*b is: " << typeid(*b).name() << '\n';
  } catch (exception& e) { cout << "Exception: " << e.what() << endl; }
  return 0;
}


參考:

[1]  http://www.cplusplus.com/doc/tutorial/typecasting/

[2]  http://msdn.microsoft.com/en-us/library/c36yw7x9%28v=vs.80%29.aspx






發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章