1 理解
“const应该理解为只读变量,而不是常量”这是之前死记下来的,当时并没有完全理解什么意思。最近在搜寻“const变量能否作为数组长度大小”问题时,发现原来要彻底理解const变量还是需要从编译链接的角度分析,即存储的位置是不同的。对于常量(如在程序中定义了数字123或者字符串“Hello World”)它有特定的段存储常量,即它的地址是固定的。而只读变量是在栈里的,只是其内容不能在代码中改变,访问它的时候需要弹栈操作,而不是通过地址直接定位。
基于上述理解,再来回答以下两个问题。
问题一:const变量能否作为数组长度大小,即如下代码能否编译通过?
Const int len = 10;
int array[len];
答:基于上述理解,由于只读变量存储在栈中,所以上述貌似应该不能通过。但是在VS2008的环境中又是通过的。原因在于,与编译器有关,最新的C99编译器还有C++中一般是通过的。但是仍然不建议这样使用。
问题二:如果类中定义的常量,能否被所有类对象共享?即如果下代码中a1.constA_是否与a2.constA_相同。
class A{
const int constA_;
}
A a1,a2;
答:是不相同的,正如上所述,const始终是变量存储在栈中,而a1的栈空间和a2的栈地址是不同的。所以不能被共享。正确的做法是使用枚举常量,见参考文献1。
2 const引用
非const引用不能指向 const对象,但const引用能够指向非const对象。
const int a=1024
int b=20;
const int& a1 = a; //正确
const int& b1 = b; //正确
int& a2 = a; //错误
另外,附一种奇葩的用法,在低精度引用变量来自高精度时,可以通过const引用实现。但是修改引用是不能修改原变量的值的。
double d = 3.15; //正确
int& a1 = d; //错误
const int& a2=&d; //通过,但是a的值是不会随d的变化而改变的。因为这一语句会被编译器转换成两条语句“临时int型变量等于d”“a2指向临时变量”
类似地,当const对象不允许直接使用const_cast去除const属性,但指针或者引用是允许的,同上转换之后,两个是没有任何关联的,修改非const对象是不会影响到const对象的。如下代码所示。
const int b = 100;
//intd = const_cast<int>(b) ; //不允许
int d = *(const_cast<int*>(&b)); //允许
综上,const_cast用来移除常量且用于指针或者引用,且目的并不是修改(因为转过换后两者没有关系)而是让函数接受。
关于使用const_cast转换后,到底与被转换的关系,这取决于是转换后,是否取值,如果取值了,则是把申请个临时变量,如果只是单纯的指针,那么指向的是同一个地址。如下所述。
方式一:
cosnt int a = 100;
int b = *const_cast<int*>(&a);
cout << &b << " "<< &a << endl; //此时a和b的地址是两个不同的。
方式二:
const int a = 100;
int *b =const_cast<int*>(&a);
cout <<b<<" "<<&a << endl; //此时a和b是同一个地址
3 初始化
Const变量如果只是作为普通函数中声明的,那么必须在声明时就初始化。如果是作为类的成员变量,那么初始化必须在初始化列表中。
拓:只能在初始化列表中初始化的变量。
(1)const成员(2)引用成员(3)如果成员是类对象,且该类没有默认的构造函数(4)基类,且基类没有默认构造函数
4 const 修饰成员函数
当const修改成员函数时,首先需要在函数参数列表后面添加 const,然后在定义时,也需要加上const修饰。同时,用const 修饰的成员函数不能修改类的成员变量。
class Test
{
public :
void TestConstFunction(void) const;
}
void Test::TestConstFunction(void) const
{
//iValue_= 100; 错误不允许修改
}
参考文献
[1] http://blog.sina.com.cn/s/blog_5fa144950100ko07.html