多年来一直对const不是抠的很清楚,最近看了《the c++ templates》,在图书约定中目睹了更高级的变量声明方法,才慢慢明白const的真正用法。
以前看《c++ primer》,作者告诉你怎样看一个使用到了const的语句:const int a; -- “从右向左看”。我一直没搞清楚这句话的意思,究竟怎样从右向左看呢???
在《C++ Templates》中,我看到作者对变量的声明的风格类似是这样的:
1. int const a;
2. int const & a;
3. int& const a = other;
4. int const * a;
5. int const* &a;
6. int const* const a;
7. int const* cosnt& a;
8 int* const & a;
...
才有种顿悟的感觉,如果把const和右边的token结合,那么很多问题就迎刃而解了:
1.a本身作为变量被设定为const,所以a不能在改变。
2.第二句这样的申明在函数中使用:
void func(type const & value);
const 与右边的&结合,所以这个引用是const,你没办法改这个传入引用的的值,比如value = other;这就会导致编译错误。
3.第三句这样的写法,没有实际意义,但有语义意义。
同样,const是修饰a的,那么a是不能在更改为其他变量的引用的,但是由于引用只能在初始话的时候被指定一次,所以int& const a ; 和int & a; 在实际效果上是一模一样的,无论起作为函数参数,还是变量类型。
void fun(int& const value); == void fun(int& value);
int c = 5;
int& const d = c; == int& d = c;
4.const修饰的是*,所以这个指针所指向的东西是不能被更改的,但由于a不是const,所以可以将a指向不同的变量。
void fun(int const* a)
{
*a = 5; //编译错误,试图将a指向的值修改
int b = 5;
a = &b; //ok,因为a不是常量
*a = 10; //同样编译错误,同上上
}
注:在这种声明中,当进入函数的时候,系统在栈上创建了一个新的指针变量,该指针变量的值被设定成传入的指针的值,所以对该指针变量的修改,不会影响传入的指针的值。
5.这种方法和上一种的实际意义基本一样,只是语义上还是不同的。a是作为引用创建的,但和上一种方法的基本一致。
6.第一个const修饰的*,代表指针指向的值不能改,第二个const修饰的a,说不a的值也不能改,这种申明应该是比较常用的,这样声明以后,你传入的指针值,你只能获取这个指针所指向的对象的成员变量或调用函数等等,但是却不能更改任何东西,甚至不能将a重新指定到另一个地址。
7.实际意义等同于6,只是a是作为引用创建的,由于引用的是指针,这4个字节怎样都会被开销掉。
8.这种情况比较少用,const修饰的引用所以不能更改a的值,但是由于a的类型是int*,并且没有被指定为const,所以:
class TestClass
{
public:
int a;
};
void fun(TestClass* const& value)
{
value->a = 12;
}
int main()
{
TestClass t;
t.a = 0;
fun(&t);
cout << t.a << endl; //12 a所指向的东西被改变了
}
总结:
在使用的const的时候,要牢牢记住“右结合原则”,const会寻找右边的任何可以结合的token,类似:
int const* a; //const在右边发现了*,所以const与*结合
const int * a; //const向右边找,看到int,对他来说没用,因为他无法简单的与一个最简类型结合,再向右找,看到*,所以与*结合
const int a; //同上,最终const与a结合了。
int* const& a; //const 与&结合了
const int* const& a; //第一个同*结合了,第二个同&结合了
int b =10;
const int* const& const a = &b; //这个最花哨的写法了,第一个const修饰*, 第二个修饰&,第三个修饰a,由于他是引用,所以这种写法同
cosnt int* cosnt& a = &b; //在实际上是一模一样的
看了这么多例子,应该知道结合条件了吧,const可以和*, &, 具体变量结合,但不能和int, float这种最简类型结合,当然如果你觉得和*,&这种东西结合听起来觉得不爽,那么说它和int* ,float*这种复合类型结合也是可以的。
所以,只要掌握“右结合原则”,以及“结合条件”,那么无论多么复杂的申明语句,都将难不倒你,起码,现在已经难不倒我了:)