数据类型决定了程序中数据和操作的意义。
2.1 基本内置类型
基本数据类型:** 算数类型 空类型(void) **,其中算数类型包括:字符、正整数、布尔值、浮点数。空类型不对应具体的值,用于一些特殊的场合。
2.1.1 算数类型
分为整形和浮点型。
整形:
- bool:取值为true或者false。
- char:基本的字符类型,一个char的大小与一个机器字节一样。
- wchar_t,char16_t,char32_t
** rules: **一个int至少和一个short一样大,一个long至少跟一个int一样大,一个long long至少跟一个long一样大。
浮点型:
- float:一般一个字,32bit
- double:2个字,64bit
- long double:3或4个字,96或128bit
带符号类型和无符号类型
2.1.2 类型转换
转换过程:
- 非bool到bool:初始为0则为false,其他为true
- bool到非bool:初始值为false则为0,初始值为true为1
- 浮点数到整型:仅保留浮点数中的** 小数点部分 **
- 整数到浮点数:小数部分记为0,如果整数所占的空间超过浮点类型的容量,会报错。
- 赋给无符号类型,当超出它表示范围的时候,转换为该无符号类型表示数值总数取模后的余数。
- 给带符号的数输出超过范围的值是,结果时** 未定义的 **
tips:一般不在算数表达式中使用bool值
含有无符号类型的表达式
一般不要混用无符号和有符号的类型,当无符号超过范围时,可能会出现取模的情况,放在循环中,或者计算结果中,会产生无法预计的结果
2.1.3 字面值常量
顾名思义,字面值常量一望而知。每个字面值常量对应一种数据类型,字面量常量得形式和值决定了它的数据类型。
整型和浮点型字面值
严格来说,十进制字面值不会是负数,通常,负号并不在字面值内,它的作用仅仅是对字面值取负值而已。
字符和字符串字面值
- char型字面值:由单引号括起来的一个字符
- 字符串字面值:由双引号括起来的零个或多个字符
** Note:字符串字面值的类型实际上是由常量字符组成的数组,编译器在每个字符串的结尾处添加一个空字符('\0'),字符串的字面值的实际长度比它的内容多1。 **
转义序列
有两类不能直接使用的字符。不可打印的和特殊含义的字符(单引号,双引号,问号,反斜线),这些情况下需要使用转义字符。
指定字面值类型
添加一定的前缀和后缀,可以改变整型、浮点型和字符型字面值的默认类型。前缀有:u(Unicode16)、U(Unicode32)、L(宽字符)、u8(UTF-8)。后缀有:u或者U(unsigned)、l或者L(ling)、ll或者LL(long long),f或者F(float)、l或者L(long double)。
布尔字面值和指针字面值
bool:true、false
指针:nullptr
2.2 变量
对于c++来说,一般“变量”和“对象”可以互换使用。对象时具有某种数据类型的内存空间。
2.2.1 变量定义
基本形式:类型说明符+一个或多个变量名组成的列表(变量名以逗号分隔)+分号
初始值
当对象在创建时获得了一个特定的值,称为被初始化了。** 初始化和复制是两个完全不同的操作,注意这个概念很重要 **
初始化:在创建变量是赋予其一个初始值。
复制:把对象的当前值擦除,以一个新的值代替。
列表初始化
无论是初始化对象还是某些时候为对象赋新值,都可以使用一组又花括号括起来的初始值。
int units_sold=0;
int units_sold={0};
int units_sold{0};
int units_sold(0);
默认初始化
定义于函数体内的内置类型的对象如果没有初始化,则其值未定义。类的对象如果没有显式的初始化,则其值由类确定。。建议初始化每一个内置类型的变量。
2.2.2 变量声明与定义的关系
声明使得名字为程序所知,定义负责创建与名字关联的实体。
** extern **关键字:如果想声明一个变量而不是定义它,就在变量名前添加extern,而不显示的初始化变量。如果在函数体内部试图初始化一个有extern关键字标记的变量,会引发错误。
2.2.3 标识符
用户自定义的标识符中不能出现两个连续的下划线,也不能以下划线紧连大写字母开头。定义在函数体内的标识符不能以下划线开头。
变量命名规范
- 标识符要能体现实际含义
- 变量名一般小写字母
- 自定义的类名一般大写字母开头
- 标识符由多个单词组成时,单词应有明显区分,使用下划线
2.2.4 名字的作用域
当内层出现与外层相同的名字时,使用内层定义的名字。
2.3 复合类型
复合类型指的是基于其他类型定义的类型。这里介绍两种:引用和指针。
2.3.1 引用
引用为对象起了另外一个名字,引用;类型引用另外一种类型。通过将生命符写成&d的形式来定义引用类型,其中d是声明的变量名。引用必须初始化。
引用即别名
引用并不是对象,只是一个已经存在的对象起的另外一个名字。定义了一个引用之后,对其做的所有操作都是在与之绑定的对象上进行的。
因为引用本身只是一个别名,不是一个对象,所以不能定义引用的引用。
引用的定义
除了两种例外的情况,其他所有的引用类型都要与之绑定的对象严格比配。
引用只能绑定到对象上,不能绑定到字面值或者某个表达式的计算结果上。
2.3.2 指针
指针是“指向point to”的另外一种类型的复合引用。指针也实现了对其他对象的间接访问。
两者的不同点:
- 1.指针本身就是一个对象,允许对指针赋值和拷贝,而且指针的生命周期内可以指向多个不同的对象。
- 2.指针无需在定义时赋初值。
获取对象的地址
指针存放某个对象的地址,要想获取该地址,需要使用取地址符(操作符&)
不能定义指向引用的指针(因为引用不是一个对象)。
除了两种例外的情况,所有指针的类型都要和它指向的对象严格匹配。
指针值
指针的值(即地址)应该属于下面四种状态之一:
- 1.指向一个对象
- 2.指向紧邻对象所占空间的下一个位置
- 3.空指针,表示没有指向任何对象。
- 4.无效指针,上述之外的其他值。
利用指针访问对象
如果指针指向了一个对象,允许使用解引用符(操作符*)来访问对象。
空指针
空指针不指向任何对象,得到空指针的办法:直接用字面值nullptr初始化指针或者将指针初始化为字面值0来生成空指针。
** 建议 **:初始化所有指针
赋值和指针
记住赋值永远改变的是等号左侧的对象。
其他指针操作
只要一个指针拥有合法值,就能将它用在条件表达式中,只要不为空,条件都为true。
void* 指针
void* 是一种特殊的指针类型,可用于存放任意对象的地址。
2.3.3 理解复合类型的声明
变量的定义包括:一个基本数据类型+一组声明符。基本数据类型只有一个,但是声明符的形式可以不同。
指向指针的指针
当有多个修饰符连写在一起的时候,按照逻辑关系解释。
指向指针的引用
引用本身不是对象,但是指针是对象,所以可以对指针引用。
面对一条复杂的指针或引用的声明语句时,从右向左阅读有助于弄清真实含义。
2.4 const限定符
初始化和const
const与非const对象的区别就是,const类型的对象执行不改变起内容的操作。如:const int也能像int一样参与算术运算,也能转化为bool值。
默认状态下,const对象仅在文件内有效
如果想在多个文件之间共享const对象,必须在变量定义之前添加extern关键字。
2.4.1 const的引用
可以把引用绑定到const对象上,就像绑定到其他对象上一样,称为对常量引用,对常量的引用不能修改它所绑定的对象。
** 术语:常量引用是对const的引用 **:并不存在常量引用,是对const的引用。
初始化和对const的引用
引用情况的例外:第一种是,在初始化常量引用时,允许用任意表达式作为初始值,只要该表达式的结果能转换成引用的类型即可。尤其允许为一个常量引用绑定非常量的对象、字面值,甚至是个一般表达式。
对const的引用可能引用一个非const的对象
此种行为是合法的,但是不能通过对const的引用改变对象的值,兑现可以通过其他的方式改变值。
2.4.2 指针和const
指向常量的指针不能改变其所指对象的值,要想存放常量对象的地址,只能只用指向常量的指针。
所谓指向常量的指针和引用,只是自以为指向了一个常量,所以自觉不去改变所指对象的值。
const指针
*const:不变的是指针的值而不是指向的那个值。采用从右向左的方式阅读,看离最近的符号。
顶层const
顶层const表示指针本身是个常量,底层const表示指针指的对象是一个常量。
当对象执行拷贝操作时,顶层const不受影响,拷入和拷出的对象必须具有相同的底层const资格,或者两个对象的数据类型必须能够转化。
2.4.4 constexpr和常量表达式
常量表达式指:值不会改变且在编译过程就能得到计算结果的表达式。(字面值、用常量表达式初始化的const对象)
constexpr变量
声明为constexpr的变量一定是一个变量,且必须用常量表达式初始化。
字面值类型
指针和constexpr
在constexpr如果定义了一个指针,则constexpr只对指针有效,与指针所指的对象无关。
2.5 处理类型
2.5.1 类型别名
类型别名是一个名字,是某种类型的同义词。使用方式:
typedef double wages //wages 是double的别名
typedef wages base,*p
#别名声明
using SI=Scales_item;
指针、常量和类型别名
2.5.2 auto类型说明符
复合类型、常量和auto
- 引用时的auto,以引用对象的类型作为auto的类型
- auto一般会忽略掉顶层const,底层const会保留下来。
- 可以将引用的类型设为auto
2.5.3 decltype类型指示符
选择并返回操作数的类型,编译器分析表达式并得到类型,但并不实际计算值
decltype和引用
有些表达式将向decltype返回一个引用类型。如果表达式的内容是解引用操作,则decltype将得到引用类型。
解引用指针可以得到指针所指的对象,而且还能给这个对象赋值。
decltype和auto的重要区别:decltype的结果类型与表达式形式密切相关。
** 如果给变量加上一层或多层括号,decltype就会得到引用类型。decltype((val))的结果永远是引用,decltype(val)只有当val本身是一个引用时才是引用。另外,赋值是会产生引用的一类典型表达式,引用的类型就是左值的类型 **