天天看點

淺談C++新式轉型操作符

淺談C++新式轉型操作符

淺談新式轉型操作符:

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;

淺談C++新式轉型操作符

對了,至于引用不能作為if判斷條件,很簡單,引用不能為空,引用一旦聲明就必須初始化。但考慮如下:

const int&a=2;

   const int&b=NULL;

   if (b==NULL)

   {

      std::cout<<"b is null"<<std::endl;

 }
           

這确是可以的,當一個指向常量的引用采用一個字面值來初始化,該引用實際上被設定指向“采用該字面值初始化”的一個臨時位置。因為a,b并非真的指向字面值,而是指向一個采用字面值初始化、類型為int的的臨時量。

繼續閱讀