原文地址:http://www.cnblogs.com/TianFang/archive/2008/09/24/1298344.html
Boost的轉換函式(一)
Boost的轉換函式是對C++中的四種類型轉換函式(const_cast,reinterpret_cast,static_cast,dynamic_cast)的一些補充和擴充,在閱讀本文前,請先熟悉C++中的四種類型轉換函式相關知識。
C++提供了dynamic_cast來實現運行時的類型轉換,但是如果用來轉換指標時,需要記得檢查傳回值(這是很多程式員容易忘掉的地方),否則一旦轉換失敗,將獲得一個NULL指標,無異於給程式埋下了一個定時炸彈。
Boost的polymorphic_cast在dynamic_cast的基礎上增加了對傳回值的檢測,如果轉換失敗,它就會拋出std::bad_cast異常。其函數體如下:
template <class Target, class Source>
inline Target polymorphic_cast(Source* x BOOST_EXPLICIT_DEFAULT_TARGET)
{
Target tmp = dynamic_cast<Target>(x);
if ( tmp == 0 ) throw std::bad_cast();
return tmp;
}
雖然拋異常增加了開銷,但使用起來卻更加簡單了。
由於拋出異常會降低程式的效率,而且dynamic_cast更會查詢一個type_info結構來確定正確的類型,所以不管是空間上的成本還是時間上的成本,都會大大增加。在一些應用情境中,只需要在編譯期間進行類型轉換即可。這時我們可以使用static_cast來實現編譯期間的類型轉換,但static_cast可能導致錯誤的類型轉換:
struct A
{
virtual ~A(){}
};
class B:public A{};
class C:public A{};
int main()
{
A *pa = new C();
B *pb = static_cast<B*>(pa);
}
對於上述程式,雖然pa和pb間沒有繼承關係,但是這個轉換卻可以通過,運行時也不會報任何錯誤,可一旦對pb進行訪問,就會得到錯誤的結果甚至直接導致程式死掉。
polymorphic_downcast就巧妙的解決的這一問題,首先還是先看看它的定義:
template <class Target, class Source>
inline Target polymorphic_downcast(Source* x BOOST_EXPLICIT_DEFAULT_TARGET)
{
BOOST_ASSERT( dynamic_cast<Target>(x) == x ); // detect logic error
return static_cast<Target>(x);
}
從它的定義可以看出,在運行Release模式下,它和是static_cast一樣的,也就是說它的Release版具有和static_cast一樣的開銷。但在Debug模式下,它會首先進行一次動態轉換,而一旦類型不符,就會拋出異常。
在上述程式中,如果用polymorphic_downcast來替換static_cast的話,我們可以先在Debug模式下運行程式,如果有錯誤的類型轉換,將很容易的檢測出來。待改正所有的錯誤後,再發布Release版,這樣即沒有動態轉換造成的開銷,又杜絕了錯誤的類型轉換。
完
Boost的轉換函式是對C++中的四種類型轉換函式(const_cast,reinterpret_cast,static_cast,dynamic_cast)的一些補充和擴充,在閱讀本文前,請先熟悉C++中的四種類型轉換函式相關知識。
C++提供了dynamic_cast來實現運行時的類型轉換,但是如果用來轉換指標時,需要記得檢查傳回值(這是很多程式員容易忘掉的地方),否則一旦轉換失敗,將獲得一個NULL指標,無異於給程式埋下了一個定時炸彈。
Boost的polymorphic_cast在dynamic_cast的基礎上增加了對傳回值的檢測,如果轉換失敗,它就會拋出std::bad_cast異常。其函數體如下:
template <class Target, class Source>
inline Target polymorphic_cast(Source* x BOOST_EXPLICIT_DEFAULT_TARGET)
{
Target tmp = dynamic_cast<Target>(x);
if ( tmp == 0 ) throw std::bad_cast();
return tmp;
}
雖然拋異常增加了開銷,但使用起來卻更加簡單了。
由於拋出異常會降低程式的效率,而且dynamic_cast更會查詢一個type_info結構來確定正確的類型,所以不管是空間上的成本還是時間上的成本,都會大大增加。在一些應用情境中,只需要在編譯期間進行類型轉換即可。這時我們可以使用static_cast來實現編譯期間的類型轉換,但static_cast可能導致錯誤的類型轉換:
struct A
{
virtual ~A(){}
};
class B:public A{};
class C:public A{};
int main()
{
A *pa = new C();
B *pb = static_cast<B*>(pa);
}
對於上述程式,雖然pa和pb間沒有繼承關係,但是這個轉換卻可以通過,運行時也不會報任何錯誤,可一旦對pb進行訪問,就會得到錯誤的結果甚至直接導致程式死掉。
polymorphic_downcast就巧妙的解決的這一問題,首先還是先看看它的定義:
template <class Target, class Source>
inline Target polymorphic_downcast(Source* x BOOST_EXPLICIT_DEFAULT_TARGET)
{
BOOST_ASSERT( dynamic_cast<Target>(x) == x ); // detect logic error
return static_cast<Target>(x);
}
從它的定義可以看出,在運行Release模式下,它和是static_cast一樣的,也就是說它的Release版具有和static_cast一樣的開銷。但在Debug模式下,它會首先進行一次動態轉換,而一旦類型不符,就會拋出異常。
在上述程式中,如果用polymorphic_downcast來替換static_cast的話,我們可以先在Debug模式下運行程式,如果有錯誤的類型轉換,將很容易的檢測出來。待改正所有的錯誤後,再發布Release版,這樣即沒有動態轉換造成的開銷,又杜絕了錯誤的類型轉換。