1. 程式人生 > >c++小技巧(三)更好的型別轉換implicit_cast和down_cast

c++小技巧(三)更好的型別轉換implicit_cast和down_cast

在C++中有四種類型轉換

1.static_cast:這個是最常用的型別轉換,凡是C++隱式執行的型別轉換都可以用static_cast顯式完成。在隱式轉換時有時編譯器會有警告資訊,但是顯示轉換(使用static_cast)就不會有。static_cast還會進行一些基礎的型別檢查,能在編譯期發現錯誤。

float f=0;
int a=(int)f; //強行轉換,可能會有警告
int a=static_cast<int>f; //使用static_cast消除警告

2.const_cast:從名字可以看出和const有關,這個轉換的作用是去除或新增const特性,它可以將一個const變數轉換為非const變數,或將一個非const變數轉換為const變數。
3.dynamic_cast

:dynamic_cast依賴於RTTI資訊,在轉換時,dynamic_cast會檢查轉換的source物件是否真的可以轉換成target型別,這種檢查不是語法上的,而是真實情況的檢查。被轉換的型別必須是多型(即有虛擬函式)。
4.interpret_cast:interpret意思為重新解釋,意思為將資料的二進位制格式重新解釋,它依賴機器。

implicit_cast和down_cast

  在muduo有另外兩個轉換implicit_cast和down_cast(看註釋應該是google的程式碼)。什麼時候用,為什麼用基本上都在註釋裡面了,可以重點看下。

// Use implicit_cast as a safe version of static_cast or const_cast
// for upcasting in the type hierarchy (i.e. casting a pointer to Foo // to a pointer to SuperclassOfFoo or casting a pointer to Foo to // a const pointer to Foo). // When you use implicit_cast, the compiler checks that the cast is safe. // Such explicit implicit_casts are necessary in surprisingly many // situations where C++ demands an exact type match instead of an
// argument type convertable to a target type. // // The From type can be inferred, so the preferred syntax for using // implicit_cast is the same as for static_cast etc.: // // implicit_cast<ToType>(expr) // // implicit_cast would have been part of the C++ standard library, // but the proposal was submitted too late. It will probably make // its way into the language in the future. template<typename To, typename From> inline To implicit_cast(From const &f) { return f; } // When you upcast (that is, cast a pointer from type Foo to type // SuperclassOfFoo), it's fine to use implicit_cast<>, since upcasts // always succeed. When you downcast (that is, cast a pointer from // type Foo to type SubclassOfFoo), static_cast<> isn't safe, because // how do you know the pointer is really of type SubclassOfFoo? It // could be a bare Foo, or of type DifferentSubclassOfFoo. Thus, // when you downcast, you should use this macro. In debug mode, we // use dynamic_cast<> to double-check the downcast is legal (we die // if it's not). In normal mode, we do the efficient static_cast<> // instead. Thus, it's important to test in debug mode to make sure // the cast is legal! // This is the only place in the code we should use dynamic_cast<>. // In particular, you SHOULDN'T be using dynamic_cast<> in order to // do RTTI (eg code like this: // if (dynamic_cast<Subclass1>(foo)) HandleASubclass1Object(foo); // if (dynamic_cast<Subclass2>(foo)) HandleASubclass2Object(foo); // You should design the code some other way not to need this. template<typename To, typename From> // use like this: down_cast<T*>(foo); inline To down_cast(From* f) // so we only accept pointers { // Ensures that To is a sub-type of From *. This test is here only // for compile-time type checking, and has no overhead in an // optimized build at run-time, as it will be optimized away // completely. if (false) { implicit_cast<From*, To>(0); } #if !defined(NDEBUG) && !defined(GOOGLE_PROTOBUF_NO_RTTI) assert(f == NULL || dynamic_cast<To>(f) != NULL); // RTTI: debug mode only! #endif return static_cast<To>(f); }

  在up_cast時應該使用implicit_cast替換static_cast,因為後者比前者要安全,以一個例子說明,在菱形繼承中,最底層的物件可以轉換為中層物件

#include<boost/implicit_cast.hpp>
#include<iostream>

class Top{};
class MiddleA:public Top{};
class MiddleB:public Top{};
class Bottom:public MiddleA,public MiddleB{};

void Function(MiddleA& A)
{
    std::cout<<"MiddleA Function"<<std::endl;
}
void Function(MiddleB& B)
{
    std::cout<<"MiddleB Function"<<std::endl;
}
int main()
{
    Bottom bottom;
    Function(bottom);
    return 0;
}

  這時如果編譯,就會出現錯誤,因為在呼叫函式Function時,bottom既可以預設轉換為MiddleA,也可以預設轉換為MiddleB,如果不明確指出就會出現歧義。這時可以改為:
Function(static_cast<MiddleA&>(bottom));Function(static_cast<MiddleB&>(bottom));
程式可以運行了。但是如果不小心這樣使用了:

Top top;
Function(static_cast<MiddleB&>top);

  這樣編譯可以通過,但是在執行時可能崩潰,因為top不是“一種”MiddleB,但是static_cast不能發現這個問題,這時如果用implicit_cast就不會有這個問題了,在編譯時就會給出錯誤資訊。static_cast不進行真正的型別檢查(在down_cast和up_cast的時候)。implicit_cast只能用在up_cast,當需要down_cast(這種形式)時候我們就應該使用上面的down_cast(上面的程式碼)。
down_cast在debug模式下內部使用了dynamic_cast進行驗證,在release下使用static_cast替換dynamic_cast。

為什麼使用down_cast而不直接使用dynamic_cast?

1.因為但凡程式設計正確,dynamic_cast就可以用static_cast來替換,而後者比前者更有效率。
2.dynamic_cast可能失敗(在執行時crash),執行時RTTI不是好的設計,不應該在執行時RTTI或者需要RTTI時一般都有更好的選擇。
知乎上有個討論 為什麼說不要使用 dynamic_cast,需要執行時確定型別資訊,說明設計有缺陷? - 知乎

總結

  在程式設計中,主要是我們自己程式碼編寫者要明確的知道當前是down_cast還是up_cast,up_cast那就使用implicit_cast,down_cast就用down_cast。

相關推薦

c++技巧()型別轉換implicit_castdown_cast

在C++中有四種類型轉換 1.static_cast:這個是最常用的型別轉換,凡是C++隱式執行的型別轉換都可以用static_cast顯式完成。在隱式轉換時有時編譯器會有警告資訊,但是顯示轉換(使用static_cast)就不會有。static_cast還會

【譯】《C# 技巧 -- 編寫優雅的 C#》原書名《C# Tips -- Write Better C#》

pos center book 優雅 int ntc code don sso 【譯】《C# 小技巧 -- 編寫更優雅的 C#》原書名《C# Tips -- Write Better C#》 目錄   介紹(Introduction)   第一部分:各種小技巧(Par

C#/.NET整數的種強制型別轉換(int)、Convert.ToInt32()、int.Parse()的區別總結

1.(int) 適合簡單資料型別之間的轉換,C#的預設整型是int32(不支援bool型)。 2. int.Parse(string sParameter) 是個建構函式,引數型別只支援string型別,Parse就是把String型別轉換成int,char,doubl

群用戶通過微信程序可以地協作了

bug space 隱藏 針對 簡單 完整 script 寬度 table   今天,小程序向開發者開放了群ID的接口能力。簡單地說,就是當你把小程序分享在群聊中,被點擊後開發者可獲取群ID和群名稱,也方便更好地針對群場景提供個性化服務。不同的群有各自的群ID,那麽這個新能

C語言第天-資料型別,if switch,for while

背會!!! 格式字元有d,o,x,u,c,s,f,e,g等。  如 %d整型輸出,%ld長整型輸出, %o以八進位制數形式輸出整數, %x以十六進位制數形式輸出整數,或輸出字串的地址。 %u以十進位制數輸出unsigned型資料(無符號數)。注意:%d與%u有無符號的數

SpringCloud-Eureka服務註冊與發現之開發技巧()

1.如何為服務起別名,即修改下面紅色部分 解決方案:在yml配置檔案中加入以下資訊 測試: 2.如何設定服務端的ip地址 解決方案: 在yml配置檔案中加入以下資訊

C++技巧

nullptr C++11引入,代表空指標,避免給指標賦值NULL時被編譯器替換為0 巨集 #define是巨集定義命令,前處理器將源程式檔案中出現的對巨集的引用展開成相應的巨集定義(單純當做是字串,沒有特定語法) 其主要目的是為程式設計師在程式設計時

C語言筆記 第四課 型別轉換

第四課 型別轉換 型別之間的轉換 C語言中的資料型別可以進行轉換 強制型別轉換 隱式型別轉換 強制型別轉換 強制型別轉換的語法 (Type)var_name; (Type)value; 強制型別轉換的結果 目標型別能夠容納目標值:結果不變 目標型別不能容納目標值:結果將產生截斷

C# 型別轉換isas

看書得來的知識點: //第一種轉換 if(elem is Solid) { Solid solid=elem as Solid; } //第二種轉換 Solid solid=elem as Solid; if(solid!=null) ...... 在第一種方式中,CLR

c語言中32為地址型別轉換為64位整數型別

uint64_t idt_operand = ((sizeof(idt) - 1) | ((uint64_t)(uint32_t)idt << 16)); idt是陣列名,也就是結構陣列型別的指標。static struct gate_desc idt[IDT

C#技巧總結

.Net中的DateTime結構類中的MinValue和MaxValue有時會引發一個異常,那就是日期溢位的問題,您輸入的日期必須介於 1753 年 1 月 1 日到 9999 年 12 月 31 日之間,而DateTime.MinValue實際上不是1753 年 1 月 1日,而是0000年1月1日,而資料

Qt技巧:Qt常用資料型別轉換

1、QString與int、long、double、float int 轉 QString int a = 10; QString b; b=QString::number(a); QString 轉 int 注意:基數預設為10。當基數為10時,並且基數必須在2到36之

C語言進階剖析 04 型別轉換

型別之間的轉換 C語言中的數型別可以進行轉換     ○ 強制型別轉換     ○ 隱世型別轉換 void code_1() { long l = 800; int i

C++中的4個與型別轉換相關的關鍵字

在C/C++語言中用 (type) value(在C++還可以採用type(value))來進行顯式型別轉換(explicit type conversion),常常又被稱為強制轉換(cast投射/鑄模)。這種轉換的正確性完全掌握在程式設計師手中,傳統上強制轉換往往被過度使

技術卻進不了大公司?程式設計師面試的幾個技巧請收

有很多程式設計師,專業技術挺好,專案經驗充足,簡歷上金碧輝煌,也面試了很多國內大廠,但就是沒有一家能成功的。處境可以說是相當尷尬。 大家都知道程式設計師本身就是要吃年輕飯,不僅是技術活,也是體力活。早點跳槽,早點漲薪,就顯得格外的重要了。 那麼我就給大家分享一下程式設計師面試的幾個小技巧: 1.面試準備要

C++ 高階篇(四)—— 型別轉換高階

目前為止,我們一直使用傳統的型別轉換符來進行簡單物件的型別轉換。例如,要把一個double型別的浮點型數字轉換為int 的整型數字,我們是這樣做的: int i; double d; i = (int) d; 或者 i = int (d); 這樣做對基本資料型別時沒問題的,

C++中的四種強制型別轉換的區別

使用標準C++的型別轉換符:static_cast、dynamic_cast、reinterpret_cast、和const_cast。 1 static_cast 用法:static_cast < type-id > ( expression

端位元組序 強制型別轉換

/* * ===================================================================================== * * Filename: point.c * * Descr

C++技巧彙總

// “d:\錄取i.txt”改成”d:\錄取‘’+i +“.txt” string filename = “d:\錄取”; char index = i + ‘0’;//數字i轉換成字元i filename = filename + index + “.

SpringBoot框架搭建系列():解決日期轉換問題日期展示問題

本次我們解決問題:日期展示問題(返回的json中日期的格式是:"birthday":"1988-08-07T15:00:00.000+0000");需要轉化成指定的格式(年月日時分秒格式) 1、問題如 2、解決方案 在配置中加入 #時間戳統一轉換 spring.j