const修饰指针的情况
int b = 500;
const int * a = &b //情况1
int const *a = &b //情况2
int* const a = &b //情况3
const int* const a = &b//情况4
1)先看情况1
如果const位于*号的左侧,则const就是用来修饰指针所指向的变量,即指针指向为常量;如果const位于*号的右侧,const就是修饰指针本身,即指针本身就是常量。1和2的情况相同,都是指针所指向的的内容是常量。所以这种情况下不能对内容进行更改操作。
打个比方来说,如果a是一名仓库管理员的话,他所进入的仓库,里面放的货物他是没资格动的。里面放的是什么就是什么
int b = 500;
const int* a = &b;
*a = 600;//错误
但是也有别的方法改变*a的值,一个是改变 b的值
int b = 500;
const int* a = &b;
b = 600;
cout << * a << endl //得到600
还有一种方法就是a指向别处 (也就是管理员换一个仓库)
int b = 500; c = 600 ;
const int* a = &b ;
a =&c;
cout << *a << endl // 得到600
对于情况1,可以先不初始化。虽然因为指针内容是常量,但是指针本身不是常量。
2)情况2和情况1相同。
3)情况3为指针本身就是常量这种情况不能对指针本身进行任何的改变,而指针指向的内容也不是常量。
还是用上面的例子,如果a是仓库保管员,他只能进入特定(const)的仓库,但是不能区别的仓库(如a++一定是错误的);但是这个仓库的货物是可以随便移动的。(*a =600 是对的)
int b =500 ,c = 600;
int* const a ;// 错误没有初始化
int const a = &b; // 正确 必须初始化
* a = 600;//正确,允许该值
cout<< a++ <<endl;// 错误
4 )情况4是前两种的集合 ,指针本身和指向的内容都是常量。在这里我就不多做赘述了。
const成员函数
我们常定义的成员函数中,常常是有一些不改变类的数据成员,也就是说这些函数是”只读“函数,而有一些函数需要修改数据成员的值。如果把不改变数据成员的函数都加上const关键字进行标示,这显然可提高程序的可读性。此外还能提高程序的可靠性,已经定义成const的成员函数,一旦企图修改数据成员的值,则编译会按照错误处理。
class Point
{
int xVal, yVal;
public:
int GetY() const;
};
//关键字const必须用同样的方式重复出现在函数实现里,否则编译器会把它看成一个不同的函数;
int Point::GetY() const
{
return yVal;
}
如果GetY()试图用任何方式改变yVal或调用const成员函数,编译器就会报错,任何不修改成员数据的函数都应该声明为const函数,这样才有助于提高函数的可读性。
那么将const放在声明前呢?因为这样做的以为着函数的返回值是常量,定义就完全不同了。
那么问题来了,这种情况下我们又要修改类的成员变量怎么办呢?
解决的方法很简单,在const成员函数中,用mutable修饰成员变量名后,就可以修改类的成员变量了。
const在c和c++的区别
const 在c中 是常变量,在编译阶段,c只判断常变量是否作左值,其他的处理和变量一样。这就意味着我们可以通过间接的方式修改const修饰的内容。
const在c++中做作常量,编译阶段,把用到的常量的地方替换成常量的初始值。这就避免了通过间接修改const修饰内容的风险。
在c++中const修饰的变量有一下几个特点
1.一定要初始化
2.不能做左值
3.不能间接修改修改,杜绝了间接访问修改访问修改常量内存的风险
const 和define 相比有什么不同?
1.c++语言可以用const定义常量,也可以用#define定义常量,但是前者比后者有着更多的优点:
const常量有着数据类型,而宏常量没有数据类型。编译器可以对前者进行安全检查,而对后者只进行字符替换,没有类型安全检查,并且在字符替换中可能会产生意想不到的错误(边际效应)。
2.在有些集成化的调试工具可以对const常量进行调试,但是不能对宏常量进行调试。在c++程序中只使用const常量而不使用宏常量,即const常量完全取代宏常量。