C++Primer(5th) Notes - 2.4 const限定符

文章目录

  • 2.4 const限定符
      • const对象仅在文件内有效
    • 2.4.1 const的引用(reference to const)
      • 【1】初始化和对const的引用
    • 2.4.2 指针和const
      • 【1】指向常量的指针(pointer to const)
      • 【2】const指针(const pointer)
    • 2.4.3 顶层const
      • 【1】顶层/底层const的区别
    • 2.4.4 constexpr和常量表达式
      • 【1】constexpr变量
      • 【2】字面值类型
      • 【3】指针和constexpr
    • 2.4.5 关于引用的一些补充知识
      • 【1】对常量的引用和普通引用的相同点/不同点
      • 【2】有没有 `int &const r = i`

@Author:CSU张扬
@Email:[email protected] or [email protected]
@我的网站: https://www.faker.top

2.4 const限定符

  1. const 对象创建后,值不能被改变。
  2. const 对象必须被初始化。

这两条对以下所述的 const 类型都适合。

const对象仅在文件内有效

  1. 如果在多个文件中出现了同名的 const 变量时,相当于在不同文件里分别定义了一个独立的变量。
  2. 若我们希望在文件之间共享,只在一个文件里定义它,其他文件里声明它(extern)。

2.4.1 const的引用(reference to const)

即:对常量的引用

【1】初始化和对const的引用

  1. 引用类型必须和引用的对象类型不需要一致,只要能够转化成引用的类型即可。因此,常量引用可以绑定 常量/非常量对象、字面值、表达式。

  2. 非常量引用不能绑定一个常量对象。

  3. 对常量的引用 不能被用作 修改所指的对象。例如:

    int i = 0;
    const int &r = i;
    r = 1;  // 错误,r是常量引用
    

2.4.2 指针和const

【1】指向常量的指针(pointer to const)

性质和对 const 的引用几乎类似。

  1. 指针类型必须和所指对象的类型一致。
  2. 指向常量的指针可以绑定 常量/非常量对象。
  3. 普通指针不能绑定一个常量对象。
  4. 指向常量的指针 不能通过该指针 修改所指的对象的值。

唯一的不同就是第2条:对常量的引用可以绑定字面值、表达式。指向常量的指针不能。

注意:
我们不能通过 *p 来修改所指对象的值,但是我们可以修改 p 的值,此时 p 指向另一个对象。也就是说 *p 是一个不可修改的左值。

int i = 1;
int j = 2;
const int *p = &i;
cout << p << " " << *p << endl;  // 0x61fe3c 1
int *q = &j;
cout << q << " " << *q << endl;  // 0x61fe38 2
p = q;
cout << p << " " << *p << endl;  // 0x61fe38 2
*p = 3;  // 错误,*p是一个不可修改的左值

【2】const指针(const pointer)

* 放在 const 前说明指针是个常量,即指针本身的值不变,而非指向的值不变。
我们可以通过 *p 来改变指向的对象的值。

int i = 0, j = 1;
int *const p = &i;
p = j;  // 错误,p的值不能改变,p中存放着i的地址
*p = 10;  // 正确,i的值变为10

性质和指向常量的指针相同。

2.4.3 顶层const

顶层const(top-level const):指针本身是个常量。
底层const(low-level const):指针所指的对象是个常量。

【1】顶层/底层const的区别

  1. 顶层const适用于算术类型、类、指针。
  2. 底层const适用于指针和引用。
int i = 0;
const int j = i;  // 顶层,j是int型的对象
int *const q = &i;  // 顶层,表示指针本身是常量
const int *p = &i;  // 底层,表示指针所指对象是个常量
const int &r = i;  // 底层,引用类型都是底层const

顶层/底层 const 赋值规则,书上说的太过复杂,其实就是前面几节 const的引用,指向常量的指针,常量指针一些性质。

比较通用的规则:
我们可以使用非常量初始化一个底层 const 对象,反过来不行。

2.4.4 constexpr和常量表达式

常量表达式(const expression):值不会改变,并且在编译过程中就能得到计算结果的表达式。字面值属于常量表达式。

一个对象或者表达式是不是常量表达式由数据类型和初始值共同决定。

const int a = 20;  // yes
const int b = a + 1;  // yes
int c = 1; // no, 因为不是const int
const int d = get_size();  //no, 我们到运行get_size()时才能确定d的值

【1】constexpr变量

我们很难区分一个变量到底是不是常量表达式,或者我们变量的初始值根本不是常量表达式。于是,C++11 允许将变量声明为 constexpr 由编译器验证变量是否是常量表达式。

constexpr int a = 1;  // yes
constexpr int b = a + 1;  // yes
constexpr int c = size();  // 当size()是constexpr函数时正确。

【2】字面值类型

算术类型、指针和引用都属于字面值类型,自定义类、IO库、string类都不属于。

指针能定义为 constexpr,但初始值必须为 nullptr0,或者是某个固定地址的对象。函数体内的变量一般并非存在固定地址中,所以 constexpr 指针不能指向这样的对象,函数体之外的可以。当然函数体内的静态变量也可以。

【3】指针和constexpr

constexpr 只对指针本身有效,与其所指对象无关。
例如:constexpr int *q = nullptr,q是一个常量指针。

constexpr 指针既可以指向常量也可指向非常量。

2.4.5 关于引用的一些补充知识

【1】对常量的引用和普通引用的相同点/不同点

相同点

  1. 必须初始化。

不同点

  1. 对常量的引用不能被修改它的值。
  2. 普通引用必须绑定到类型相同的对象上,对常量的引用可以绑定 常量/非常量对象、字面值、表达式,只要能够转化成对应的类型即可。

【2】有没有 int &const r = i

指针有两种行为的 const ,引用有没有呢?

首先,我们明确一些概念。

  1. const int i = 0; const int &r1 = i;,像这样,我们把引用绑定到 const 对象上,这叫对常量的引用。当然我们也能绑定到非常量对象上,这个暂时不考虑。
  2. const int i = 0; int &const r2 = i;,这种情况的 const 限定的是我们不能更改 r2 的绑定对象。

我们学习引用时就知道,不允许改变引用所绑定的对象。这其实就说明:引用本身就是 const 的。所以 int &const r2 = i; 这条语句本质上就是 int &r2 = i; ,是冗余的,所以C++没有这种语法。

References and const
Quora
C++中的引用与const

你可能感兴趣的:(C++,Primer(5th),Notes)