类型限定符
const限定符
const变量:定义一种变量,值不能被改变,试图修改会报错
形式: const int i = 10;
基本类型和const
-
基本类型的非
const和const变相都能相互转化和赋值,和const无关int i = 42; const int ci = i; //正确 int j = ci; //正确 bool bi = i; //正确,bi是true -
默认情况下,
const对象仅在文件内有效若想跨文件访问,可以声明为
extern
引用和const
-
被
const修饰的引用常量,不能通过引用修改它绑定的对象const int ci = 42; const int &r1 = ci; //正确,引用和其绑定对象都是常量 r1 = 42; //错误,r1是对常量的引用 -
const的引用常量不能给非const变量赋值假设可以,那么久可以通过非
const变量改变const引用的对象的值了,是不正确的int &r2 = ci; //错误 -
非
const变量可以给const引用常量赋值int i = 42; int &r1 = i; //正确虽然不能通过r1改变i的值,但是i自己还是可以改变的,i改变后,r1也就跟着变化了
int i = 10; const int &ri = i; i = 20; > > 输出:i是20 , ri也是20
指针和const
-
和引用一样,指针也可以指向常量或者非常量
- 可以用
const常量给const指针赋值 - 也可以用非
const变量给const指针赋值 - 不可用
const常量给非const指针赋值 const指针指向一个非const变量后,非const变量自身也是可以修改的
- 可以用
-
与引用不同的是,指针是对象,引用不是
所以存在指针本身是常量,称为常量指针,常量指针必须初始化,初始化后,就不能再改变
-
const int *p = xx;p是一个指向常量的指针,p可变,*p不可变
-
int * const p = xx;p是一个常量指针,p不可变,*p可变
-
const int * const p = xx;p是一个指向常量的常量指针,p不可变,*p也不可变
-
理解
const的含义,也可以从右向左理解 离p最近的有const,那么就是一个常量指针,没有就是指针变量 再往前,最开始有const,那么表示p指向的常量不可变;没有就表示指向的变量可变
-
顶层const和底层const
-
顶层
const:const修饰的变量不可变int i = 0; int *const p1 = &1; //顶层const,p1不可变 const int ci = 42; //顶层const,ci不可变顶层
const在数据拷贝时不受影响const int *const p3 = p2; i = ci; //ci是顶层const,无影响 p2 = p3; //p3顶层const部分不受影响 -
底层
const:const修饰的指针变量指向的数据不可变const int *p2 = &ci; //底层const,p2指向的变量不可变 const int &i = ci; //底层const,引用不可变底层
const的限制不能被忽视。指向拷贝时,拷入和拷出的对象必须具有相同的底层const资格。一般的,非常量可以转换成常量,反之不行
int *p = p3; //错误,p3包含底层const,p不包含 p2 = p3; //p2和p3都包含底层const
constexpr和常量表达式
-
常量表达式是指值不会改变并且在编译过程就能得到计算结果的表达式
字面值属于常量表达式,用常量表达式初始化的
const对象也是常量表达式const int max_files - 20; //max_files是常量表达式 const int limit = max_files + 1; //limit是常量表达式 const int sz = get_size(); //sz不是常量表达式,因为具体值直到运行时才能获取到 -
使用
constexpr申明变量,以便编译器来验证变量是否是一个常量表达式声明为
constexpr的变量一定是一个常量,而且必须用常量表达式初始化constexpr int mf = 20; //20是常量表达式 constexpr int limit = mf +1; //mf+1是常量表达式 constexpr int sz = size(); //只有size是一个constexptr函数时才正确
字面值类型
-
算数类型、引用和指针都属于字面值类型
-
自定义的类都不属于字面值类型,不能定义成
constexpr -
尽管指针和引用都能定义成
constexpr,但初始值却受到严格限制一个
constexpr指针的初始值必须是nullptr或者0,或者是存储于某个固定地址中的对象 -
函数体内定义的变量一般来说并非存放在固定地址中,因此
constexpr指针不能指向这样的变量定义于所有函数体之外的对象其地址固定不变,能用来初始化
constexpr指针
指针和constexpr
-
在
constexpr声明中如果定义了一个指针,限定符constexpr仅对指针有效,与指针所指的对象无关:const int *p = nullptr; // p是一个指向整型常量的指针 constexpr int *q = nullptr; //q是一个指向整型的常量指针 -
与其他常量指针类似,
constexpr指针既可以指向常量也可以指向一个非常量int j = 0; constexpr int i = 42; constexpr const int *p = &i; //指向常量,p是一个常量指针 constexpr int *P1 = &j; //指向非常量,p1也是常量指针
处理类型
类型别名
-
形式
-
传统的使用
typedeftypedef double wages; //给double定义wages的别名 wages *p = nullptr; //使用别名定义指针数据 -
新方式,使用别名声明
using用关键字
using作为别名声明的开始,其后紧跟别名和等号,其作用是把等号左侧的名字规定成等号右侧类型的别名using SI = double; // SI是double的同义词
-
-
指针、常量和类型别名
-
类型别名使用在指针上,正好也加上了
const限定,那么现在这个const指向的是什么?typedef char *pstring; //pstring实际是char *的别名 const pstring cstr = 0; //cstr是指向char的常量指针,即cstr不可变 const pstring *ps; // ps是指向 char的常量指针 的指针pstring实际是char *的别名,而const是对给定类型的修饰。即const pstring就指向char的常量指针,而非指向char常量的指针也就说
pstring是指针类型,那么const pstring中的const就是修饰指针的,也就是常量指针 -
不能使用原始类型替换掉别名理解含义
如 const char * cstr = 0;这是错误的
pstring是指针类型。可是用char*重写了声明语句后,数据类型就变成了char,*成为了声明符的一部分。这样改写的结果是,const char成了基本数据类型。 前后两种声明含义截然不同,前者声明了一个指向char的常量指针,改写后的形式则声明了一个指向const char的指针
-
auto类型
自动类型,让编译器去分析表达式所属的类型
-
auto是让编译器通过初始值来推算变量类型,所以,auto定义的变量必须有初始值auto i = 0; //auto是int -
引用作为
auto变量的初始值时,此时变量的类型就是引用对象的类型int i = 0 ; &r = i; auto a = r; //a是int类型 -
在同一行定义多个变量时
符号
&和*只从属于某个声明符,而非基本数据类型的一部分,所以auto想要修饰引用或者指针也必须加上&或者*auto i = 0, &ri = i, *p = &i; //i是int 类型 //ri就是i的引用 //p指向int类型i的数据 -
const和auto-
auto会忽略顶层const如果需要顶层
const,则需要明确加上顶层constint i =0; const int ci = i; &cr = ci; auto b = ci; //b是一个int数据,顶层const被忽略 const auto b2 = ci; //b2是一个int常量,明确机上顶层const -
auto会保留底层constauto c = &ci; //c是指向整型常量的指针 , 对常来那个取地址,是一种底层const
-
decltype类型指示符
decltype,它的作用是选择并返回操作数的数据类型 在此过程中,编译器分析表达式并得到它的类型,却不实际计算表达式的值
-
形式
decltype( f() ) sum = x; //sum的类型是函数f的返回值类型 -
与
auto的区别decltype使用的表达式是一个变量,则类型就是该变量的类型,也会保留顶层constdecltype的结果类型与表达式形式密切相关
-
总结
-
decltype( (variable) )永远是引用,注意,是两个括号int i = 0; decltype((i)) d = i; //d是int&,必须初始化 -
decltype(引用)是引用decltype(&i) d = i; //d是int&类型 -
decltype(*p)是引用int p = &i; decltype(p) d = i; //d是int &类型 -
decltype(引用作为表达式的一部分)是引用的变量的数据类型decltype( i+0 ) d ; //d是int类型 -
decltype(基本类型)是数据类型decltype(i) d ; //d是int类型
-