![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIyZwpmLwADN48FOzETN4cjN1MTMvwVOy8CXyEjMxAjMvw1ckF2bsBXdvwFdl5mLuR2cj5Set1yZtl2Lc9CX6MHc0RHaiojIsJye.jpg)
淺談新式轉型操作符:
const_cast
#include "stdafx.h"
#include <IOSTREAM>
#include "Animal.h"
#include "Cat.h"
using namespace std;
int main(int argc, char* argv[])
{
const CCat mycat;
Animal* cat=&mycat;
cat->eat();
return 0;
}
上面代碼Animal是基類,并且有一個eat的虛方法,CCat派生于Animal并實作了eat方法。
在運作如上代碼時,毋庸置疑會發生錯誤。cannot convert from 'const class CCat *' to 'class Animal *'
是以利用舊式轉型操作,可以很簡單的避免這個錯誤,作如下類型轉換:
#include "stdafx.h"
#include <IOSTREAM>
#include "Animal.h"
#include "Cat.h"
using namespace std;
int main(int argc, char* argv[])
{
const CCat mycat;
Animal*cat=(Animal*)&mycat;
cat->eat();
return 0;
}
仔細考慮,上面代碼其實做了兩個轉型,一個是去除了mycat的const,另一個将*CCat轉換成了*Animal.
這看上去很正确,但考慮下面代碼:
我們新增一個Person類,人不是動物是以無須繼承Animal類。
int main(int argc, char* argv[])
{
const CCat mycat;
Person*p=(Person*)&mycat;
return 0;
}
但上面的代碼依然是編譯通過的。這不就是cat is a person.然後利用const_cast進行轉換時
int main(int argc, char* argv[])
{
const CCat mycat;
Person*p=const_cast<Person*>(&mycat);
return 0;
}
//或
int main(int argc, char* argv[])
{
const CCat mycat;
Person*p=const_cast<CCat*>(&mycat);
return 0;
}
編譯時
cannot convert from 'class CCat *' to 'class Person *'
看到這裡,讀者可能有點感覺了,對于舊式的轉換操作,他并不檢查類型不正确轉換,簡單的說就是告訴編譯器“喂,給我把const cat轉成person”,而const_cast轉換操作則相對威力更小,因為它隻影響類型修飾符,這樣的限制同樣是件好事,因為他更能精确的表達我們的意圖。在const cat到person時,他隻能把const去除,一旦到類型轉換時,他就無能為力,編譯發現類型不比對時則會報錯。
static_cast最常用的将一個繼承層次結構中的基類指針或引用,向下轉型成派生類的指針或引用。需要注意的是必須是繼承層次中。
是以對于
Animal* an=new CCat;
CCat*cat=(CCat*)&an;
實際上由這個兩步完成
Animal* cat2=const_cast< Animal*>(&mycat);
CCat * cat2=static_cast< CCat *>(&mycat);
Reinterpret_cast指它是從bit看待一個對象。進而允許将一個東西看作另一個完全不同的東西。他在低層編碼時偶爾非用不可,但不具備移植性。當使用reinterpret_cast和static_cast将指向基類的指針向下轉型為指向派生類的指針時的行為。Reinterpret_cast通常隻是将基類指針假裝成一個派生類指針而不改變其值,而static_cast和舊式轉型則将執行正确的位址操作。
Animal* an=new Animal;
CCat*cat=reinterpret_cast<CCat*>(an);
cat->eat();
//此處cat雖然聲明類型為CCat*,但終将是假裝(實質還是Animal*),最終列印的還是//Animal eat.
CCat*cat2=static_cast<CCat*>(an);
cat2->eat();
//因為static_cast進行記憶體轉換,cat2已經貨真價實的CCat*了。
Dynamic_cast僅用于對多态類型進行向下轉型,即被轉型的表達式類型,必須是帶有一個指向虛函數的類型的指針,并且進行運作期檢查工作,而static_cast則無須付出這種代價。對指針類型進行向下轉型時,轉型失敗會傳回null,而對于引用指針類型向下轉型時,轉型失敗則會引起異常。
Animal* an=new Cat;
if (Person* cat=dynamic_cast<Person*>(an))
{
std::cout<<"castsuccess"<<std::endl;
}else
{
std::cout<<"castfailed"<<std::endl;
}
當轉型成功時會傳回正确指針對象,轉型錯誤時則會傳回null作為if條件。但是在vc6.0中以下代碼雖然編譯能通過,但執行時确會報錯,而在vs2005中則正确輸出。
Cat an;
Animal& refan=an;
Person& cat=dynamic_cast<Person&>(refan);
return 0;
對了,至于引用不能作為if判斷條件,很簡單,引用不能為空,引用一旦聲明就必須初始化。但考慮如下:
const int&a=2;
const int&b=NULL;
if (b==NULL)
{
std::cout<<"b is null"<<std::endl;
}
這确是可以的,當一個指向常量的引用采用一個字面值來初始化,該引用實際上被設定指向“采用該字面值初始化”的一個臨時位置。因為a,b并非真的指向字面值,而是指向一個采用字面值初始化、類型為int的的臨時量。