C++標準轉換運算子const_cast – Ider – 部落格園C++標準轉換運算子const_cast

來源:互聯網
上載者:User

C++標準轉換運算子const_cast - Ider - 部落格園

C++標準轉換運算子const_cast

 

前面講了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 = 7cout << "variable:" << variable << endl;return 0;} /**variable:7**/

 

我們定義了一個非const的變數,但用帶const限定的指標去指向它,在某一處我們突然又想修改了,可是我們手上只有指標,這時候我們可以去const來修改了。上邊的代碼結果也證實我們修改成功了。

 

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

Director: Jim Fawcett
  1. C++ Language Tutorial - Type Casting
  2. Object Oriented Design
  3. IBM Complilers - XL C/C++ V9.0 for Linux - The const_cast operator (C++ only)
  4. stackoverflow: Is const_cast safe?

 

前面講了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 = 7cout << "variable:" << variable << endl;return 0;} /**variable:7**/

 

我們定義了一個非const的變數,但用帶const限定的指標去指向它,在某一處我們突然又想修改了,可是我們手上只有指標,這時候我們可以去const來修改了。上邊的代碼結果也證實我們修改成功了。

 

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

Director: Jim Fawcett
  1. C++ Language Tutorial - Type Casting
  2. Object Oriented Design
  3. IBM Complilers - XL C/C++ V9.0 for Linux - The const_cast operator (C++ only)
  4. stackoverflow: Is const_cast safe?
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.