理清 C++ 中顶层 const 和底层 const 的概念,感觉理解起来有些混乱。

具体讲解看的是《C++ Primer》。

核心概念

顶层 const (top-level const):对象本身是常量
底层 const (low-level const):指针/引用指向的对象是常量

具体例子

1. 顶层 const 的例子

1
2
3
int a = 10;
const int b = 20; // b 是顶层 const(b 本身是常量)
int *const p1 = &a; // p1 是顶层 const(指针本身是常量)

特点:

  • 对象本身的值不能改变
  • 对于指针:指针的指向不能改变,但指向的内容可以改变
1
2
3
4
int a = 10, b = 20;
int *const p = &a; // 顶层 const
// p = &b; // 错误!指针指向不能改变
*p = 30; // 正确!指向的内容可以改变

2. 底层 const 的例子

1
2
3
4
int a = 10;
const int *p1 = &a; // p1 是底层 const
int const *p2 = &a; // p2 也是底层 const(两种写法等价)
const int &r = a; // r 是底层 const

特点:

  • 指针/引用指向的对象是常量
  • 指针的指向可以改变,但不能通过指针修改指向的对象
1
2
3
4
int a = 10, b = 20;
const int *p = &a; // 底层 const
p = &b; // 正确!指针指向可以改变
// *p = 30; // 错误!不能通过指针修改指向的对象

3. 同时包含的情况

1
2
const int *const p = &a;     // 左边是底层 const,右边是顶层 const
// 读作:p 是一个常量指针,指向一个常量整数

记忆技巧

方法1:看 const 的位置

1
2
3
int *const p;           // const 在 * 右边 → 顶层 const
const int *p; // const 在 * 左边 → 底层 const
int const *p; // const 在 * 左边 → 底层 const

方法2:从右向左读

1
2
int *const p;           // 从右往左:p 是 const 指针,指向 int
const int *p; // 从右往左:p 是指针,指向 const int

实际应用中的区别

1. 拷贝操作的限制

1
2
3
4
5
6
7
8
9
int a = 10;
const int b = 20;

// 顶层 const 不影响拷贝
int c = b; // 正确:可以忽略顶层 const

const int *p1 = &a; // 底层 const
int *p2 = p1; // 错误!不能忽略底层 const
const int *p3 = p1; // 正确:底层 const 可以保留

2. 函数重载

1
2
3
4
5
void func(int *p);          // #1
void func(const int *p); // #2 重载,底层 const 不同

void func(int p); // #3
void func(const int p); // #4 错误!顶层 const 不能重载

这里需要用函数值传递仔细说明一下:

const不会改变参数的类型,因此不能作为函数重载的依据。会忽略掉顶层const

函数进行传参时,传的都是值的副本,对副本是否加const,不会改变参数类型。

1
2
void fun1(int x);
void fun1(const int x);//报错

Redundant ‘fun1’ declaration [readability-redundant-declaration]
E:\UnrealWorld\project\Learncpp\Learncpp\main.cpp:5:6: note: previously declared here

3. 引用的情况

引用天生就是”顶层 const”(因为引用一旦绑定就不能改变),所以我们只关心底层 const:

1
2
3
int a = 10;
int &r1 = a; // 普通引用
const int &r2 = a; // 底层 const 引用

总结

类型 示例 const 类型 什么不能改变
常量整数 const int a 顶层 const a 的值
常量指针 int *const p 顶层 const p 的指向
指向常量的指针 const int *p 底层 const 通过 p 修改指向的对象
常量引用 const int &r 底层 const 通过 r 修改绑定的对象

核心区别:

  • 顶层 const:我本身是常量
  • 底层 const:我指向/引用的对象是常量