static_cast一般用來將枚舉類型轉換成整型,或者整型轉換成浮點型。也可以用來將指向父類的指針轉換成指向子類的指針。做這些轉換前,你必須確定要轉換的數據確實是目標類型的數據,因為static_cast不做運行時的類型檢查以保證轉換的安全性。也因此,static_cast不如dynamic_cast安全。對含有二義性的指針,dynamic_cast會轉換失敗,而static_cast卻直接且粗暴地進行轉換。這是非常危險的。
比如:
class B {};
class D : public B {};
void f(B* pb, D* pd) {
D* pd2 = static_cast<D*>(pb); // Not safe, D can have fields
// and methods that are not in B.
B* pb2 = static_cast<B*>(pd); // Safe conversion, D always
// contains all of B.
}
上面的第一個類型轉換是不安全的。比如,一旦使用pd2調用了一個子類D有而父類B沒有的方法,則程序就會因越界訪問而崩潰。
static_cast和dynamic_cast都可以用於類層次結構中基類和子類之間指針或引用的轉換。所不同的是,static_cast僅僅是依靠類型轉換語句中提供的信息(尖括號中的類型)來進行轉換;而dynamic_cast則會遍歷整個類的繼承體系進行類型檢查。比如:
class B {
public:
virtual void Test(){}
};
class D : public B {};
void f(B* pb) {
D* pd1 = dynamic_cast<D*>(pb);
D* pd2 = static_cast<D*>(pb);
}
如果pb確實是指向一個D類型的對象,那pd1和pd2的值是相同的,即使pb為NULL。
如果pb實際指向的是一個B類型的對象,那dynamic_cast就會轉換失敗,並返回NULL(此時pd1為NULL);而static_cast卻依據程序員指定的類型簡單地返回一個指針指向假定的D類型的對象(此時pd2不為NULL),這當然是錯誤的。
static_cast還可以在兩個類對象之間進行轉換,比如把類型為A的對象a,轉換為類型為B的對象。如下:
class A; class B; A a; B b; b = static_cast<B>(a);
此過程可以看做是以a為參數構造一個B類型的臨時對象,然后再把這個臨時對象賦值給b。如下:
class A; class B; A a; B b; B c(a); b = c;
所以,如果讓以上代碼通過編譯,那么B類必須含有以A類的對象(或對象的引用)為參數的構造函數。如下:
B(A& a)
{
// ...
}
這實際上是把轉換的工作交給構造函數去做了。
static_cast最常用的是基本類型直接的轉換,比如char與int、int與float、enum與int之間的轉換。在把int轉換為char時,如果char沒有足夠的比特位來存放int的值(int>127或int<-127時),那么static_cast所做的只是簡單的截斷,及簡單地把int的低8位復制到char的8位中,並直接拋棄高位。在把int轉換為enum時,如果int的值沒有落進enum的范圍內,則enum的值將是“未定義”的。比如,定義一個枚舉類型Week,它包含周一到周日七天:
enum Week
{
Monday = 1,
Tuesday,
Wednesday,
Thursday,
Friday,
Saturday,
Sunday
};
此時如果把值為8的int轉換為week類型,那么這個Week變量不會是周一到周日的任何一天。
Week noday = static_cast<Week>(8);
如果你用“%d”格式把它打印出來,你會發現,它的值確實是8。但這已經超出周一到周日了。世界上沒有“星期八”,不是嗎?
static_cast甚至可以把任何一個表達式轉換為void類型。
再次提醒,static_cast完全靠程序員自己去保證轉換的正確性。
static_cast轉換的目標類型可以帶const、volatile或__unaligned屬性。但static_cast不能把源類型的這些熟悉移除。如果想強制移除一個變量的const、volatile或__unaligned屬性,請參考const_cast操作符。
小結一下:
static_cast常用來進行基本類型直接的轉換,如char與int、int與float、enum與int之間;
static_cast也可以轉換用戶自定義類型,但目標類型必須含有相應的構造函數;
static_cast還可以轉換對象的指針類型,但它不進行運行時類型檢查,所以是不安全的;
static_cast甚至可以把任何表達式都轉換成void類型;
satic_cast不能移除變量的const屬性,請參考const_cast操作符;
static_cast進行的是簡單粗暴的轉換,所以其正確性完全由程序員自己保證。
