NIUCLOUD是一款SaaS管理后台框架多应用插件+云编译。上千名开发者、服务商正在积极拥抱开发者生态。欢迎开发者们免费入驻。一起助力发展! 广告
# 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标准引入的,它只可以用于限定和约束指针,并表明指针是访问一个数据对象的唯一且初始的方式。即它告诉编译器,所有修改该指针所指向内存中内容的操作都必须通过该指针来修改,而不能通过其它途径(其它变量或指针)来修改。