const 指针的定义
声明指针时,可以在类型前或后使用关键字const,也可在两个位置都使用。例如,下面都是合法的声明,但是含义大不同:
const int* pOne; //指向整型常量的指针,它指向的值不能修改
int* const pTwo; //指向整型的常量指针,它不能在指向别的变量,但指向(变量)的值可以修改。
const int *const pThree; //指向整型常量的常量指针。它既不能再指向别的常量,指向的值也不能修改。
关键字const右边来确定什么被声明为常量 ,如果该关键字的右边是类型,则值是常量;如果关键字的右边是指针变量,则指针本身是常量。
const指针和指向const的指针
指向const的指针
指针指向的内容是不能被修改的!!
两种写法:
1 | const int* p |
1 | int const* p |
第一种可以理解为,p是一个指针,指向一个const int类型的变量。p本身不用初始化它可以指向任何标示符,但这里它指向的内容是不能被改变的。
第二种很容易被理解成是p是一个指向int的const指针(指针本身不能被修改,但这样理解是错误的,它也是表示的是指向const的指针(指针指向的内容是不能被修改的),它跟第一种表达的是一个意思。
为了避免混淆推荐大家用第一种。
const指针
指针本身的值是不能被修改的!!
只有一种写法:
1 | int* const p = 一个地址; |
这种形式可以被理解为,p是一个指针,这个指针是指向int的const指针。它指向的值是可以被改变的,如
*p=3;
指向const的指针(指针指向的内容不能被修改)const关健字总是出现在*的左边;
而const指针(指针本身不能被修改)const关健字总是出现在*的右边。
那不用说两个const中间加个*肯定是指针本身和它指向的内容都是不能被改变的。
const修饰函数的参数
如果参数作输出用,不论它是什么数据类型,也不论它采用“指针传递”还是“引用传递”,都不能加const 修饰,否则该参数将失去输出功能。
const 只能修饰输入参数:
如果输入参数采用“指针传递”,那么加const修饰可以防止意外地改动该指针,起到保护作用。对于非内部数据类型的输入参数,应该将“值传递”的方式改为“const引用传递”,目的是提高效率。例如: void Func(A a) 改为 void Func(const A &a)。
对于内部数据类型的输入参数,不要将“值传递”的方式改为“const引用传递”。否则既达不到提高效率的目的,又降低了函数的可理解性。例如 void Func(int x)不应该改为 void Func(const int &x) 。
const 修饰函数的返回值
如果给以“指针传递”方式的函数返回值加const 修饰,那么函数返回值(即指针)的内容不能被修改,该返回值只能被赋给加const 修饰的同类型指针。例如函数const char * GetString(void);
如下语句将出现编译错误:
char *str = GetString();
正确的用法是
const char *str = GetString();
如果返回值不是内部数据类型,将函数A GetA(void)
改写为const A & GetA(void)
的确能提高效率。但此时千万千万要小心,一定要搞清楚函数究竟是想返回一个对象的“拷贝”还是仅返回“别名”就可以了,否则程序会出错。
函数返回值采用“引用传递”的场合并不多,这种方式一般只出现在类的赋值函数中,目的是为了实现链式表达。
const修饰成员函数
关于Const函数的几点规则:
- const对象只能访问const成员函数,而非const对象可以访问任意的成员函数,包括const成员函数.
- const对象的成员是不可修改的,然而const对象通过指针维护的对象却是可以修改的.
- const成员函数不可以修改对象的数据,不管对象是否具有const性质.它在编译时,以是否修改成员数据为依据,进行检查.
- 然而加上mutable修饰符的数据成员,对于任何情况下通过任何手段都可修改,自然此时的const成员函数是可以修改它的
附注:
几种函数传参方式及区别:
值传递:形参是实参的拷贝,改变函数形参的值并不会影响外部实参的值;
指针传递:指针传递参数从本质上来说也是值传递,它传递的是一个地址。【值传递过程中,被调函数的形参作为被调函数的局部变量来处理,即在函数内的栈中开辟内存空间以存放由主调函数放进来的实参的值,从而成了实参的一个副本(记住这个,函数内参数的是实参的副本)】。由于指针传递的是外部实参的地址,当被调函数的形参值发生改变时,自然外部实参值也发生改变。
引用传递:被调函数的形参虽然也作为局部变量在栈中开辟了内存空间,但是栈中存放的是由主调函数放进的实参变量的地址。被调函数对形参的任何操作都被处理成间接寻址,即通过栈中存放的地址访问主调函数中实参变量(实参和形参通过引用,合二为一,说白点就是:一个人,有两个名字那种;后面想会详细说)。因此,形参的任何改动都会直接影响到实参。