C++ 提供了五種特定的類型轉換:const_cast<>()、static_cast<>()、reinterpret_cast<>()、dynamic_cast<>() 和 C++20 引入的 std::bit_cast<>()。
請注意,舊的 C 風格類型轉換(如 (int)myFloat)在 C++ 中仍然有效,并在現有代碼庫中廣泛使用。C 風格的類型轉換涵蓋了所有四種 C++ 類型轉換,因此它們更容易出錯,因為您試圖實現的目的并不總是顯而易見的,可能會得到意外的結果。我強烈建議您在新代碼中只使用 C++ 風格的類型轉換,因為它們更安全,且在代碼中更加突出。
模糊基類出現在多個父類共有一個共同的父類時。推薦的解決方案是確保共享的父類自身不具有任何功能。這樣,其方法永遠不會被調用,從而避免了歧義問題。C++ 還有另一種機制,稱為虛擬基類,用于解決您希望共享的父類具有自己功能的情況。
如果共享的父類是一個虛擬基類,則不會有任何歧義。以下代碼在 Animal 基類中添加了一個 sleep() 方法,并修改了 Dog 和 Bird 類,使它們作為虛擬基類從 Animal 繼承。如果不使用虛擬基類,對 DogBird 對象的 sleep() 調用將是模糊的,并會生成編譯器錯誤,因為 DogBird 將具有兩個 Animal 子對象,一個來自 Dog,一個來自 Bird。然而,當 Animal 被虛擬繼承時,DogBird 只有一個 Animal 類的子對象,因此調用 sleep() 不會有歧義。
class Animal {public: virtual void eat() = 0; virtual void sleep() { cout << "zzzzz...." << endl; }};class Dog : public virtual Animal {public: virtual void bark() { cout << "Woof!" << endl; } void eat() override { cout << "The dog ate." << endl; }};class Bird : public virtual Animal {public: virtual void chirp() { cout << "Chirp!" << endl; } void eat() override { cout << "The bird ate." << endl; }};class DogBird : public Dog, public Bird {public: void eat() override { Dog::eat(); }};int main() { DogBird myConfusedAnimal; myConfusedAnimal.sleep(); // 因為虛擬基類而不模糊}
注意:虛擬基類是避免類層次結構中歧義的好方法。
C++ 提供了五種特定的類型轉換:const_cast<>()、static_cast<>()、reinterpret_cast<>()、dynamic_cast<>() 和 C++20 引入的 std::bit_cast<>()。第一種在第 1 章中討論過。第 1 章還介紹了用于某些基本類型之間轉換的 static_cast<>(),但在繼承的上下文中還有更多內容。現在您已經熟悉編寫自己的類并理解類繼承,是時候更仔細地看看這些類型轉換了。
請注意,舊的 C 風格類型轉換(如 (int)myFloat)在 C++ 中仍然有效,并在現有代碼庫中廣泛使用。C 風格的類型轉換涵蓋了所有四種 C++ 類型轉換,因此它們更容易出錯,因為您試圖實現的目的并不總是顯而易見的,可能會得到意外的結果。我強烈建議您在新代碼中只使用 C++ 風格的類型轉換,因為它們更安全,且在代碼中更加突出。
(1) 使用場景
static_cast()用于執行語言直接支持的顯式轉換。例如,將int轉換為double以避免整數除法:
int i { 3 };int j { 4 };double result { static_cast<double>(i) / j };
static_cast() 也可用于執行因用戶定義的構造函數或轉換例程而允許的顯式轉換。例如,如果類 A 有一個接受 B 對象的構造函數,則可以使用 static_cast() 將 B 對象轉換為 A 對象。
(2) 在繼承中的應用
static_cast()可用于繼承層次結構中的向下轉型:
class Base { /* ... */ };class Derived : public Base { /* ... */ };Base* b { nullptr };Derived* d { new Derived{} };b = d; // 向上轉型,不需要轉換。d = static_cast<Derived*>(b); // 向下轉型,需要轉換。
(3) 注意事項
(1) 使用場景
(2) 注意事項
(1) 特點
(2) 示例
float asFloat { 1.23f };auto asUint { bit_cast<unsigned int>(asFloat) };if (bit_cast<float>(asUint) == asFloat) { cout << "Roundtrip success." << endl;}
(3) 應用場景
bit_cast() 的一個用例是用于平凡可復制類型的二進制 I/O。例如,可以將這些類型的單個字節寫入文件,讀取文件時,可以使用 bit_cast() 正確解釋從文件讀取的字節。
平凡可復制類型通常具有以下特征:
(1) 特點
(2) 示例
Base* b;Derived* d { new Derived{} };b = d;d = dynamic_cast<Derived*>(b);Base base;Derived derived;Base& br { base };try { Derived& dr { dynamic_cast<Derived&>(br) };} catch (const bad_cast&) { cout << "Bad cast!" << endl;}
(3) 與其他類型轉換的區別
情境 | 推薦的轉換方法 | 說明 |
移除 |
| 用于移除對象的 |
語言直接支持的顯式轉換 |
| 例如,從 |
用戶定義的構造函數或轉換支持的顯式轉換 |
| 用于用戶定義的轉換 |
一個類的對象轉換為另一個(無關)類的對象 |
| 用于無關類之間的對象轉換 |
同一繼承層次中的類的指針對象轉換 |
| 用于繼承層次中的指針對象轉換 |
同一繼承層次中的類的引用對象轉換 |
| 用于繼承層次中的引用對象轉換 |
不相關類型的指針轉換 |
| 用于完全不相關的指針類型之間的轉換 |
不相關類型的引用轉換 |
| 用于完全不相關的引用類型之間的轉換 |
函數指針之間的轉換 |
| 用于函數指針之間的轉換 |
本文鏈接:http://www.www897cc.com/showinfo-26-31013-0.htmlC++ 20類型轉換指南:使用場景與優秀實踐
聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com
上一篇: Go vs Rust:文件上傳性能比較