刚上大学那时,几个室友一块买了本《C++ Primer》第4版,看了一遍后就没怎么碰了,偶尔拿出来翻翻,当作工具书使用。后来知道有第5版了,一直觉得内容差不多吧。直到最近,再读其中的一些内容,结合自己曾经所学所用,很多地方都想得更深了。结合C++11,也有很多新的发现。人就是在不断否定过去的自己中成熟的。
以下是书的第2章,变量和基本类型,的一些笔记。
一、基本内置类型
基本数据类型包括算数类型(arithmetic type)和空类型(void)。
书中列出了每种类型的最小存储空间,在不同机器上这些类型的存储空间可能会不同,在程序中怎么获得实际的大小呢?
C++中有个关键字 sizeof ,可以获得一个类型对应对象的大小(以字节byte为单位)。具体细节参考sizeof。
1.算术类型
算术类型分为整型和浮点型。
表示整数、字符和布尔值的算数类型称为整型(integral type)。
char类型通常是单个机器字节,wchar_t用于扩展字符集,比如汉字和日语。
通常,short为半个机器字长,int为一个机器字长,long为一个或两个机器字长(跟操作系统有关)。
2.类型转换
注意有符号数转换为无符号数时可能会出现的问题。
比如:
for (unsigned i = 10; i >= 0; --i) std::cout << i << std::endl;
上面的程序中,i永远也不会小于0,循环条件一直成立。
分析:当i减小到0时,经过一次循环,i再减一,值为-1,-1不满足无符号数的要求,将被自动转换成一个合法的无符号数。
计算机中有符号数是用补码表示的,如果int类型占32位,那么-1的补码是32个1(负数符号位是1,其余各位取反,再在末位加1),转换成无符号数也就是232-1,所以当i等于0时,--i的结果将会是4294967295。
二、变量
1.初始化
一种特殊的初始化方式:列表初始化。
比如:int units_sold = {0};
如果我们使用列表初始化,并且初始值存在丢失信息的风险,编译器将会报错:
long double ld = 3.14159; int a{ ld };
2.声明和定义
定义(definition):为变量分配存储空间,也可以为变量指定初始值。
声明(declaration):用于向程序表明变量的类型和名字。定义也是声明。
可以使用 extern 关键字声明变量而不定义它。
只有当extern声明位于函数外部时,才可以含有初始化式。
三、复合类型
复合类型主要是引用和指针。
1.引用
引用为对象起了另外一个名字,引用类型引用另外一种类型。定义引用时,程序把引用和它的初始值绑定在一起(不是将初始值复制给引用),无法令引用重新绑定到另外一个对象。
引用不是对象,引用不是对象,引用不是对象,重要的话说三遍!它只是已有对象的别名,所以不能定义引用的引用。而且引用的类型要和与之绑定的对象严格匹配。
2.指针
生成空指针的几个方法:
int *p1 = nullptr; int *p2 = 0; int *p3 = NULL;
nullptr 是C++11新标准引入的,它是一种特殊的字面值。
以前我一直是用NULL来生成空指针,NULL是一个预处理变量,在头文件cstdlib中定义,它的值就是0。
在新标准下,现在最好是用nullptr。
四、const限定符
1.const的引用
允许为一个常量引用绑定非常量的对象、字面值。
int i = 42; const int &r1 = i;
2.指针和const
指向常量的指针:
const double a = 3.14; const double *ptr = &a;
const指针:
int b = 3.14; int *const ptr = &b;
指针本身是一个常量,不代表不能通过指针修改其所指向的对象的值。
3.顶层const
顶层const:指针本身是个常量。
底层const:指针所指的对象是一个常量。
五、处理类型
1.类型别名
方法1:使用typedef关键字
typedef double wages;
方法2:使用别名声明
using SI = Sales_item;
方法2是新标准中的。
2.auto类型说明符
让编译器分析表达式所属的类型,auto定义的变量必须有初始值。
3.decltype
选择并返回操作数的类型。
decltype(f()) sum = x;
sum的类型就是函数f的返回类型。