const int* p 中 const 修饰的是 *p
int* const p 中 const 修饰的是 p
关键是看const修饰的是什么
技巧是看const和*的相对位置
const在*左边,则指针指向的值不可改变;const在*右边,则指针本身不可改变;
比如:
const int * pOne (推荐)或者 int const * pOne; //指向整形常量 的指针,它指向的值不能修改
int * const pTwo; //指向整形的常量指针 ,它不能在指向别的变量,但指向(变量)的值可以修改。
const int *const pThree(推荐)或者 int const * const pThree; //指向整形常量 的常量指针 。它既不能再指向别的常量,指向的值也不能修改
需要注意的是:如果想像上面第二种方法定义一个不可改变的指针,则必须用下面的形式
int* const p=一个地址; (因为指针本身的值是不能被修改的所以它必须被初始化)
==========华丽分割线=====================================================
以下内容转自:博客园 https://www.cnblogs.com/xkfz007/articles/2419540.html
下面说一下const的一些其他用法:
const修饰函数参数
const修饰函数参数是它最广泛的一种用途,它表示在函数体中不能修改参数的值(包括参数本身的值或者参数其中包含的值):
void function(const int Var); //传递过来的参数在函数内不可以改变(无意义,该函数以传值的方式调用)
void function(const char* Var); //参数指针所指内容为常量不可变
void function(char* const Var); //参数指针本身为常量不可变(也无意义,var本身也是通过传值的形式赋值的)
void function(const Class& Var); //引用参数在函数内不可以改变
参数const通常用于参数为指针或引用的情况,若输入参数采用“值传递”方式,由于函数将自动产生临时变量用于复制该参数,该参数本就不需要保护,所以不用const修饰。
const修饰类对象/对象指针/对象引用
const修饰类对象表示该对象为常量对象,其中的任何成员都不能被修改。对于对象指针和对象引用也是一样。
const修饰的对象,该对象的任何非const成员函数都不能被调用,因为任何非const成员函数会有修改成员变量的企图。
例如:
class AAA
{
void func1();
void func2() const;
}
const AAA aObj; //aObj是由const修饰的对象,所以aObj无法调用类中的非const方法
aObj.func1(); 错误
aObj.func2(); 正确
const AAA* aObj = new AAA(); //aObj是由const修饰的对象指针,所以aObj也无法调用类中的非const方法
aObj->func1(); 错误
aObj->func2(); 正确
const修饰数据成员
const数据成员只在某个对象生存期内是常量,而对于整个类而言却是可变的。因为类可以创建多个对象,不同的对象其const数据成员的值可以不同。所以不能在类声明中初始化const数据成员,因为类的对象未被创建时,编译器不知道const 数据成员的值是什么,例如:
class A
{
const int size = 100; //错误
int array[size]; //错误,未知的size
}
const数据成员的初始化只能在类的构造函数的初始化列表中进行。要想建立在整个类中都恒定的常量,可以用类中的枚举常量来实现,例如:
class A
{
…
enum {size1=100, size2 = 200 };
int array1[size1];
int array2[size2];
…
}
枚举常量不会占用对象的存储空间,他们在编译时被全部求值。但是枚举常量的隐含数据类型是整数,其最大值有限,且不能表示浮点数。
const修饰成员函数
const修饰类的成员函数,用const修饰的成员函数不能改变对象的成员变量。一般把const写在成员函数的最后:
class A
{
...
void function()const; //常成员函数, 它不改变对象的成员变量(除非有mutable修饰). 也不能调用类中任何非const成员函数。
...
}
对于const类对象/指针/引用,只能调用类的const成员函数。
const修饰成员函数的返回值
1、一般情况下,函数的返回值为某个对象时,如果将其声明为const时,多用于操作符的重载。通常,不建议用const修饰函数的返回值类型为某个对象或对某个对象引用的情况。原因如下:如果返回const对象,或返回const对象的引用,则返回值具有const属性,返回实例只能访问类A中的公有(保护)数据成员和const成员函数,并且不允许对其进行赋值操作,这在一般情况下很少用到。
2、如果给采用“指针传递”方式的函数返回值加const修饰,那么函数返回值(即指针所指的内容)不能被修改,该返回值只能被赋给加const 修饰的同类型指针:
const char * GetString(void);
// 如下语句将出现编译错误:
char *str=GetString();
// 正确的用法是:
const char *str=GetString();
const常量与define宏定义的区别
(1) 编译器处理方式不同
define宏是在预处理阶段展开。
const常量是编译运行阶段使用。
(2)类型和安全检查不同
define宏没有类型,不做任何类型检查,仅仅是展开。
const常量有具体的类型,在编译阶段会执行类型检查。
(3) 存储方式不同
define宏仅仅是展开,有多少地方使用,就展开多少次,不会分配内存。
const常量会在内存中分配(可以是堆中也可以是栈中)。