首先,普通const变量
const默认具有内部连接属性,这个可以参考连接里面的一篇文章,说的很详细.
如果让const常量可以在多个文件里面使用,必须在定义的时候指定extern.如:
extern cosnt int i=0;
普通的const变量不会占用内存空间.但是加上extern后就会强制分配内存给这个变量.还有一种情况,在程序中用到这个const变量的地址的时候也会分配空间.
进入正题,所有的临时变量都会被默认指定为const类型.所以当你要改变一个临死变量的时候就会出错.例如:
// Constant return by value
// Result cannot be used as an lvalue
class X ... {
int i;
public:
X(int ii = 0);
void modify();
} ;
X::X( int ii) ... { i = ii; }
void X::modify() ... { i++; }
X f5() ... {
return X();
}
const X f6() ... {
return X();
}
void f7(X & x) ... { // Pass by non-const reference
x.modify();
}
int main() ... {
f5() = X(1); // OK -- non-const return value
f5().modify(); // OK
// Causes compile-time errors:
//! f7(f5());
//! f6() = X(1);
//! f6().modify();
//! f7(f6());
} /**/ ///:~其中比较难理解的是//! f7(f5());这一行.为什么这一行是错的呢?解释如下:
f5()直接作为f7的变量,这里实际上会出现一个临时变量.而f7又是引用传递参数,在f7里面直接操作这个临时变量,所以会出错.
所以如果f7采用值传递,或者使用const引用传递,都不会出现错误.
然后是类内部的const变量:
... {
enum ...{size=9};
int array_2[size];
const int j;
static const int i=9;
int array[i];
public:
A(int i_j);
} ;
A::A( int i_j):j(i_j)
... {
}
int main ()
... {
A a(3);
return 0;
}
类内部的const变量分两种,一种是非静态的.它的初始化应该在这个类的构造函数的前面,最好是放在初始化列表里面。
静态的const 变量的初始化可以在类的声明里面。如上面的程序,但是这个程序在vc里面不能不能编译通过。
静态的const变量可以直接用作数组的大小。但上面的普通const变量却不可以。
还有另外一种方法,比较古老的方法就是用一个没有标签的enum。程序中已经很清楚。
const类成员函数不会改变类成员变量。const成员函数需要在声明和定义处都带上const关键字。一个const的类对象只能调用类中的const成员函数,但实际上,const的成员函数其实也能改变类中的成员变量,方法有两种,一种是在const成员函数中,将this指针进行强制转换,使其失去const 的功能,如下:
int i;
public:
Y();
void f() const;
} ;
Y::Y() ... { i = 0; }
void Y::f() const ... {
//! i++; // Error -- const member function
((Y*)this)->i++; // OK: cast away const-ness
// Better: use C++ explicit cast syntax:
(const_cast<Y*>(this))->i++;
}
另外一种方法就是使用mutable 关键字,在类的声明中,在类的成员变量前加上mutable关键字,那么这个成员变量就可以在const成员函数里面改变。是合法的。
int i;
mutable int j;
public:
Z();
void f() const;
} ;
Z::Z() : i( 0 ), j( 0 ) ... {}
void Z::f() const ... {
//! i++; // Error -- const member function
j++; // OK: mutable
}
据可以被改变”。不知何故,环境正在改变数据(可能通过 多任务处理),所以,v o l a t i l e告诉编
译器不要擅自做出有关数据的任何假定—在优化期间这是特别重要的。如果编译器说:“我
已经把数据读进寄存器,而且再没有与寄存器接触”。一般情况下,它不需要再读这个数据。
但是,如果数据是v o l a t i l e修饰的,编译器不能作出这样的假定,因为可能被其他进程改变了,
它必须重读这个数据而不是优化这个代码。
就像建立c o n s t对象一样,程序员也可以建立v o l a t i l e对象,甚至还可以建立const volatile对
象,这个对象不能被程序员改变,但可通过外面的工具改变。