天天看點

類型轉換

在c++中,兩個類型相關的定義是:這兩個類型之間可以互相轉。

一、隐式轉換

c++不把兩個不同類型的值加在一起,而是提供了一組轉換規則,以便在執行算數操作前将兩個操作數轉換為同一種類型。這類不需要程式員介入而直接執行的轉換稱為隐式類型轉換。

c++定義的算術類型之間的内置轉換盡可能防止精度損失。編譯器在必要時将類型轉換規則應用到内置類型和類類型的對象。

1、發生隐式類型轉換的情況:

(1)、在混合類型表達式中,其操作數被轉換為相同的類型:

(2)、用作條件表達式被轉換為bool類型:

條件操作符(?:)中的第一個操作數以及邏輯非(!)、邏輯與(&&)和邏輯或(||)的操作數都是條件表達式。出現在if、while、for和do...while語句中的同樣也是條件表達式。

(3)、用一表達式初始化某個變量,或将一表達式指派給某個變量,則該表達式被轉換為該變量的類型:

2、算數轉換:

此類隐式轉換最常用,它保證在執行操作之前,将二進制操作符的兩個操作數轉換為同一類型,并使表達式的值也具有相同的類型。最簡單的轉換為整型提升:對所有比int小的整型,包括bool(0或1)、char、signed char、unsigned char、short和unsigned short,如果該類型的所有可能的值都能包容在int内,它們就會被提升為int型,否則,它們将被提升為unsigned int。

有符号與無符号類型之間的轉換:

這類轉換本質上依賴機器。因為如果表達式使用了無符号數值,那麼所定義的轉換規則需保護操作數的精度。而unsigned操作數的轉換依賴于機器中整型的相對大小。

對unsigned short/int和int/long的轉換,如果int/long型足夠表示unsigned short/int型的值,九江unsigned short/int轉換為int/long型,否則将兩個操作數轉換為unsigned int/long。

3、指針轉換:

使用數組時,大多數情況下數組都會自動轉換為指向第一個元素的指針:

例外情況有:

數組用作取位址(&)操作符的操作數或sizeof操作符的操作數時,或用數組對數組的引用進行初始化時。

ps:指向任意資料類型的指針都可以轉換為void*類型;整型數值常量0可轉換為任意指針類型。

4、轉換為bool類型:

算數值和指針值都可以轉換為bool類型。對應false和true。

bool型也可以轉換為int型,對應為0和1。

5、轉換與枚舉類型:

c++自動将枚舉類型的對象或枚舉成員轉換為整型,該轉換結果可用于任何要求使用整數值的地方。而将enum對象或枚舉成員提升為什麼類型由機器定義,并且依賴于枚舉成員的最大值。

6、轉換為const對象:

當使用非const對象初始化const對象的引用時,系統将非const對象轉換為const對象。此外,還可以将非const對象的位址(或非const指針)轉換為指向相關const類型的指針:

二、顯式轉換

即強制類型轉換。

命名的強制類型轉換符号的一般形式如下:

其中cast-name為static_cast、dynamic_cast、const_cast和reinterpret_cast之一,type為轉換的目标類型,而expression則是被強制轉換的值。

1、dynamic_cast

dynamic_cast支援運作時識别指針或引用所指向的對象。與其一起使用的指針必須是有效的。

與其它三者不同的是,它涉及運作時類型檢查。如果轉換到指針類型的dynamic_cast失敗,則dynamic_cast的結果是0值;若轉換到引用類型的dynamic_cast失敗,則抛出一個bad_cast類型的異常。

是以,該操作符一次執行兩個操作。它首先驗證被請求的轉換是否有效,隻有轉換有效,操作符才實際進行轉換。

2、const_cast

該操作符可以轉換掉表達式的const性質:

隻有使用const_cast才能将const性質轉換掉,而且,除了添加與删除const特性,用const_cast符來執行其它任何類型轉換,都會引起編譯錯誤。

3、static_cast

編譯器隐式執行的任何類型轉換都可以用static_cast顯示完成:

當需要将一個較大的算術類型指派給較小的類型時,使用強制轉換非常有用。

4、reinterpret_cast

reinterpret_cast通常為操作數的位模式提供較低層次的重新解釋。該操作符本質上依賴于機器,是以其安全性應重點考慮。

程式員應該記得pc所指向的真實對象其實是int型,而并非字元數組。任何假設pc是普通字元指針的應用,都有可能帶來未知的運作時錯誤。

ps:應盡量避免使用強制類型轉換,不依賴強制類型轉換往往也能寫出很好的c++程式。

三、實參類型轉換(函數重載)

類型提升或轉換适用于實參類型可通過某種标準轉換提升或轉換為适當的形參類型的情況。

必須注意的一個重點是較小的整型提升為int型。假設有兩個函數,一個的形參為int型,另一個的形參則是short型。對于任意整型的實參值,int版本都是由于short版本的較佳比對,即使從形式上看short型版本的比對更佳:

四、轉換與類類型

我們可以用一個實參調用的非explicit構造函數定義一個隐式轉換,當提供了實參類型的對象而需要一個類類型的對象時,編譯器将使用該轉換。

除了定義類類型的轉換外,我們還可以定義從類類型的轉換。即,定義轉換操作符,給定類類型的對象,該操作符将産生其他類型的對象,而且編譯器也将自動應用這個轉換。其用途如下:

1、支援混合類型表達式;

2、轉換減少所需操作符的數目。

轉換操作符有:

轉換操作符是一種特殊的類成員函數,它定義将類類型值轉變為其他類型值的轉換。轉換操作符在類定義體内聲明,在保留字operator之後跟着轉換的目标類型:

type表示内置類型名、類類型名由類型别名所定義的名字。對任何可作為函數傳回類型的類型(除void外)都可以定義轉換函數。一般而言,不允許轉換為數組或函數類型,轉換為指針類型(資料和函數指針)以及引用類型是可以的。

雖然轉換函數不能指定傳回類型,但是每個轉換函數必須顯式傳回一個指定類型的值。

ps:轉換函數必須是成員函數,不能指定傳回類型,并且形參表必須為空。轉換函數一般不應該改變被轉換的對象。是以,轉換操作符通常應定義為const成員。

1、使用類類型轉換

隻要存在轉換,編譯器将在可以使用内置轉換的地方自動調用它:表達式中、條件中、實參傳值、重載、顯示類型中等。

2、類類型轉換和标準轉換

使用轉換函數時,被轉換的類型不必與所需要的類型完全比對。必要時可以在類類型轉換之後跟上标準轉換以獲得想要的類型。

3、隻能應用一個類類型轉換

類類型轉換之後不能再跟另一個列類型轉換。如果需要多個類類型轉換,則代碼将出錯。

4、标準轉換可放在類類型轉換之前

使用構造函數執行隐式轉換時,構造函數的形參類型不必與所提供的類型完全比對。如果需要,在調用構造函數執行類類型轉換之前,可将一個标準轉換序列應用于實參。

五、轉換與繼承

主要是基類類型和派生類型之間的轉換。

1、派生類到基類的轉換

如果有一個派生類型的對象,則可以使用它的位址對基類類型的指針進行指派或初始化。同樣,可以使用派生類型的引用或對象初始化基類類型的引用。

(1).引用轉換不同于轉換對象

我們可以将派生類型的對象傳給希望接受基類引用的函數,這時,引用直接綁定到該對象,實參隻是該對象的引用,對象本身未被複制。

(2).用派生類對象對基類對象進行初始化或指派

對基類對象進行初始化或指派實際上實在調用函數:初始化時調用構造函數,指派時調用指派操作符。正因為存在從派生類引用到基類引用的轉換,才使指派控制成員可用于從派生類對象對基類對象進行初始化或指派成為可能。

(3).派生類到基類轉換的可通路性

像繼承的成員函數一樣,從派生類到基類的轉換可能是也可能不是可通路的,這取決于在派生類的派生清單中指定的通路标号。

ps:要确定到基類的轉換是否可通路,可以考慮基類的public成員是否可通路,如果可以,則轉換是可通路的,否則,轉換是不可通路的。

2、基類到派生類的轉換

從基類到派生類的自動轉換是不存在的,需要派生類對象時不能使用基類對象,因為基類對象隻能是基類對象對象,不能包含派生類型的成員。

當基類指針或引用實際綁定到派生類對象時,從基類到派生類的轉換也是存在限制的,編譯器确定轉換是否合法,隻看指針或引用的靜态類型。在此情況下,如果知道從基類到派生類的轉換是安全的,就可以使用static_cast強制編譯器進行轉換,或者可以用dynamic_cast申請在運作時進行檢查。

繼續閱讀