C/C++ const详解

1.  什么是const

1.1 const基础知识

const是C语言关键字之一,它先定了一个变量为只读变量(即变量的值不能被修改)。

const通常作为符号常量出现,能够增加代码的可维护性。

例如我们可以定义某一类元素个数固定的数组的大小为const size = 10;

  1.2. const主要有如下几类应用

  • 常变量 const <类型> 变量名
  • 常指针 const <指向类型>* 指针名        <指向类型> * const 指针   
  • 常数组 const <类型> 数组名[数组大小]
  • 常引用 const <类型>& 引用名
  • 常对象 const <类名>& 对象名
  • 常成员函数 <类名>::<函数名>(形参)const
除了常指针外,另外五种类类型的 const与类型标识符可以互换位置

2. const变量与常量

C语言的数据分为两类,一种是常量,一种是变量。
常量如:6, “abc”,存储在数据的只读区。
const变量,可以成为常变量,但最根本的还是个变量,尽管他只读。
因此,在ANSI C标准下的编译器中,如下代码会产生错误。
const size = 5;
int a[size];


因为数组定义时必须知道其大小才能为其分配内存空间
但是在C99标准下的编译器,如GCC,VS2005等系列,该代码不会报错。
从编译过程的角度来看,上面的代码原本就应该合理,C语言的初始化在编译时期就已经完成
所以,编译时期,编译到第二行代码的时候,就已经知道了size的值了。

3.const与指针(const的限定内容)

  • 关于typedef陷阱
typedef与const一起用时会产生一个陷阱,我们看下面的代码,

typedef char* pstr;
const char* p1;
const pstr p2;
p1++;
p2++;//在p2++出编译器会报错。原因如下,




尽管typedef只是给char*取了个别名pstr;但是编译器还是把整个ptr当成了一个类型,

因此const pstr p2;限定了p2只读。p2++自然也就有错误了。

而p1++为什么不会报错呢,原因很简单const char* p1;限定的是p1指向的变量只读,

也就是下面一个知识点要说的左定值,p1的指向可以发生改变。
  •  关于“左定值、右定向”问题
const char* p;
const * char *p;
char const*p;


这三行代码都使用了const,但是有一个问题,const究竟是修饰p本身还是*p。
针对这一点,我们可以利用规律,左定值右定向来判断(即const相对*的位置)。
当const在*左边时,*p只读,
当const在*右边时,p只读。
所以
const char* p;//*p只读,p可以指向其他对象
const * char *p;//*p只读,p可以指向其他对象,同上一行
char const*p;//p只读,初始化时即确定指向,之后不能指向其他对象,但是*p可以改变指向对象的值
上面所说的*p只读,是指不能通过*p改变指向对象的值,而不是指向对象的值本身不能改变。
例如

int a = 10;
const int * p = &a;
*p++;//错误。不能通过p改变a的值
a++;//正确

  • const限定内容的其他情况
观察下面代码,判断const修饰的内容
const int *p1, p2;
int *const p1, p2;
const int * const p1, p2;
cosnt修饰情况如下

const int *p1, p2;//*p1是一个整体;相当于const int *p1; const int p2;
int *const p1, p2;//*const p1是一个整体,const不修饰p2;相当于:int *const p1; int p2;
const int * const p1, p2;//第一个const修饰p1、p2;第二个从const修饰p1
			//相当于:const int * const p1; const int p2;


4 const 与数组

这个暂时没什么好讲的,数组就是变量的集合

5 const与引用

定义方式:
<类型> const& 引用 = ...;
cosnt <类型>& 引用 = ...;
两种定义方式等价;
在老式编译器const引用必须是指向const对象的引用。若指向非const对象则会产生错误;
但在现在的VS中,const引用可以指向非const对象了。
定义引用后,不能通过引用改变对象的值,但是对象可以通过原来的名字,修改值。

const 引用则可以绑定到不同但相关的类型的对象或绑定到右值。
1. const int &i = 10;// 指向常量
2. int i = 10, j = 5;
    const int &kk = i + j;//指向右值 i+j。
3. double d = 10;

const int &dd = d;//指向相关类型
const修饰引用有一个值得注意的情况就是他的初始化


我们说初始化是在编译时完成的,但是引用的初始化只是初始化他指向的对象,而没有把对象的值也给他(除非指向常量)
1. int i = 10;
    const int &ii = i;//初始化ii指向i;为i的别名
2.int i = 10, j = 5;
   const int &kk = i+j;//初始化kk指向i+j;kk的具体值在运行时才得到。
6 const与对象

对象实际上也可以看成一种变量,一般不会定义一个const的类对象,所以意义不大,此处不做深究


7 const与类
  • 修饰成员变量
必须且只能在构造函数的初始化列表里初始化,在构造函数体内都不行
  • 修饰成员函数
void f() const; // const成员函数中不允许对数据成员进行修改


8补充














原文地址:https://www.cnblogs.com/Windeal/p/4284698.html