首頁 > 軟體

C++ Boost Conversion超詳細講解

2022-11-25 14:00:16

一、說明

Boost.Conversion 在標頭檔案 boost/cast.hpp 中定義了轉換運運算元 boost::polymorphic_cast 和 boost::polymorphic_downcast。它們旨在更精確地處理型別轉換——通常使用 dynamic_cast 完成。

庫由兩個檔案組成。分別在boost/cast.hpp檔案中定義了boost::polymorphic_castboost::polymorphic_downcast這兩個型別轉換操作符, 在boost/lexical_cast.hpp檔案中定義了boost::lexical_cast

二、範例和程式碼

boost::polymorphic_castboost::polymorphic_downcast是為了使原來用dynamic_cast實現的型別轉換更加具體。具體細節,如下例所示。

struct father 
{ 
  virtual ~father() { }; 
}; 
struct mother 
{ 
  virtual ~mother() { }; 
}; 
struct child : 
  public father, 
  public mother 
{ 
}; 
void func(father *f) 
{ 
  child *c = dynamic_cast<child*>(f); 
} 
int main() 
{ 
  child *c = new child; 
  func(c); 
  father *f = new child; 
  mother *m = dynamic_cast<mother*>(f); 
} 

本例使用dynamic_cast型別轉換操作符兩次: 在func()函數中,它將指向父類別的指標轉換為指向子類的指標。在main()中, 它將一個指向父類別的指標轉為指向另一個父類別的指標。第一個轉換稱為向下轉換(downcast),第二個轉換稱為交叉轉換(cross cast)。

通過使用 Boost.Conversion 的型別轉換操作符,可以將向下轉換和交叉轉換區分開來。

#include <boost/cast.hpp> 
struct father 
{ 
  virtual ~father() { }; 
}; 
struct mother 
{ 
  virtual ~mother() { }; 
}; 
struct child : 
  public father, 
  public mother 
{ 
}; 
void func(father *f) 
{ 
  child *c = boost::polymorphic_downcast<child*>(f); 
} 
int main() 
{ 
  child *c = new child; 
  func(c); 
  father *f = new child; 
  mother *m = boost::polymorphic_cast<mother*>(f); 
} 

boost::polymorphic_downcast
 型別轉換操作符只能用於向下轉換。 它內部使用 
static_cast
 實現型別轉換。 由於 
static_cast
 並不動態檢查型別轉換是否合法,所以 
boost::polymorphic_downcast
 應該只在型別轉換是安全的情況下使用。 在偵錯(debug builds)模式下, 
boost::polymorphic_downcast
 實際上在 
assert ()
函數中使用
 dynamic_cast
 驗證型別轉換是否合法。 請注意這種合法性檢測只在定義了
NDEBUG
宏的情況下執行,這通常是在偵錯模式下。

向下轉換最好使用boost::polymorphic_downcast, 那麼boost::polymorphic_cast就是交叉轉換所需要的了。 由於dynamic_cast是唯一能實現交叉轉換的型別轉換操作符,boost::polymorphic_cast內部使用了它。 由於boost::polymorphic_cast能夠在錯誤的時候丟擲std::bad_cast型別的異常,所以優先使用這個型別轉換操作符還是很有必要的。相反,dynamic_cast在型別轉換失敗使將返回0。 避免手工驗證返回值,boost::polymorphic_cast提供了自動化的替代方式。

boost::polymorphic_downcastboost::polymorphic_cast只在指標必須轉換的時候使用;否則,必須使用dynamic_cast執行轉換。 由於boost::polymorphic_downcast是基於static_cast,所以它不能夠,比如說,將父類別物件轉換為子類物件。 如果轉換的型別不是指標,則使用boost::polymorphic_cast執行型別轉換也沒有什麼意義,而在這種情況下使用dynamic_cast還會丟擲一個std::bad_cast異常。

雖然所有的型別轉換都可用dynamic_cast實現,可boost::polymorphic_downcastboost::polymorphic_cast也不是真正隨意使用的。 Boost.Conversion 還提供了另外一種在實踐中很有用的型別轉換操作符。 體會一下下面的例子。

#include <boost/lexical_cast.hpp> 
#include <string> 
#include <iostream> 
int main() 
{ 
  std::string s = boost::lexical_cast<std::string>(169); 
  std::cout << s << std::endl; 
  double d = boost::lexical_cast<double>(s); 
  std::cout << d << std::endl; 
} 

型別轉換操作符boost::lexical_cast可將數位轉換為其他型別。 例子首先將整數169轉換為字串,然後將字串轉換為浮點數。

boost::lexical_cast內部使用流(streams)執行轉換操作。 因此,只有那些過載了operator<<()operator>>()這兩個操作符的型別可以轉換。 使用boost::lexical_cast的優點是型別轉換出現在一行程式碼之內,無需手工操作流(streams)。 由於流的用法對於型別轉換不能立刻理解程式碼含義, 而boost::lexical_cast型別轉換操作符還可以使程式碼更有意義,更加容易理解。

請注意boost::lexical_cast並不總是存取流(streams);它自己也優化了一些資料型別的轉換。

如果轉換失敗,則丟擲boost::bad_lexical_cast型別的異常,它繼承自std::bad_cast

#include <boost/lexical_cast.hpp> 
#include <string> 
#include <iostream> 
int main() 
{ 
  try 
  { 
    int i = boost::lexical_cast<int>("abc"); 
    std::cout << i << std::endl; 
  } 
  catch (boost::bad_lexical_cast &e) 
  { 
    std::cerr << e.what() << std::endl; 
  } 
} 

三、更多範例程式碼

本例由於字串 "abc" 不能轉換為int型別的數位而丟擲異常。

範例 54.1。使用 dynamic_cast 向下和交叉投射

struct base1 { virtual ~base1() = default; };
struct base2 { virtual ~base2() = default; };
struct derived : public base1, public base2 {};
void downcast(base1 *b1)
{
  derived *d = dynamic_cast<derived*>(b1);
}
void crosscast(base1 *b1)
{
  base2 *b2 = dynamic_cast<base2*>(b1);
}
int main()
{
  derived *d = new derived;
  downcast(d);
  base1 *b1 = new derived;
  crosscast(b1);
}

Example54.1

範例 54.1 兩次使用了轉換運運算元 dynamic_cast:在 downcast() 中,它將指向基礎類別的指標轉換為指向派生類的指標。在 crosscast() 中,它將指向基礎類別的指標轉換為指向不同基礎類別的指標。第一個轉換是向下轉換,第二個轉換是交叉轉換。 Boost.Conversion 中的轉換運運算元讓您可以區分向下轉換和交叉轉換。

範例 54.2。使用 polymorphic_downcast 和 polymorphic_cast 進行向下和交叉轉換

#include <boost/cast.hpp>
struct base1 { virtual ~base1() = default; };
struct base2 { virtual ~base2() = default; };
struct derived : public base1, public base2 {};
void downcast(base1 *b1)
{
  derived *d = boost::polymorphic_downcast<derived*>(b1);
}
void crosscast(base1 *b1)
{
  base2 *b2 = boost::polymorphic_cast<base2*>(b1);
}
int main()
{
  derived *d = new derived;
  downcast(d);
  base1 *b1 = new derived;
  crosscast(b1);
}

boost::polymorphic_downcast(參見範例 54.2)只能用於向下轉型,因為它使用 static_cast 來執行轉換。因為 static_cast 不會動態檢查轉換的有效性,boost::polymorphic_downcast 必須僅在轉換安全時使用。在偵錯版本中,boost::polymorphic_downcast 使用 dynamic_cast 和 assert() 來確保型別轉換有效。只有在未定義宏 NDEBUG 時才會執行此測試,這通常是偵錯版本的情況。

boost::polymorphic_cast 是交叉轉換所必需的。 boost::polymorphic_cast 使用 dynamic_cast,它是唯一可以執行交叉轉換的轉換運運算元。最好使用 boost::polymorphic_cast 而不是 dynamic_cast,因為前者在出現錯誤時丟擲 std::bad_cast 型別的異常,而 dynamic_cast 在型別轉換失敗時返回空指標。

僅使用 boost::polymorphic_downcast 和 boost::polymorphic_cast 來轉換指標;否則,使用 dynamic_cast。因為 boost::polymorphic_downcast 是基於 static_cast 的,所以它不能將基礎類別的物件轉換為派生類的物件。此外,使用 boost::polymorphic_cast 轉換指標以外的型別沒有意義,因為如果轉換失敗,dynamic_cast 將丟擲 std::bad_cast 型別的異常。

到此這篇關於C++ Boost Conversion超詳細講解的文章就介紹到這了,更多相關C++ Boost Conversion內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com