2 回答

TA貢獻1794條經(jīng)驗 獲得超8個贊
C++標(biāo)準(zhǔn)轉(zhuǎn)換運算符const_cast
C++相比于C是一門面向?qū)ο蟮恼Z言,面向?qū)ο笞畲蟮奶攸c之一就是具有“多態(tài)性(Polymorphism)”。
C++提供了四個轉(zhuǎn)換運算符:
const_cast <new_type> (expression)
static_cast <new_type> (expression)
reinterpret_cast <new_type> (expression)
dynamic_cast <new_type> (expression)
它們有著相同的結(jié)構(gòu),看起來像是模板方法。這些方法就是提供給開發(fā)者用來進行指針和引用的轉(zhuǎn)換的。
標(biāo)準(zhǔn)運算符的作用就是對傳統(tǒng)運算符的代替,以便做到統(tǒng)一。就像用std::endl來輸出換行,而不是'\n'。用代碼來說明相應(yīng)的傳統(tǒng)轉(zhuǎn)換可以如何這些標(biāo)準(zhǔn)運算符。在標(biāo)準(zhǔn)運算符上,編譯器肯定有做更多的處理,特別是dynamic_cast是不能用傳統(tǒng)轉(zhuǎn)換方式來完全實現(xiàn)的。
const_cast (expression)
const_cast轉(zhuǎn)換符是用來移除變量的const或volatile限定符。它涉及到了多線程的設(shè)計,
用const_cast來去除const限定
對于const變量,不能修改它的值,這是這個限定符最直接的表現(xiàn)。
下邊的代碼顯然是達不到目的的: const int constant = 10;
int modifier = constant;
因為對modifier的修改并不會影響到constant,這暗示了一點:const_cast轉(zhuǎn)換符也不該用在對象數(shù)據(jù)上,因為這樣的轉(zhuǎn)換得到的兩個變量/對象并沒有相關(guān)性。
只有用指針或者引用,讓變量指向同一個地址才是解決方案,可惜下邊的代碼在C++中也是編譯不過的: const int constant = 21;
int* modifier = &constant
// Error: invalid conversion from 'const int*' to 'int*'
(上邊的代碼在C中是可以編譯的,最多會得到一個warning,所在在C中上一步就可以開始對constant里面的數(shù)據(jù)胡作非為了)
把constant交給非const的引用也是不行的。 const int constant = 21;
int& modifier = constant;
// Error: invalid initialization of reference of type 'int&' from expression of type 'const int'
于是const_cast就出來消滅const,以求引起程序世界的混亂。
下邊的代碼就順利編譯功過了: const int constant = 21;
const int* const_p = &constant;
int* modifier = const_cast<int*>(const_p);
*modifier = 7;
傳統(tǒng)轉(zhuǎn)換方式實現(xiàn)const_cast運算符
準(zhǔn)轉(zhuǎn)換運算符是可以用傳統(tǒng)轉(zhuǎn)換方式實現(xiàn)的。const_cast實現(xiàn)原因就在于C++對于指針的轉(zhuǎn)換是任意的,它不會檢查類型,任何指針之間都可以進行互相轉(zhuǎn)換,因此const_cast就可以直接使用顯示轉(zhuǎn)換(int*)來代替: const int constant = 21;
const int* const_p = &constant;
int* modifier = (int*)(const_p);
或者可以把他們合成一個語句,跳過中間變量,用 const int constant = 21;
int* modifier = (int*)(&constant);
替代 const int constant = 21;
int* modifier = const_cast<int*>(&constant);
為何要去除const限定
從前面代碼中已經(jīng)看到,不能對constant進行修改,但是可以對modifier進行重新賦值。
如果我們把結(jié)果打印出來: cout << "constant: "<< constant <<endl;
cout << "const_p: "<< *const_p <<endl;
cout << "modifier: "<< *modifier <<endl;
/**
constant: 21
const_p: 7
modifier: 7
**/
constant還是保留了它原來的值。
可是它們的確指向了同一個地址:
cout << "constant: "<< &constant <<endl;
cout << "const_p: "<< const_p <<endl;
cout << "modifier: "<< modifier <<endl;
/**
constant: 0x7fff5fbff72c
const_p: 0x7fff5fbff72c
modifier: 0x7fff5fbff72c
**/
說明C++里是const,就是const,const也沒有存在的意義了。
IBM的C++指南稱呼“*modifier = 7;”為“未定義行為(Undefined Behavior)”。所謂未定義,是說這個語句在標(biāo)準(zhǔn)C++中沒有明確的規(guī)定,由編譯器來決定如何處理。
位運算的左移操作也可算一種未定義行為,因為不確定是邏輯左移,還是算數(shù)左移。
再比如下邊的語句:v[i] = i++; 也是一種未定義行為,因為不知道是先做自增,還是先用來找數(shù)組中的位置。
對于未定義行為,能做的所要做的就是避免出現(xiàn)這樣的語句。對于const數(shù)據(jù)更要這樣保證:絕對不對const數(shù)據(jù)進行重新賦值。
調(diào)用了一個參數(shù)不是const的函數(shù),而要傳進去的實際參數(shù)確實const的,但是知道這個函數(shù)是不會對參數(shù)做修改的。于是就需要使用const_cast去除const限定,以便函數(shù)能夠接受這個實際參數(shù)。
#include <iostream>
using namespace std;
void Printer (int* val,string seperator = "\n")
{
cout << val<< seperator;
}
int main(void)
{
const int consatant = 20;
//Printer(consatant);//Error: invalid conversion from 'int' to 'int*'
Printer(const_cast<int *>(&consatant));
return 0;
}
出現(xiàn)這種情況的原因,可能是所調(diào)用的方法是別人寫的。出現(xiàn)在const對象想調(diào)用自身的非const方法的時候,因為在類定義中,const也可以作為函數(shù)重載的一個標(biāo)示符。有機會,會專門回顧一下我所知道const的用法,C++的const真的有太多可以說的了。
在IBM的C++指南中還提到了另一種可能需要去const的情況:
#include <iostream>
using namespace std;
int main(void) {
int variable = 21;
int* const_p = &variable;
int* modifier = const_cast<int*>(const_p);
*modifier = 7
cout << "variable:" << variable << endl;
return 0;
}
/**
variable:7
**/
定義了一個非const的變量,但用帶const限定的指針去指向它,
Director: Jim Fawcett
C++ Language Tutorial - Type Casting
Object Oriented Design
IBM Complilers - XL C/C++ V9.0 for Linux - The const_cast operator (C++ only)
stackoverflow: Is const_cast safe?

TA貢獻1863條經(jīng)驗 獲得超2個贊
顯式強制類型轉(zhuǎn)換(cast)包括以下操作符:
static_cast, dynamic_cast, const_cast, reinterpret_cast,對各種顯式類型轉(zhuǎn)換解釋:
static_cast:編譯器隱式執(zhí)行的轉(zhuǎn)換都可以有static_cast顯式執(zhí)行。
例子:
double num = 12.32;
int data = num;
這個例子完成了顯式類型轉(zhuǎn)換,當(dāng)然我們完全可以顯式告訴編譯器我要轉(zhuǎn)換類型不且不關(guān)心轉(zhuǎn)換后精度損失,就可以寫成是:int data = static_cast<int>(num);
dynamic_cast:支持運行時識別指針或引用所指向的對象,如果綁定到引用或指針的對象不是目標(biāo)類型的對象,則dynamic_cast失敗,如果轉(zhuǎn)換到指針類型的dynamic_cast失敗,則dynamic_cast的結(jié)果為0值;如果轉(zhuǎn)換到引用類型的dynamic_cast失敗,則拋出一個bad_cast類型的異常。
因此,dynamic_cast操作符一次執(zhí)行兩個操作。首先驗證被請求的轉(zhuǎn)換是否有效,只有轉(zhuǎn)換有效,操作符才實際進行轉(zhuǎn)換?;惖闹羔樋梢再x值為指向派生類的對象,同樣,基類的引用也可以用派生類對象初始化,因此,dynamic_cast操作符執(zhí)行的驗證必須在運行時進行。
const_cast:將轉(zhuǎn)換掉表達式的const性質(zhì).
例子:
const char * source = "zhangsan";
char * dest = source;
編譯出現(xiàn)錯誤提示:error C2440: 'initializing' : cannot convert from 'const char *' to 'char *'
這時我們可以運用const_cast去掉source的const性質(zhì)。改為
char * dest = const_cast<char *>(source);就通過了編譯。
reinterpret_cast:顧名思義reinterpret:重新解釋。就是將操作數(shù)內(nèi)容解釋為另一種不同的類型。這種強制轉(zhuǎn)換本質(zhì)上依賴于機器,而且非常危險。
例子:
int * source ;
char *dest = reinterpret_cast<char *>(source);
如上,本來source本來指向的對象時int類型,但是想把這塊內(nèi)存重新解釋為char類型,就用reinterpret_cast,但是這很危險,編程人員必須記住dest指向的真實對象其實是int類型。
你的例子問題在于,既然你用const定義常量,就不能改變a的值,但是你賦值了,所以錯誤。const_cast只是去掉const屬性,并沒說你可以改變其內(nèi)容,只是可以講const定義的常量賦值給其他的變量而已。
添加回答
舉報