C++中的類型轉換static_cast、dynamic_cast、const_cast和reinterpret_cast總結。本站提示廣大學習愛好者:(C++中的類型轉換static_cast、dynamic_cast、const_cast和reinterpret_cast總結)文章只能為提供參考,不一定能成為您想要的結果。以下是C++中的類型轉換static_cast、dynamic_cast、const_cast和reinterpret_cast總結正文
媒介
這篇文章總結的是C++中的類型轉換,這些小的常識點,有的時刻,本身不是很留意,然則在現實開辟中確切常常應用的。俗語說的好,不懂本身寫的代碼的法式員,不是好的法式員;假如一個法式員關於本身寫的代碼都不懂,只是曉得一昧的的去應用,終有一天,你會迷掉你本身的。
C++中的類型轉換分為兩種:
1.隱式類型轉換;
2.顯式類型轉換。
而關於隱式變換,就是尺度的轉換,在許多時刻,不經意間就產生了,好比int類型和float類型相加時,int類型就會被隱式的轉換位float類型,然後再停止相加運算。而關於隱式轉換不是明天總結的重點,重點是顯式轉換。在尺度C++中有四個類型轉換符:static_cast、dynamic_cast、const_cast和reinterpret_cast;上面將對它們逐個的停止總結。
static_cast
static_cast的轉換格局:static_cast <type-id> (expression)
將expression轉換為type-id類型,重要用於非多態類型之間的轉換,不供給運轉時的檢討來確保轉換的平安性。重要在以下幾種場所中應用:
1.用於類條理構造中,基類和子類之間指針和援用的轉換;
當停止下行轉換,也就是把子類的指針或援用轉換成父類表現,這類轉換是平安的;
當停止下行轉換,也就是把父類的指針或援用轉換成子類表現,這類轉換是不平安的,也須要法式員來包管;
2.用於根本數據類型之間的轉換,如把int轉換成char,把int轉換成enum等等,這類轉換的平安性須要法式員來包管;
3.把void指針轉換成目的類型的指針,是及其不平安的;
注:static_cast不克不及轉換失落expression的const、volatile和__unaligned屬性。
dynamic_cast
dynamic_cast的轉換格局:dynamic_cast <type-id> (expression)
將expression轉換為type-id類型,type-id必需是類的指針、類的援用或許是void *;假如type-id是指針類型,那末expression也必需是一個指針;假如type-id是一個援用,那末expression也必需是一個援用。
dynamic_cast重要用於類條理間的下行轉換和下行轉換,還可以用於類之間的穿插轉換。在類條理間停止下行轉換時,dynamic_cast和static_cast的後果是一樣的;在停止下行轉換時,dynamic_cast具有類型檢討的功效,比static_cast更平安。在多態類型之間的轉換重要應用dynamic_cast,由於類型供給了運轉時信息。上面我將分離在以下的幾種場所下停止dynamic_cast的應用總結:
1.最簡略的下行轉換
好比B繼續自A,B轉換為A,停止下行轉換時,是平安的,以下:
#include <iostream>
using namespace std;
class A
{
// ......
};
class B : public A
{
// ......
};
int main()
{
B *pB = new B;
A *pA = dynamic_cast<A *>(pB); // Safe and will succeed
}
2.多重繼續之間的下行轉換
C繼續自B,B繼續自A,這類多重繼續的關系;然則,關系很明白,應用dynamic_cast停止轉換時,也是很簡略的:
class A
{
// ......
};
class B : public A
{
// ......
};
class C : public B
{
// ......
};
int main()
{
C *pC = new C;
B *pB = dynamic_cast<B *>(pC); // OK
A *pA = dynamic_cast<A *>(pC); // OK
}
而上述的轉換,static_cast和dynamic_cast具有異樣的後果。而這類下行轉換,也被稱為隱式轉換;好比我們在界說變量時常常這麼寫:B *pB = new C;這和下面是一個事理的,只是多加了一個dynamic_cast轉換符罷了。
3.轉換成void *
可以將類轉換成void *,例如:
class A
{
public:
virtual void f(){}
// ......
};
class B
{
public:
virtual void f(){}
// ......
};
int main()
{
A *pA = new A;
B *pB = new B;
void *pV = dynamic_cast<void *>(pA); // pV points to an object of A
pV = dynamic_cast<void *>(pB); // pV points to an object of B
}
然則,在類A和類B中必需包括虛函數,為何呢?由於類中存在虛函數,就解釋它有想讓基類指針或援用指向派生類對象的情形,此時轉換才成心義;因為運轉時類型檢討須要運轉時類型信息,而這個信息存儲在類的虛函數表中,只要界說了虛函數的類才有虛函數表。
4.假如expression是type-id的基類,應用dynamic_cast停止轉換時,在運轉時就會檢討expression能否真實的指向一個type-id類型的對象,假如是,則能停止准確的轉換,取得對應的值;不然前往NULL,假如是援用,則在運轉時就會拋出異常;例如:
class B
{
virtual void f(){};
};
class D : public B
{
virtual void f(){};
};
void main()
{
B* pb = new D; // unclear but ok
B* pb2 = new B;
D* pd = dynamic_cast<D*>(pb); // ok: pb actually points to a D
D* pd2 = dynamic_cast<D*>(pb2); // pb2 points to a B not a D, now pd2 is NULL
}
這個就是下行轉換,從基類指針轉換到派生類指針。
關於一些龐雜的繼續關系來講,應用dynamic_cast停止轉換是存在一些圈套的;好比,有以下的一個構造:
D類型可以平安的轉換成B和C類型,然則D類型如果直接轉換成A類型呢?
class A
{
virtual void Func() = 0;
};
class B : public A
{
void Func(){};
};
class C : public A
{
void Func(){};
};
class D : public B, public C
{
void Func(){}
};
int main()
{
D *pD = new D;
A *pA = dynamic_cast<A *>(pD); // You will get a pA which is NULL
}
假如停止下面的直接轉,你將會獲得一個NULL的pA指針;這是由於,B和C都繼續了A,而且都完成了虛函數Func,招致在停止轉換時,沒法停止決定應當向哪一個A停止轉換。准確的做法是:
int main()
{
D *pD = new D;
B *pB = dynamic_cast<B *>(pD);
A *pA = dynamic_cast<A *>(pB);
}
這就是我在完成QueryInterface時,獲得IUnknown的指針時,應用的是*ppv = static_cast<IX *>(this);而不是*ppv = static_cast<IUnknown *>(this);
關於多重繼續的情形,從派生類往父類的父類停止轉時,須要特殊留意;好比有上面這類情形:
如今,你具有一個A類型的指針,它指向E實例,若何取得B類型的指針,指向E實例呢?假如直接停止轉的話,就會湧現編譯器湧現不合,不曉得是走E->C->B,照樣走E->D->B。關於這類情形,我們就必需先將A類型的指針停止下行轉換,取得E類型的指針,然後,在指定一條准確的道路停止下行轉換。
下面就是關於dynamic_cast轉換的一些細節常識點,特殊是關於多重繼續的情形,在現實項目中,很輕易湧現成績。
const_cast
const_cast的轉換格局:const_cast <type-id> (expression)
const_cast用來將類型的const、volatile和__unaligned屬性移除。常量指針被轉換成異常量指針,而且依然指向本來的對象;常量援用被轉換成異常量援用,而且依然援用本來的對象。看以下的代碼例子:
/*
** FileName : ConstCastDemo
** Author : Jelly Young
** Date : 2013/12/27
** Description : More information, please go to http://www.jb51.net
*/
#include <iostream>
using namespace std;
class CA
{
public:
CA():m_iA(10){}
int m_iA;
};
int main()
{
const CA *pA = new CA;
// pA->m_iA = 100; // Error
CA *pB = const_cast<CA *>(pA);
pB->m_iA = 100;
// Now the pA and the pB points to the same object
cout<<pA->m_iA<<endl;
cout<<pB->m_iA<<endl;
const CA &a = *pA;
// a.m_iA = 200; // Error
CA &b = const_cast<CA &>(a);
pB->m_iA = 200;
// Now the a and the b reference to the same object
cout<<b.m_iA<<endl;
cout<<a.m_iA<<endl;
}
注:你不克不及直接對非指針和非援用的變量應用const_cast操作符去直接移除它的const、volatile和__unaligned屬性。
reinterpret_cast
reinterpret_cast的轉換格局:reinterpret_cast <type-id> (expression)
許可將任何指針類型轉換為其它的指針類型;聽起來很壯大,然則也很不靠譜。它重要用於將一種數據類型從一品種型轉換為另外一品種型。它可以將一個指針轉換成一個整數,也能夠將一個整數轉換成一個指針,在現實開辟中,先把一個指針轉換成一個整數,在把該整數轉換成原類型的指針,還可以獲得本來的指針值;特殊是開拓了體系全局的內存空間,須要在多個運用法式之間應用時,須要彼此同享,傳遞這個內存空間的指針時,便可以將指針轉換成整數值,獲得今後,再將整數值轉換成指針,停止對應的操作。
總結
這篇博文總結了C++中的類型轉換,重點總結了個中的顯式轉換。關於C++支撐的這四種顯式轉換都停止了具體的描寫。假如年夜家有甚麼彌補的,或許我總結的有誤的處所,請年夜家多多指教。