C 中的顯式型別轉換

2021-08-14 13:48:12 字數 3785 閱讀 2577

寫c++**的時候,有時候不可避免的會使用型別轉換,良好的編碼風格中應該避免隱式轉換,隱式轉換有時候會產生不易察覺的問題。c++提供了四種顯示型別轉換方式,當然顯示的強制型別轉換也是需要盡量避免的。

四種顯示轉換具有相同的形式

cast_name

(expression)

type:是轉換的目標型別

expression:是要轉換的值

const_name:可以是static_cast、dynamic_cast、const_cast和reinterpret_cast四種中的一種

注意:如果type是引用型別,則結果是左值。

static_cast是用的最多的轉換方式,任何具有明確定義的型別轉換,都要不包含底層const,都可以使用,示例如下:

int j = 12;

double result = static_cast

(j)/1.2;

像上面這種轉換也可以使用隱式型別轉換,不過,編譯器會給出警告,一般工作中都會把所有的警告消除,或者把警告作為錯誤處理,防止因為警告產生的錯誤導致執行結果不正確。

static_cast也用於編譯器無法自動執行的型別轉換。例如我們把void*指標轉換成初始的型別指標:

double d = 12.34;

void *p = &d;

double *dp = static_cast

(p);

我們知道任何非常量物件的位址都可以存入void*,所以我們可以把double型別的物件位址存入void*,然後使用static_cast將其轉換成原來的型別。

注意,一定要確保轉換後的型別就是指標所指的型別,型別不符的話,產生的結果將是未定義的。

dynamic_cast支援執行時識別。執行時型別識別(run-time type identification,rtti)的功能有兩個運算子實現:

dynamic_cast的使用形式如下:

dynamic_cast

(e)dynamic_cast

(e)dynamic_cast

(e)

type必須是個類型別,並且通常情況下該型別應該含有虛函式。

在上面的所有形式中,e的型別必須符合以下三個條件中的乙個:

如果符合的話,則轉換成功,否則轉換失敗。

如果一條 dynamic_cast語句的轉換目標是指標型別失敗並且失敗了,則結果為0;如果轉換目標是引用型別並且失敗了,dynamic_cast會丟擲乙個bad_cast異常。

假定base類至少有乙個虛函式,derived是base的公有派生類,如果有乙個指向base的指標bp,則我們可以在執行時將它轉換成derived型別的指標:

if (derived *dp = dynamic_cast

(bp)) else

如果轉換失敗的話,dp為0,這時執行else分支。

我們可以對乙個空指標執行dynamic_cast操作,結果是所需型別的空指標。

注意上面在if語句中定義了dp,這樣做的好處是可以在乙個操作中同時完成型別轉換和條件檢查。而且,指標dp在if語句外部是不可訪問的。一旦轉換失敗,後續的**即使忘了做相應判斷,也不會接觸到這個未繫結的指標,從而確保程式是安全的。

引用型別的dynamic_cast和指標型別的dynamic_cast在轉換發生錯誤時表現略有不同。因為不存在所謂的空引用,所有對於引用型別來說,無法使用與指標型別完全相同的錯誤處理方式。對引用型別的型別轉換失敗時,程式丟擲乙個名為std::bad_cast的異常,該異常定義在typeinfo標頭檔案中。

我們使用如下方式改寫上面的程式:

void f(const base &b)  catch (bad_cast) 

}

const_cast用於改變物件的底層const。

頂層const(top-level const)表示指標本身是個常量;

底層const(low-level const)表示指標所指的物件是乙個常量。

int i = 0;

int *const p1 = &i; // 不能改變p1的值,這個乙個頂層const

const

int ci = 42; // 不能改變ci的值,這是乙個頂層const

const

int *p2 = &ci;// 允許改變p2的值,這是乙個底層const

const

int *const p3 = p2; // 靠右的const是頂層const,靠左的是底層const

const

int &r = ci; // 用於宣告的const都是底層const

對於將常量轉換成非常量的行為,稱之為「去掉const性質」。一旦我們去掉了const性質,編譯器就不再阻止我們對該物件進行寫操作了。

如果物件本身不是乙個常量,使用強制型別轉換獲得寫許可權是合法的行為,如果物件是乙個常量,再使用const_cast執行寫操作就會產生未定義的後果。

const

char *pc;

char *p = const_cast

(pc); // 正確,但是通過p寫值是未定義的行為

只有const_cast能改變表示式的常量屬性。不能使用const_cast改變表示式的型別。

const

char *cp;

char *q = static_cast

(cp); // 錯誤,不能轉換掉const性質

static_cast

cp; // 正確:字串字面值轉換成string型別

const_cast

(cp); // 錯誤:const_cast只改變常量屬性

reinterpret_cast是一種更加底層的轉換,reinterpret意為重新解釋。它可以轉化任何內建的資料型別為其他任何的資料型別,也可以轉化任何指標型別為其他的型別。它甚至可以轉化內建的資料型別為指標,無須考慮型別安全或者常量的情形。對它的使用要非常謹慎,實際上,這種轉換很少使用。

舉乙個簡單的例子:

int *ip;

char *pc = reinterpret_cast

(ip);

這裡pc指向的物件是乙個int,不是char,如果把pc當做普通的字元指標使用可能會在執行時發生錯誤。例如,以下語句可能導致異常的執行時行為:

string str(pc);
使用reinterpret_cast非常危險。用pc出事str的例子很好地證明了這點,其中的關鍵問題是型別改變了,但編譯器沒有給出任何警告或者錯誤的提示資訊。當我們用乙個int的位址初始化pc時,由於顯式地說明這種轉換合法,所以編譯器不會發出任何警告或任何錯誤資訊。接下來再使用pc時就會認定它的值是char*型別,編譯器沒法知道它實際存放的是int的指標。

最終的結果就是,上面的例子用pc初始化str沒什麼實際意義,甚至還可能引發更糟糕的結果,但僅從語法上這種操作是沒有問題的,查詢這類問題非常困難。

從上面的描述可以看出,c++為我們提供了多種轉換方式,但是還是建議盡量少用。在無法避免的情況下,使用顯式轉換優於隱式轉換,reinterpret_cast強烈建議不要使用。

更詳細的內容請查閱《c++ primer》第5版。

C 顯式型別轉換

對於型別轉換,我在查資料的時候看到了一種很有意思的解釋,我們可以這樣理解型別轉換 某塊記憶體中的資料是不變的,而型別就是我們戴上的眼鏡,當我們戴上一種眼鏡後,我們就會用對應的型別來解釋記憶體中的資料,這樣不同的解釋就得到了不同的資訊。所謂強制型別轉換實際上就是換上另一副眼鏡後再來看同樣的那塊記憶體資...

c 顯式型別轉換

乙個命名的強制型別轉換具有以下形式 cast name expression 其中,type是轉換的目標型別,而expression是要轉換的值。如果type是引用型別,則結果是左值。cast name是static cast dynamic cast const cast reinterpret ...

C 顯式型別轉換

c 的隱式型別轉換不在此文章講述範圍。c 的顯式型別轉換有 4 種 static cast dynamic cast const cast reinterpret cast。語法 cast name expression type 是轉換的目標型別,expression 是要轉換的值。cast na...