程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> C++標准轉換運算符const_cast

C++標准轉換運算符const_cast

編輯:C++入門知識

 

前面講了C++繼承並擴展C語言的傳統類型轉換方式,最後留下了一些關於指針和引用上的轉換問題,沒有做詳細地講述。C++相比於C是一門面向對象的語言,面向對象最大的特點之一就是具有“多態性(Polymorphism)”。

 

要想很好的使用多態性,就免不了要使用指針和引用,也免不了會碰到轉換的問題,所以在這一篇,就把導師講的以及在網上反復查閱了解的知識總結一下。

 

C++提供了四個轉換運算符:

 

const_cast <new_type> (expression)

static_cast <new_type> (expression)

reinterpret_cast <new_type> (expression)

dynamic_cast <new_type> (expression)

它們有著相同的結構,看起來像是模板方法。這些方法就是提供給開發者用來進行指針和引用的轉換的。

 

其實我很早就想寫這篇內容的,自己不斷地查看導師發來的資料,也在網上不停地看相關的知識,卻一直遲遲不能完全理解C++轉換運算符的用法,倒是看了那些資料後先寫了一篇傳統轉換方面的內容。雖然從字面上很好理解它們大致是什麼作用,但是真正像使用起來,卻用不知道他們具體的用途,只會不斷的被編譯器提醒Error。所以如果出現理解不到位或錯誤的地方,還希望前人或來者能夠指正。

 

在我看來這些標准運算符的作用就是對傳統運算符的代替,以便做到統一。就像我們用std::endl來輸出換行,而不是'\n'。我會用代碼來說明相應的傳統轉換可以如何這些標准運算符。當然,這這是大致的理解,在標准運算符上,編譯器肯定有做更多的處理,特別是dynamic_cast是不能用傳統轉換方式來完全實現的。

 

在這一篇文章裡,我會先講講我對const_cast運算符的理解。

 

const_cast (expression)

const_cast轉換符是用來移除變量的const或volatile限定符。對於後者,我不是太清楚,因為它涉及到了多線程的設計,而我在這方面沒有什麼了解。所以我只來說const方面的內容。

 

 

用const_cast來去除const限定

 

對於const變量,我們不能修改它的值,這是這個限定符最直接的表現。但是我們就是想違背它的限定希望修改其內容怎麼辦呢?

 

下邊的代碼顯然是達不到目的的:

const int constant = 10;

int modifier = constant;

 

因為對modifier的修改並不會影響到constant,這暗示了一點:const_cast轉換符也不該用在對象數據上,因為這樣的轉換得到的兩個變量/對象並沒有相關性。

 

只有用指針或者引用,讓變量指向同一個地址才是解決方案,可惜下邊的代碼在C++中也是編譯不過的:

const int constant = 21;

int* modifier = &constant

// Error: invalid conversion from 'const int*' to 'int*'

 

(上邊的代碼在C中是可以編譯的,最多會得到一個warning,所在在C中上一步就可以開始對constant裡面的數據胡作非為了)

 

把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;

 

 

傳統轉換方式實現const_cast運算符

 

我說過標:准轉換運算符是可以用傳統轉換方式實現的。const_cast實現原因就在於C++對於指針的轉換是任意的,它不會檢查類型,任何指針之間都可以進行互相轉換,因此const_cast就可以直接使用顯示轉換(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限定

 

從前面代碼中已經看到,我們不能對constant進行修改,但是我們可以對modifier進行重新賦值。

 

但是但是,程序世界真的混亂了嗎?我們真的通過modifier修改了constatn的值了嗎?修改const變量的數據真的是C++去const的目的嗎?

 

如果我們把結果打印出來:

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)”。所謂未定義,是說這個語句在標准C++中沒有明確的規定,由編譯器來決定如何處理。

 

位運算的左移操作也可算一種未定義行為,因為我們不確定是邏輯左移,還是算數左移。

 

再比如下邊的語句:v[i] = i++; 也是一種未定義行為,因為我們不知道是先做自增,還是先用來找數組中的位置。

 

 

對於未定義行為,我們所能做的所要做的就是避免出現這樣的語句。對於const數據我們更要這樣保證:絕對不對const數據進行重新賦值。

 

如果我們不想修改const變量的值,那我們又為什麼要去const呢?

 

原因是,我們可能調用了一個參數不是const的函數,而我們要傳進去的實際參數確實const的,但是我們知道這個函數是不會對參數做修改的。於是我們就需要使用const_cast去除const限定,以便函數能夠接受這個實際參數。

 

 

#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;

}出現這種情況的原因,可能是我們所調用的方法是別人寫的。還有一種我能想到的原因,是出現在const對象想調用自身的非const方法的時候,因為在類定義中,const也可以作為函數重載的一個標示符。有機會,我會專門回顧一下我所知道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限定的指針去指向它,在某一處我們突然又想修改了,可是我們手上只有指針,這時候我們可以去const來修改了。上邊的代碼結果也證實我們修改成功了。

 

 

不過我覺得這並不是一個好的設計,還是應該遵從這樣的原則:使用const_cast去除const限定的目的絕對不是為了修改它的內容,只是出於無奈。(如果真像我說是種無奈,似乎const_cast就不太有用到的時候了,但的確我也很少用到它)

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved