primer C++:第二章学习

C++是一种静态数据类型语言,它的类型检查发生在编译时。因此,编译器必须知道程序中每一个变量对应的数据类型。

  C++定义了一套包括算术类型(arithmetic type)和空类型(void)在内的基本数据类型。其中算术类型包含了字符、整型数、布尔值和浮点数。空类型不对应具体的值,仅用于一些特殊的场合。


选择类型的准则:

  • 当明确知晓数值不可能为负时,选用无符号类型;

  • 使用int执行整数运算,当超过int的表示范围时选用long long;

  • 在算术表达式中不要使用bool或char,只有存放字符或布尔值时才使用他们;

  • 执行浮点数运算使用double(float和long double一般不使用)。


类型所能表示的值的范围决定了转换的过程:

  • 把一个非布尔类型的算术值赋给布尔类型时,初始值为0则结果为false,否则结果为true;

  • 把一个布尔值赋给非布尔类型时,初始值为false则结果为0,初始值为true则结果为1;

  • 把一个浮点数赋给整型类型时,结果值仅保留浮点数中的小数点之前的部分;

  • 把一个整型数赋给浮点类型时,小数部分记为0。如果该整数所占的空间超过了浮点类型的容量,精度可能损失;

  • 当赋给无符号类型一个超出它表示范围的值时,结果是初始值对无符号类型表示数值总数取模后的余数;

  • 当赋给带符号类型一个超出它表示范围的值时,结果是未定义的。


建议:避免无法预知和依赖于实现环境的行为。


  字符串字面值常量实际上是由常量字符构成的数组。编译器在每个字符串的结尾加上一个‘\0’,因此,字符串字面值常量的实际长度要比它的内容多1。如果两个而字符串字面值位置仅由空格、缩进和换行符分隔,则它们实际上是一个整体。

  有两类字符程序员不能直接使用:一类是不可打印的字符;另一类是C++语言中含有特殊含义的字符。在这种情况下需要用到转义字符,转义字符均以反斜线作为开始。C++的转义序列如下:

换行符  \n  横向制表符 \t  报警符 \a  纵向制表符 \v  退格符 \b  双引号 \" 反斜线 \\  问号 \?  单引号 \'  回车符 \r  进纸符 \f

  我们也可以使用泛化的转义字符,其形式是\x后紧跟一个或多个十六进制数字,或者\后紧跟1个、2个或3个八进制数字,其中数字部分表示的是字符对应的数值。                                   primer C++:第二章学习

  变量提供一个具名的、可供程序操作的存储空间。C++中的每个变量都有其数据类型,数据类型决定着变量所占内存空间的大小和布局方式、该空间能存储的值的范围,以及变量能参与的运算。对于程序员来说,变量(variable)和对象(object)一般可以互换使用。

  变量定义的基本形式:类型说明符后紧跟由一个或多个变量名组成的列表,其中变量名以逗号分隔,最后以分号结束。列表中每个变量名的类型都由类型说明符指定,定义时还可以为一个或多个变量赋初值。


通常情况下,对象是指一块能存储数据并具有某种类型的内存空间。


  当对象在创建时获得了一个特定的值,我们说这个对象被初始化了。


初始化不是赋值,初始化的含义是创建变量时赋予其一个初始值,而赋值的含义是把对象的当前值擦除,而以一个新的值来代替。(建议初始化每一个内置类型的变量)


  如果定义变量时没有指定初值,则变量被默认初始化,此时变量被赋予了“默认值”。默认值到底是什么由变量类型决定,同时定义变量的位置也会对此有影响。

  如果内置类型的变量未被显式初始化,它的值由定义的位置决定。定义在任何函数之外的变量被初始化为0,而定义在函数体内部的内置类型变量将不被初始化。一个未被初始化的内置类型变量的值是未定义的,如果试图拷贝或以其他形式访问此类值将引发错误。

  声明使得名字为程序所知,一个文件如果想使用别处定义的名字则必须包含对那个名字的声明。而定义负责创建与名字关联的实体。

  如果想要声明一个变量而非定义它,就在变量名之前加上extern关键字,而不要显式地初始化变量。任何包含了显式初始化的声明即成为定义。为extern标记的变量赋值会抵消extern的作用。

primer C++:第二章学习    primer C++:第二章学习


变量只能被定义一次,但是能被声明多次。  


  如果要在多个文件中使用同一个变量,就必须将声明和定义分离,此时,变量的定义必须出现在且只能出现在一个文件中,而其他用到该变量的文件必须对其进行声明,却绝不能重复定义。

  编译器负责检查数据类型是否支持要执行的运算,如果试图执行类型不支持的运算,编译器将报错并且不会生成可执行文件。

  C++的标识符由字母、数字和下划线组成,其中必须以字母或下划线开头,标识符的长度没有限制,但是对大小写敏感。

  变量命名规范:

  • 标识符要能体现其实际意义;

  • 变量名一般用小写字母;

  • 用户自定义的类名一般以大写字母开头;

  • 如果标识符由多个单词组成,则单词间应该有明显的区别。

  primer C++:第二章学习

  作用域是程序的一部分,在其中名字有特定的含义。


当你第一次使用变量时再定义它。


  作用域能彼此包含,被包含(或者说被嵌套)的作用域被称为内层作用域,包含着其他作用域的作用域被称为外层作用域。内层作用域的变量会覆盖外层作用域的变量。


如果函数有可能用某全局变量,则不宜再定义一个同名的局部变量。


  复合类型是指基于其他类型定义的类型。

  引用为对象起了另一个名字,引用类型引用另外一种类型,通过将声明符写成&d的形式来定义引用类型,其中d是变量名。定义引用时,程序把引用和它的初始值绑定在一起,而不是将初始值拷贝给引用。一旦初始化完成,引用将和它的初始值对象一直绑定在一起。因为无法令引用重新绑定到另外一个对象,因此引用必须初始化。


引用并非对象,相反的,它只是为一个已经存在的对象所起的另外一个名字。


  引用的类型必须和与之绑定的对象严格匹配,并且引用只能绑定在对象上,而不能与一个字面值或者某个表达式的计算结果绑定在一起。

  指针是“指向”另外一种类型的复合类型。与引用类似,指针也实现了对其他对象的间接访问。

  指针与引用不同的地方:

  • 指针本身就是一个对象,允许对指针赋值和拷贝,在指针的生命周期内,它可以先后指向几个不同的对象;

  • 指针无需在定义时赋初值,和其他内置类型一样,在块作用域内定义的指针如果没有被初始化,也将拥有一个不确定的值。

  指针的值应该处于以下四种状态:

  • 指向一个对象;

  • 指向紧邻对象所占空间的下一个位置;

  • 空指针,意味着指针没有指向任何对象;

  • 无效指针,也就是上述情况意外的值。


解引用操作仅适用于那些确实指向了某个对象的有效指针。


  void*是一种特殊的指针类型,可用于存放任意对象的地址,一个void*指针存放着一个地址,这一点与其他指针类似。不同的是,我们对该地址中到底是个什么类型的对象并不了解。void*用途:拿它与其他指针比较、作为函数的输入或输出,或者赋给另外一个void*指针。不能直接操作void*指针所指的对象。

  引用本身不是一个对象,因此不能定义指向引用的指针,但能定义指针的引用。


面对一条比较复杂的指针或引用的声明语句时,从右向左读有助于弄清楚它的真实含义。


  默认情况下,const对象被设定为仅在文件内有效,当多个文件中出现了同名的const变量时,其实等同于在不同文件中分别定义了独立的变量。


如果想在多个文件之间共享const对象,必须在变量的定义之前添加extern关键字。


  可以把引用绑定到const对象上,就像绑定到其他对象上一样,我们称之为对常量的引用。与普通引用不同的是,对常量的引用不能被用作修改它所绑定的对象。初始化常量引用时允许使用任意表达式作为初始值,只要该表达式的结果能转换成引用的类型即可。

  类似于常量引用,指向常量的指针不能用于改变其所指对象的值。常量指针必须被初始化。

  顶层const表示指针本身是一个常量,底层指针表示指针所指对象是一个常量。当执行对象的拷贝操作时,拷入和拷出的对象必须具有相同的底层const资格,或者两个对象的数据类型必须能够转换。一般来说,非常量可以转换成常量,反过来则不行。

  常量表达式是指值不会改变并且在编译过程就能得到计算结果的表达式。


一般来说,如果你认定变量是一个常量表达式,那么就把它声明为constexpr类型。


  在constexpr声明中如果定义了指针,限定符constexpr仅对指针有效,与指针所指的对象无关。

primer C++:第二章学习

  类型别名是一个名字,它是某种类型的同义词,有两种类型别名:

  • typedef: typedef double wages;

  • using: using SI=Sales_data;


typedef char *pstring;

cosnt pstring cstr=0;  //cstr是指向char的常量指针

const char *cstr;  //cstr是指向const char的指针


  auto的使用:

  • 编译器以引用对象的类型作为auto的类型;

  • auto一般会忽略顶层const,同时底层const会被保留下来。

primer C++:第二章学习

  decltype的作用是选择并返回操作数的数据类型。

  如果decltype使用的表达式不是一个变量,则decltype返回表达式结果对应的类型,另一方面,如果表达式的内容是解引用操作,则decltype将得到引用类型。


decltype((variable))的结果永远是引用,而decltype(variable)结果只有当variable本身是引用时才是引用。


  为了确保各个文件中类的定义一致,类通常被定义在头文件中,而且类所在头文件的名字应与类的名字一样。头文件通常包含那些只能被定义一次的实体。


头文件一旦改变,相关的源文件必须重新编译以获取更新过的声明。


  头文件保护符:

#ifndef ...

#define ...

#endif