正文之前
看了一天《C++ Primer 第五版》,好爽啊!不过收获不是很大,而且还有不少的地方不太懂,但是还是把我的收获分享出来!希望大家喜欢吼~~
正文
1、 顶层const
- 众所周知,指针本身就是一个对象,不依附于别的对象而存在着,也就意味着指针定义的时候不需要初始化。所以对于指针这个东西来说。其本身与其所指向的对象是不是常量本身就是独立的事情。那么我们用顶层const来表示指针本身就是一个常量,也就是常指针,用底层const来表示指针所指向的对象是常量,那么我们可以知道:
const int i=21;
const int *const p= &i
代表着p是一个指向常量的常指针,也就是说其本身就兼具了顶层const和底层const的特性。
- 注意注意!!必须在* 跟p之间加一个const,才是表示的常指针,否则两个const就是重复定义:
修改之后就是完整的指向常量的常指针:
- 如果只有一个const:
const int i=21;
const int *p= &i
那么其实这个意思是,p是一个指针,指向一个const常量,没错,const只用来表示&i中的i是一个常量,而不管你p这个指针的效果。
- 所以两个const 定义的话是分别给p加持了顶层和底层的const特性,如果只有一个const ,那么上面的代码是底层const ,也就是说是指向常量,本身不是常指针。下面是常指针,顶层const的特性:
const int i=21;
int *const p= &i;
- 另外,注意!!拷贝操作,必须是拷贝方与被拷贝方有着相同的底层const特性(顶层特性不考虑),否则是会报错的,如下:
const int i=21;
const int *p1=&i;
const int *p2=p1; //正确,因为p2已经在const那儿申明了我是指向一个常量的,所以因为p1具备底层const 可以被p2拷贝
int *p3=p1; //所以这毫无疑问是错误的,因为你p3啥const特性都不具备,咋去拷贝一个具有底层const特性的指针?
别问我为啥,C++11就这么规定的!要从计算机组成说我还没学那么深!另外其实每一个直接定义常量的都是天生具备顶层const特性,比如const int i=21;
2、 constexpr和常量表达式
- 常量表达式两大特性:
- 本身值不会改变,const type
- 能够在编译过程中得到计算结果,而不需要等别的输入
就好比下面:
const int max=1;
const int min=size();
第一行的max就是常量表达式,而第二行的min就不是,因为size()必须在运行之后才知道结果。
constexpr变量,这个跟const很像。constexpr是新标准中允许变量声明为constexpr以便由编译器验证变量是不是常量表达式而产生的!具体的作用后面说,我也还没摸清楚
至于constexpr的另一个特性,那就是如果用它定义一个指针,那么它只针对指针,而对指针指向的对象毫不关心(官方术语是:constexpr把其定义的对象置为顶层const)。下面是区别所在:
const int *p=&i; //定义了一个指向整形常量的非常量指针;
constexpr int *p=&i; //定义了一个指向整数的常量指针!!
- 如果要定义指向常量的常量指针,那么就需要下面这一句:
constexpr const int *p=&i
3、 类型别名
类型别名有两种方法:
- 传统的方式是:
typedef
typedef double wages;
此时的话,见wages如见double。你可以用wages做任何double能做的事情:
wages file=12.1;
typedef wages *base;
上面两句中,第一句定义了一个双精度的变量file并且初始化了。第二句则是给wages *(相当于是double * )
再次定义了一个别名,那就是base ,所以以后base就代表了“double类型的指针变量”这一个固定标签。但是有一个巨坑,那就是要跟宏定义区分开来!!!这个是超级重要的!下面见例子:
typedef double *base;
const base cs=&hi;
const double *cs1=&hi;
如果一不小心,我们会以为cs是一个指向常量hi的指针,指针对象本身是一个非常量,跟第三行cs1是一样的。但是事实是:cs是一个指向double的常量指针,base据定了它是一个指向double的指针,然后const再限定了cs是一个常量,这是针对指针本身的,其效果等同于
double *const cs=&hi; // === const base cs=&hi;
- 另外一种别名方式是:
using
using base =double;
上述两种方式效果等同。
4、 auto类型说明符
- auto的作用是让编译器代替我们去分析表达式所述的类型。但是请注意,auto一次只能分析一种类型,无法分析多种,也就是说,如下:
auto i=0,*p=&i;
auto sz=0,pi=3.14;
第一句是对的,可以分析出来,auto在第一句中等效int,而第二句中,sz是int类型,pi是浮点数,很显然是无法同时自动判定两种类型的, 所以报错了!!
- auto的一些特性
1)auto在引用中忽略”引用“这一类型,而是直接返回引用绑定的对象类型
int i=0,&r=i;
auto a=r; //(这里的auto会返回一个int 类型 而不是int &这个引用的类型)
2)auto会忽略顶层的const ,但是会保留底层const,比如说:
const int ci=i;
auto b=ci;
auto c=&ci
*c=i;
3)看得出来,b是自动忽略了ci的顶层const特性,而不会忽略底层特性,所以第四行会报错,如下图:
4)如果希望auto类型被推断出一个顶层const特性,那么如下即可:
const auto f=ci;
5)设置一个引用的时候,会保留顶层常量的属性,因此初始值必须是相同的类型的,下面一对一错:
auto &m=ci,*p=&ci; //都是对整形常量的引用
auto &n=i,*p2=&ci; // 这就错了。n是对非常量i的引用,是int ,而p2对ci的引用时const int 所以不行
5、 decltype 类型提示符
这个类型提示符类似于一个类型的提取,可以返回括号内的表达式的返回类型。比如说:
- decltype(F()) 那么它整体就代表着F()函数的返回类型,如果是int 那么可以这么用:
decltype(F()) a=10; //a是整形变量;
- 另外
decltype()
对于引用和const
都会全盘返回,比如说:
const int i=10,&m=i;
decltype(m) x=i
第二句就相当于是 const int & x=i;
也就是说const
与&
这两个操作都被返回
下面是我总结的集中
decltype()
返回引用类型的情况
- 指针解引用 ,如 :
int i=10;
int *p=i;
decltype(*p) x=i
第三句等效于 int &x=i
;返回的是引用int &
而不是int
本身就是一个引用,上面说过了;
如果
decltype((X))
,也就是说括号内还有一个括号把变量包含在内,那么就是返回的这个变量加上& ,比如如果X是int变量,那么前面返回 int &赋值语句会返回引用
decltype(a=b)
返回的就是a的类型的引用, 比如如果a是int
变量,那么前面返回int &
正文之后
今天之所以现在就出来了。是因为晚上基本没怎么看书,去写简书去了。所以晚上我就没怎么看书,现在十点半已经快写完了,每天写写简书,捞捞粉丝,赚点人气,爽歪歪~ ~ 待会再看会《金粉世家》和《计算机学科导论》,这样的日子才是我大头张应该过的吗~ ~