# 1.4、类型修饰符
C++ 允许在数据类型前放置修饰符,修饰符用于改变变量的特性。
* signed、unsigned、long、short:改变算术类型变量可保存值的范围;
* const:对象在程序执行期间不能被修改;
* volatile:告诉编译器不需要优化volatile声明的变量,让程序可以直接从内存中读取变量;
* restrict:由 restrict 修饰的指针是唯一一种访问它所指向的对象的方式。只有 C99 增加了新的类型限定符 restrict。
## const 修饰符
**const** ([cppreference-const](https://en.cppreference.com/w/cpp/keyword/const))可以指定一个语义约束,指定一个不该被改动的对象,而编译器会强制实施这项约束。const 常用于修饰变量、指针、变量引用、成员函数等,可以起到一定的约束作用。对于一个类的 const 对象、指针、引用,只能调用类的 const 成员函数。
**修饰变量**:const 修饰变量一般有两种,两种写法没有区别,都是表示变量的值不可变:
```
const TYPE value;
TYPE const value;
```
**修饰指针**:用 const 关键字修饰一个指针的话,不同的写法会有不同情况,如果关键字 const 出现在星号左边,表示被指物是常量,此时指针的值可以修改,但是不可以通过指针取修改被指变量的值;如果出现在星号右边,表示指针自身是常量,此时指针的值是不能更改的,但是可以通过指针修改被指变量的值;如果出现在星号两边,表示被指物和指针都是常量,都是不能被修改的。
```
char greeting[] = "Hello";
char* p = greeting; // non-const pointer, non-const data;
const char* p = greeting; // non-const pointer, const data;
char* const p = greeting; // const pointer, non-const data;
const char* const p = greeting; // const pointer, const data;
```
可以简单理解成 const 修饰的为关键字右边的东西,例如:
* `const char** p`:指向一个 pointer 的指针 p,pointer 是一个指向 const data 的指针,我们可以通过指针 p 修改 pointer 的值,也可以修改指针 p 的值,但是不能通过 p 或 pointer 修改 pointer 指向的对象;
* `const char* const * p`:指向一个 const pointer 的指针 p,pointer 是一个指向 const data 的指针,我们不可以通过 p 修改 const pointer 的值和 const pointer 指向的对象的值,但是可以修改指针 p 的值;
* `const char* const * const p`:指向一个 const pointer 的指针 p,pointer 是一个指向 const data 的指针,不可以通过指针 p 修改 const pointer 的值和 const pointer 指向的对象的值,也不可以修改指针 p 的值;
**修饰成员函数**:
* `const T func()`表示返回的为 const 类型;
* `T func() const`表示函数不能修改其成员变量;
我们知道,成员函数的第一参数为默认的`this`指针,如果在成员函数后加 const 关键字,则传入的`this`指针是一个 const 指针。成员函数如果是 const 意味着什么?这里有流行的概念:bitwise constness(又称 physical constness)和 logical constness。
**bitwise constness**认为,成员函数只有在不更改对象中任何成员变量时,才可以说是 const。不过很多成员函数虽然不具备 const 性质,但是却能通过 bitwise 测试,例如:
```
class CTextBlock {
public:
char& operator[](std::size_t position) const {
return pText[position];
}
private:
char* pText;
};
```
**logical constness**主张一个 const 成员函数可以修改它所处理的对象内的某些 bits,但只有在客户端侦测不出的情况下才可以。但有时候符合 logical constness 的 const 成员函数并不能通过编译器,这时需要用 mutable(可变性)释放掉 non-static 成员变量的 bitwise constness 约束。
```
class CTextBlock {
private:
mutable std::size_t textLength;
};
```
**修饰引用**:真实程序中 const 对象大多用于函数的 passed by pointer-to-const 或者 passed by reference-to-const 传递结果,可以减少值拷贝。
```
void function(const int&, const int&);
```
**top-level const**:如果 const 影响的是对象本身,则为 top-level const。
> A top-level const qualifier affects the object itself. Others are only relevant with pointers and references.
### constexpr
**constexpr**:常量表达式是指在编译期间就可以确定值的表达式,我们可以通过 constexpr 告诉编译器这时一个常量表达式。
> A **constant expression** is an expression whose value cannot change and that can be evaluated at compile time.
```
constexpr int fm = 10;
constexpr int limit = fm + 1;
```
## volatile 修饰符
**volatile**([cppreference-volatile](https://en.cppreference.com/w/cpp/keyword/volatile)) 表明变量可能会通过某种方式发生改变,所以它会告诉编译器不要去优化该变量的相关操作。我们来做个简单的实验,下面有两段代码:
```
// a.cpp
int main () {
int a;
a = 5;
a = 7;
printf("%d\n", a);
return 0;
}
// b.cpp
int main () {
volatile int a;
a = 5;
a = 7;
printf("%d\n", a);
return 0;
}
```
默认情况下,编译器的优化等级是固定,所以我们在编译的时候加上`-O3`参数,对比两个源文件的汇编产物可以发现,没有 volatile 修饰的话,`a=5`这行代码会被优化。
```
g++ -O3 -S a.cpp -o a.s
g++ -O3 -S b.cpp -o b.s
```
## restrict 修饰符
**restrict**是c99标准引入的,它只可以用于限定和约束指针,并表明指针是访问一个数据对象的唯一且初始的方式。即它告诉编译器,所有修改该指针所指向内存中内容的操作都必须通过该指针来修改,而不能通过其它途径(其它变量或指针)来修改。
- 目录
- 基础知识
- 1、变量和基础类型
- 1.1、内置类型
- 1.2、变量
- 1.3、复合类型
- 1.4、类型修饰符
- 1.5、类型处理
- 1.6、自定义结构
- 1.7、数组
- 2、表达式和语句
- 2.1、运算符
- 2.2、语句
- 3、函数
- 1、语法相关
- 2、资源管理
- 3、面向对象
- 4、模板与泛型编程
- Problem01:判断类中是否包含函数
- Problem02:解析函数的参数类型
- 5、系统库
- Problem01:多线程维护最大值
- Problem02:介绍一下strcpy、strncpy、memcpy、memmove
- Problem03:介绍一下网络编程
- Problem04:select、poll、epoll的区别
- 未整理
- Problem11:实现在main函数前、后执行的函数
- Problem12:可变参函数的实现
- Problem13:全局变量初始化顺序问题
- Problem14:介绍一下隐式转换
- Problem07:实现一个不能被拷贝的类
- Problem08:实现一个只能通过动态、静态分配的类
- 开源项目
- redis
- 第一部分 数据结构与对象
- redis 底层数据结构
- redis 对象
- taskflow
- 数据结构
- Executor
