类型转换操作符:static_cast, dynamic_cast, const_cast, reinterpret_cast.
呵呵,今天來好好看看著幾個轉換操作符的用法。以前老是看著眼熟,但是用著手生。今天決定搞定這些個東西。
在C語言中類型轉換有幾種方式:
1.????? (expression). 在表達式外邊加括號,由編譯器來決定怎么改變。
2.????? new_type(expression). 強制類型括號住表達式。
3.????? (new_type)expression. 括號住強制類型。
4.????? C語言允許的內置轉換。
這些轉換非常高效,我非常喜歡使用。特別是在指針轉換和數值轉換時用到的非常多。只要編寫程序的人知道自己要做什么轉換,并知道應該怎樣轉換的話,我認為上邊的轉換方式非常之好。但是沒有清楚的了解每個轉換的細節的話,就有可能出現問題,比如指針指向不應該指向的區域:出現野指針或者指向位置錯誤(主要是對內存結構不了解),或者計算數值被截去等問題發生。
C++程序兼容C語言的轉化,但是針對面向對象語言的特性,設計了以下幾個類型轉換操作符。他們的出現是為了C語言類型轉換中語義模糊和固有的危險陷阱,因為C語言不去判斷所要操作的類型轉換是否合理。
static_cast:用于非多態類型的轉換。
dynamic_cast:用于多態類型的轉換。
const_cast:用來消除const, volatile, __unaligned屬性的轉換。
reinterpret_cast:用于空間的重新解釋。
還有一個在VS2005中出現的類型轉換關鍵字safe_cast.#2
?
static_cast:
static_cast<type_id>(expression)
這個關鍵字可以用來將一個指針轉換為父類的指針也可以轉換為子類的指針或者基本的類型轉換。但是這種轉換是強制的,并沒有任何運行時類型檢查來保證轉換的正確性,所以編寫代碼的人需要明白自己所進行的轉換是否合理。
//基本類型的轉換
enum e { A = 1, B, C };
double d = 12.25;
unsigned int ui = 25;
char c = static_cast<char>(ui);
int i = static_cast<int>(d);
int j = static_cast<int>(B);
//父類子類轉換
class F????????????????? //father
{
public:
??? int _father;
};
class S : public F ????? //son
{
public:
??? _son;
};
F *pFather = new F();
S *pSon = new S();
F *pF;
S *pS;
pF = static_cast<F *>(pSon);??? //將子類指針轉換為父類指針,OK
pS = static_cast<S *>(pFather); //將父類指針轉換為子類指針,錯誤
第二個錯誤的轉換不是說編譯器編譯不過去,而是運行時會出現錯誤。
原因如下:假設pF指向了pSon的位置,它可以訪問_father,它找不到_son,這樣沒有問題。但是pS指向了pFather的位置,它訪問_father沒有問題,但是訪問_son時就會產生錯誤,因為pFather根本沒有_son這個變量。
下面是將父類轉換為子類指針時,static_cast和dymanic_cast兩者不同的表現:
class F
{
public:
??? virtual void speak(){};
??? int i;
};
?
class S : public F
{
public:
??? void speak()
??? {
?????? cout << "S = " << _s << endl;
??? }
??? double _s;
};
F *pF = new F();
S *pS = static_cast<S*>(pF);
pS->speak();
S1 *pDS = dynamic_cast<S*>(pF);
pDS->speak();
靜態的轉換編譯不顯示警告,運行結果不輸出(調用F的speak函數)。動態的轉換編譯顯示可能出現不可預期的結果,運行時崩潰。(VS2005時,返回空指針,但是不會崩潰。我認為要是按照C++的特性還是崩潰比較好一點,讓程序員容易理解這么做是錯誤的。)
?
dynamic_cast:
dynamic_cast<type_id>(expression)
本關鍵字主要處理多態的類型轉換,type_id要么是指針類型,要么是引用類型要么是void*。當type_id為指針和void*時,expression必須是type_id類型的指針,當type_id為引用時,expression也必須是type_id類型的引用。#1
?
1.最常用的用法就是將子類指針轉換為父類指針。(不舉例)
2.當type_id為void*時,指針指向整個對象的空間。
Class A;
A *pA = new A();
void *p = dynamic_cast<void*>(pA);
但是type_id不為void*時,計算機就要在運行時檢查是否能夠轉換。
3.跳級轉換。
class A{};
class B : public A{};
class C : public B{};
??? A *pA;
??? B *pB;
??? C *pC = new C();
??? pB = dynamic_cast<B*>(pD);? //逐級轉換OK
??? pA = dynamic_cast<A*>(pB);? //逐級轉換OK
??? 或者
??? pA = dynamic_cast<A*>(pC);? //跳級轉換OK
??? delete pD;
以下情況跳級轉換不可以:
class A{};
class B : public A{};
class C : public A{};
class D : public B, public C{};
??? A *pA;
??? D *pD = new D();
??? pA = dynamic_cast<A*>(pB);? //出現錯誤,是不行的,原因大家都清楚。
?
class A{};
class B : public A{};
class C : public A{};
class D : public B{};
class E : public C, public D{};
??? A *pA;
??? B *pB;
??? E *pE = new E();
??? pB = dynamic_cast<B*>(pE);
??? pA = dynamic_cast<A*>(pB);? //可以
??? pA = dynamic_cast<A*>(pE);? //不可以,原因是很簡單的。
??? delete pE;
4.兩個不相干的類之間轉換。
class A {};
class B {};
??? A* pa = new A;
??? B* pb = dynamic_cast<B*>(pa);?? // 不可以,沒有相互轉換的基礎
但是reinterpret_cast可以轉換,可以參考reinterpret_cast
?
?
const_cast:
const_cast<type_id>(expression)
這個關鍵字消除了幾個關鍵字的作用const, volatile,和__unaligned的作用。const經常使用。MSDN有const的例子照抄過來。
class CCTest {
public:
?? void setNumber( int );
?? void printNumber() const;
private:
?? int number;
};
void CCTest::setNumber( int num ) { number = num; }
void CCTest::printNumber() const {
?? cout << "/nBefore: " << number;
?? const_cast< CCTest * >( this )->number--;//這里消除了const的作用
?? cout << "/nAfter: " << number;
}
int main() {
?? CCTest X;
?? X.setNumber( 8 );
?? X.printNumber();
}
?
reinterpret_cast:
reinterpret_cast
這個關鍵字比較“強悍”,隨意轉換類型。但是轉換錯誤,就是你的不對了。呵呵,我的原則兩個字:“慎用”。
這個關鍵字可以在任何類型的指針之間轉換。
不可以替代const_cast。
不提供安全轉換。
MSDN的例子顯示出來它的強悍,也顯示出了他的脆弱。只要你一個不小心就會亂用。
#include <iostream>
?
// Returns a hash code based on an address
unsigned short Hash( void *p ) {
?? unsigned int val = reinterpret_cast<unsigned int>( p );
?? return ( unsigned short )( val ^ (val >> 16));
}
?
using namespace std;
int main() {
?? int a[20];
?? for ( int i = 0; i < 20; i++ )
????? cout << Hash( a + i ) << endl;
}
?
?
#1 dynamic_cast的type_id為引用的情況我不準備了解,好像是微軟VS2005的特性,而不是標準C++的特性。對于VS6.0我還是感覺比較欣賞的。雖然不如他的新版本那樣支持更多的C++特性,但是我自己的感覺是VS的產品在無限的向C#靠攏,無限的向java的易用性靠攏,這樣的話C++程序在抑制到別的操作系統時就需要做很大的修改。這也是微軟的霸道之處。題外話:微軟的vista是一款失敗的產品,在vista上微軟開發了virtual PC 2007的虛擬機,但是這款產品只支持windows系統的產品安裝,對于linux產品他就不支持(只能安裝,不能用),因為他不支持24位真彩色。這就說明它的心態是封閉的,而封閉最終導致它的衰敗。
#2 safe_cast也是微軟的東西,想了解的請參考VS2005的MSDN。總結
以上是生活随笔為你收集整理的类型转换操作符:static_cast, dynamic_cast, const_cast, reinterpret_cast.的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 将查询结果插入到现有表中
- 下一篇: 基于3G网络的汽车防盗报警系统视频监控设