本文内容都属于个人总结,限于本人能力有限,如有问题欢迎指正。
const的作用
const:大致意思是“我承诺不改变这个值”。主要用于说明接口,这样在把变量传入函数时就不必担心变量会在函数内被改变。编译器负责确认并执行const的承诺。或者可以说在当前作用域内值不发生改变。
为什么使用const?
- 使用符号化常量的代码比直接使用字面值常量的代码更易维护
- 我们经常通过指针读取数据,但是很少通过指针写入数据
- 绝大多数函数的参数只负责读取数据,很少写入数据
常用用法
- 常变量:
const 类型说明符 变量名
- 常指针:
const 类型说明符* 指针名 ,类型说明符* const 指针名
- 常引用:
const 类型说明符 &引用名
- 常对象:
类名 const 对象名
- 常成员函数:
类名::fun(形参) const
- 常数组:
类型说明符 const 数组名[大小]
const
的语法虽然变化多端,但并不高深莫测,如果一个被指物是常量,const
可以写在类型之前,也可以写在类型之后,这两种写法的意义是相同的。
//下面两行代码是等同的
const int a = 5; //设置a为常量5
int const b = 6; //设置b为常量6
当const与指针一起使用时,又有些不同
char p[] = "Hello";
char* p1 = p; //非常量指针,非常量数据
const char* p1 = p; //非常量指针,常量数据
char const* p1 = p; //同上
char* const p1 = p; //常量指针,非常量数据
const char* const p1 = p; //常量指针,常量数据
如何使用
用法1:常量
在程序中应尽量使用常量代替数值,不但可以方便阅读,也方便了程序的维护。程序中在多个地方使用同一个常量,则需要改变该常量时,只需要修改一个符号即可。
const与#define的比较,
#define PI 3.14
#define 是预处理方法,其不被视为语言的一部分。在编译器处理源代码时,其定义的PI
就已经被3.14替代,于是当你运用此常量但获得一个编译错误信息时,可能会带来困惑,因为这个错误信息也许会提到3.14,而不是PI
。
使用const可以解决这个问题:
const double PI = 3.14;
PI会作为一个语言被编译器看到,因此当出现错误时,其会被编译器指出。
用法2:指针和const
指针和const的常用用法
- 第一种方法是让指针指向一个常量对象,这样可以防止使用该指针改变所指向的值,
const
位于*的左侧
int age = 13;
const int* pt = &age; //表示不能通过 *pt 改变age的值
cout << *pt << endl; //输出结果应该为13
//*pt = 14; //是无效的,在声明pt时,const的作用就是防止使用*pt改变其所指向的值
age = 14; //有效
cout << *pt << endl; //输出结果应该为14
int year = 2020;
pt = &year; //有效 此时pt是year的地址,但是此时不能使用*pt改变year的值
cout << *pt << endl; //输出结果应该为2020
- 第二种方法是将指针本身声明为常量,这样可以防止指针改变其指向的位置及指针本身的值是不能发生改变的,
const
位于*的右侧
int age = 13;
int* const pt = &age; //表示指针pt的值只能是age的地
cout << *pt << endl; //输出结果为13
*pt = 14; //是有效的
cout << *pt << endl; //输出结果为14
int year = 2020;
pt = &year; //无效 pt的值是不能改变的
用法3:const修饰函数传入参数
当函数的参数是为了进行值传递且不对其进行修改时,并且其为较大的结构,类对象,或者数组时,我们通常使用const引用或者const指针,其目的是为了提高程序的效率,这样可以节省复制结构所需要的时间和空间。
void Fun(const A *in); //修饰指针型传入参数,表示在函数内部in指向的值是不能被修改的
void Fun(const A &in); //修饰引用型传入参数,表示in引用的值在函数内部是不能被修改的
当使用const修饰函数的传入参数时,可以使函数能够处理const 和非const参数,否则只能接受非const数据。
用法4:const修饰函数返回值
可以阻止用户修改返回值。返回值也要相应的赋给一个常量或常指针。多用于操作符重载。
const Rational operator* (const Rational& lhs,const Rational& rhs);
用法5:const修饰成员函数
当我们为了改善c++程序效率时,使用用法3传递类对象时,对象会被声明成const对象,一旦一个对象被声明成为一个const对象后,那么就只能访问它的const成员函数,不能访问非const函数(而非const对象可以访问任意的成员函数,包括const成员函数)
const成员函数的好处:
第一,它们使class接口比较容易被理解。这是因为,得知哪个函数可以改动对象内容而哪个函数不行。
第二,它们使“操作const对象”成为可能。
例:
class Point
{
public:
Point(int a = 0, int b = 0)
:x(a), y(b)
{}
int getX() const
{
return x;
}
int getY() const
{
return y;
}
void setX(int x)
{
this->x = x;
}
private:
int x, y;
};
void display(const Point p1)
{
//在这个函数内p1是一个const对象,所以在此函数内只能访问const成员函数getX()与getY() ,而不能访问setX().
cout << p1.getX() << endl; //有效
p1.setX(); //无效
}
在常量成员函数内,是不允许去改变类内的数据成员的值。
例:
class Point
{
public:
Point(int a = 0, int b = 0)
:x(a), y(b)
{}
int getX() const
{
x++; //无效的,常量成员函数内部可以修改类内的数据
return x;
}
private:
int x, y;
};
用法6:const和数组
const 修饰一个数组时,该数组内的值是不可以被改变的;
const int array[2] = { 1,2 }; //声明array为const数组
array[0] = 3; //无效,不能修改数组内的值
int* p = array; //无效,array的值不能赋值给非const型实体
用法7:const和引用
const修饰引用时,表示不能通过这个引用改变原来的数据
int age = 10;
const int& ref = age; //声明ref为一个const引用
ref = 9; //无效
age = 9; //有效
参考
- Stephen Prata 著C++ Primer Plus (第六版)中文版
- Bjarne Stroustrup 著 C++程序设计语言(原书第四版)中文版
- Scott Meyers 著 Effective C++ (第三版)中文版
- C/C++中const关键字详解