数据类型决定了程序中数据和操作的意义。

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 变量定义

    基本形式:类型说明符+一个或多个变量名组成的列表(变量名以逗号分隔)+分号

    初始值

    当对象在创建时获得了一个特定的值,称为被初始化了。 初始化和复制是两个完全不同的操作,注意这个概念很重要
    初始化:在创建变量是赋予其一个初始值。
    复制:把对象的当前值擦除,以一个新的值代替。

    列表初始化

    无论是初始化对象还是某些时候为对象赋新值,都可以使用一组又花括号括起来的初始值。
    1
    2
    3
    4
    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 类型别名

    类型别名是一个名字,是某种类型的同义词。使用方式:
    1
    2
    3
    4
    5
    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本身是一个引用时才是引用。另外,赋值是会产生引用的一类典型表达式,引用的类型就是左值的类型

2.6 自定义数据结构

定义自己的数据结构

定义自己的头文件

预处理器