程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> C++中四種類型轉換 const_cast是否能改變常量

C++中四種類型轉換 const_cast是否能改變常量

編輯:關於C++

we have four specific castingoperators:dynamic_cast, reinterpret_cast, static_cast and const_cast. Their format is to follow the new type enclosed between angle-brackets (<>) and immediately after, the expression to be converted between parentheses.

dynamic_cast <new_type> (expression)
reinterpret_cast <new_type> (expression)
static_cast <new_type> (expression)
const_cast <new_type> (expression)

一、對C++中四種類型轉換總結如下:

const_cast(expr)

用來移除對象的常量性(cast away the constness)

const_cast一般用於指針或者引用

使用const_cast去除const限定的目的不是為了修改它的內容

使用const_cast去除const限定,通常是為了函數能夠接受這個實際參數

static_cast(expr)

編譯器隱式執行的任何類型轉換都可以由static_cast完成

當一個較大的算術類型賦值給較小的類型時,可以用static_cast進行強制轉換。

可以將void*指針轉換為某一類型的指針

可以將基類指針轉換為派生類指針

無法將const轉化為nonconst,這個只有const_cast才可以辦得到

reinterpret_cast(expr)

“通常為操作數的位模式提供較低層的重新解釋”也就是說將數據以二進制存在形式的重新解釋。

int i;

char *p = "This is a example.";

i = reinterpret_cast<int>(p);

//此時結果,i與p的值是完全相同的。

int *ip

char *pc = reinterpret_cast<char*>(ip);

// 程序員需要記得pc所指向的真實對象是int型,並非字符串。

// 如果將pc當作字符指針進行操作,可能會造成運行時錯誤

// 如int len = strlen(pc);

dynamic_cast(expr)

執行“安全向下”轉型操作,也就是說支持運行時識別指針或所指向的對象,這是唯一個無法用舊式語來進行的轉型操作。

dynamic_cast可謂是最嚴格的轉換,static_cast次之,而reinterpret_cast則是最寬松的。如果你遇到不能將整型轉變為函數指針的問題,你可以這樣解決:

reinterpret_cast<LPFUN&>(nAddress);

注意LPFUN這裡有個“&”符號,表示引用,C++的引用其實就是用指針實現的,而這些“轉換”其實都是指針的轉換,所以加上引用符號編譯才能通過。

二、也許大家都有過這樣的疑惑:const_cast可以去除一個常量的const屬性,去除const屬性後應該可以對“常量”進行修改,通過調試器發現內存中的值是被改變的,可是再傳遞這個“常量”的時候,值卻一直保持原狀,實在古怪,在Windows下用VC、嘗試如此,在Linux下用g++嘗試也如此,我原先以為和編譯器的優化選項有關系,把所有優化選項關閉,照樣沒用,為什麼?

寫了個程序進行測試:

#include <iostream>
using namespace std;
    
void Fun(int &value)
{
    cout << "Fun(val) = " << value << endl;
}
    
int main(void)
{
    const int val = 100;
    
    int *ptr = const_cast<int *>(&val);
    *ptr = 200;
    cout << &val << endl;
    cout << ptr << endl;
    cout << "val = " << val << endl;
    cout << "*ptr = " << *ptr << endl;
    
    
    int &ref = const_cast<int &>(val);
    ref = 300;
    cout << "val = " << val << endl;
    cout << "ref = " << ref << endl;
    
    Fun(const_cast<int &>(val));
    
    return 0;
}

輸出為:

可以看出打印的地址是一樣的,而且奇怪的是val還是等於100,而通過*ptr打印出來的卻是更改後的200,再者Fun函數打印的是300,即被引用再次修改了一次,在打印語句附近設置斷點並調試反匯編,截取一段如下圖:

可以明顯地看出系統是對val這個const進行了預處理般的替換,將它替換成“64h”(十六進制的64就是十進制的100),即在編譯生成的指令中val就已經被替換成100了,其實加const只是告訴編譯器不能修改而不是真正地不可修改,如果程序員不注意而去修改了它會報錯,現在我們利用const_cast去除了常量性,然後通過指針和引用對其進行了修改,所以通過指針打印或者引用傳參的時候就能看出其內存確實變化了,但為了保護val這個變量本來的const特性,所以每次我們使用val時,系統都將其替換成初始值100,確保了val還是“不可變”的。記住,只有當const限定符加在已經初始化的全局變量前面的時候,此時變量處在.rodata段(linux下),才是真正的不可修改,否則通過指針都是可以修改的,雖然編譯過程中會產生警告。

在linux下測試也是同樣的輸出結果:

附錄:

MSDN上關於四種cast的說明:

reinterpret_cast Operator

The reinterpret_cast operator allows any pointer to be converted into any other pointer type. It also allows any integral type to be converted into any pointer type and vice versa. Misuse of the reinterpret_cast operator can easily be unsafe. Unless the desired conversion is inherently low-level, you should use one of the other cast operators.

dynamic_cast Operator

The expression dynamic_cast( expression ) converts the operand expression to an object of type type-id. The type-id must be a pointer or a reference to a previously defined class type or a“pointer to void”. The type of expression must be a pointer if type-id is a pointer, or an l-value if type-id is a reference.

static_cast Operator

The expression static_cast < type-id > ( expression ) converts expression to the type of type-id based solely on the types present in the expression. No run-time type check is made to ensure the safety of the conversion.

const_cast operator

The const_cast operator can be used to remove the const, volatile, and __unaligned attribute(s) from a class.

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