const_cast<typename> 运算符,只是改变指针的const属性,但const命名的变量依旧不能改变。
换句话说,就是指针不是const指针,const int* 变为int*,但指向的变量val依旧是const。
我觉得是编译器行为,目的是保证只要const的变量,就一定不能改变,至于上面的运算符的作用,往往是用于参数传递。
如有函数 void fun(int n);
如果需要传入的实参是一个const变量,而我们也知道fun函数本身并不会改变参数的值,这个时候,如果把形参声明为非const是无法通过编译的,只有用const_cast<int>,之后,可以代入函数。
反汇编的源码也说明了const值的不可改变,你的程序,用vs2010调试运行时,cout<<val的反汇编代码,
00F942DC push 0Dh
00F942DE mov ecx,dword ptr [__imp_std::cout (0F9A300h)]
你看这里压入的是 0Dh,也就是13这个字面变量,
而普通的变量打印的汇编代码则是
00F9428C push eax
00F9428D mov ecx,dword ptr [__imp_std::cout (0F9A300h)]
00F94293 call dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (0F9A2FCh)]
压入的是eax(或别的寄存器),寄存器里存着变量的值,也显示出是一个普通变量。
看的出来,该地址的值虽然被改变了,但val依旧被解释为字面常量,并且在编译过程中已经被替换为13了,也正因为编译时就是13,所以编译器是不允许你改变val的值的,否则就乱套了。
但也有一个很有意思的事情,*(&val)的值虽然为13不变,但*(int*)(&val)的值却为23.这里的强制类型转换,应该彻底抹去了指针和val变量的关系。看汇编代码,也是体现出前者是字面值,而后者是一个变量。
cout<<"*(&val): "<<*(&val)<<" ;*(int*)(&val): "<<*(int*)(&val)<<endl; //13 ;23
00F94318 mov esi,esp
00F9431A mov eax,dword ptr [__imp_std::endl (0F9A304h)]
00F9431F push eax
00F94320 mov edi,esp
00F94322 mov ecx,dword ptr [val] //对应源代码 *(int*)(&val)
00F94325 push ecx //压入的是寄存器
00F94326 push offset string " \xa3\xbb*(int*)(&val): " (0F97AFCh)
00F9432B mov ebx,esp
00F9432D push 0Dh //对应源代码 *(&val),压入的是字面常量0Dh
00F9432F push offset string "*(&val): " (0F97898h)
00F94334 mov edx,dword ptr [__imp_std::cout (0F9A300h)]
在你的程序基础上我增加了若干代码,我觉得基本上说明了const_cast<typename>运算符的这种性质#include "stdafx.h"
#include<iostream>
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
const int val=13;
int temp=15;
const int* ptr=&temp;
int* ppp=const_cast<int*>(ptr);
*ppp=16;
// (*ptr)++; // 接触引用的值依旧是const
ptr++; //说明指针不是常量
// (*ptr)++; //指针+1了,指向下一个地址了,但其解除引用后依旧是const
ptr--;
ppp=const_cast<int*>(&val);
(*ppp)=23;
cout<<*ppp<<" ;&ppp: "<<ppp<<endl;
cout<<val<<" ;&val: "<<&val<<endl; //val=13
cout<<"*(&val): "<<*(&val)<<" ;*(int*)(&val): "<<*(int*)(&val)<<endl; //13 ;23
cin.get();
return 0;
}
|