C++ Primer第二章的内容主要介绍了变量和基础类型,包括C++语言定义的基础内置类型、变量的定义及声明、符合类型如指针及引用的介绍和const及常量表达式constexpr的介绍,本次博客也从这四个方面进行系统的介绍,如果有不足之处,还望其他博主留言指正;如果博客对你有一定的帮助,还请点个赞支持一下。
1)基本内置类型
C++语言具有广泛的数据类型,除了基本内置类型之外,还定义了一些复杂的数据类型,比如可变长字符串string和向量vector等,另外也为码农提供了自定义数据类型的机制,比如类和结构体等,本次博客主要是介绍C++语言中的基本内置类型。
C++将基本内置类型分为算术类型和空类型(void),算术类型又分为整数类型和浮点数类型,其中整数类型又分为布尔类型(bool 未定义最小尺寸大小,值为true或false),字符类型(char,最小尺寸为8位),short类型(最小尺寸为16位),int类型(最小尺寸为16位),long类型(最小尺寸为32位),long long类型(C++11中新定义的,最小尺寸为64位);另外浮点型包括单精度浮点型(32位,有效位数为5位)和双精度浮点型(64位,有效位数为7位),且浮点数在计算机中的储存结构如下图所示:
C++中定义一个char类型的大小和一个机器字节一样长,同时定义byte(long long)>=byte(long)>=byte(int)>=byte(short)。
在选择数据类型的时候有以下四条建议:1)合理使用无符号类型,避免无符合和有符号数混合运算;2)整型定义尽量使用int,如果数据较大则使用long long;3)算术表达式尽量不要出现bool和char类型;4)浮点运算选用double类型。
2)初始化及赋值和声明及定义
初始化和赋值时两个完全不同的概念,初始化的含义是创建变量时并对变量赋予一个初始值,其调用的是定义好或默认的构造函数,而赋值的含义是将对象当前的值擦除,并用一个新值来替代,调用的是拷贝构造函数或=重载操作符函数。
如果变量只是定义但没有指定初值,系统会对变量进行默认初始化。对于内置类型变量的默认初始化值,和其位置有关。如果内置类型变量定义在任何函数之外,则默认初始化为0;如果定义在函数内部,则不会被初始化,此时的值未定义,拷贝和访问没有定义的值会发生错误。绝大多数类都支持默认初始化,这和类中是否有默认构造函数有关,有一些其他的类则需要显示进行初始化。
C++规定,可以采用初始化列表的形式来初始化变量,即采用一组由花括号括起来的值来初始化变量,但是需要注意的是使用初始化列表的形式初始化内置类型变量时,如果初始化过程中存在数据截断的情况,如把一个浮点数赋值给整数,编译器会报错。
C++为了方便程序实现分离式编译(可以理解成.C和.h文件的独立),将声明和定义区分开。声明的目的是为了让变量的名字为程序所知,声明中只规定变量的类型和名字,并在前面加上extern关键字(但不能对加了extern关键字的变量进行初始化,否则extern关键字失效);定义的目的则是为了创建和名字有关的实体,为变量申请内存空间,还可能初始化变量。
建议:不管是在函数内还是函数外,使用内置类型都要初始化。在函数体内部初始化一个由extern关键字标记的变量,会发生错误,因为变量只能定义一次,但可以多次声明。
3)指针及引用
指针是一种指向其他类型对象的复合类型(基本数据类型+一组声明符),大多数情况下需要满足定义的指针类型和指针指向对象的类型匹配(两种特殊情况:1)常量指针指向非常量对象。2)virtual类的动态编译)。指针是一个对象,可以进行赋值和拷贝,也可以指向不同的对象,同时不需要在定义的时候进行赋值(和引用的区别)。使用指针时,如果需要分析程序执行的每个时间段指针的指向,可以采用内存四区模型和一个建议(指针指向谁,就把谁的地址赋给指针)来进行分析。
对于指针而言,指针的值存在四种状态:1)指向一个对象(一般情况);2)指向紧邻对象的一个空间(尾后迭代器);3)空指针,没有指向任何对象;4)无效指针,除1)2)3)情况之外。
建议:对于使用了指针的情况下,要判断所得到的指针是否有效,访问和拷贝无效指针的值会使程序崩溃。
引用是指对象的别名,一般情况下的引用都指的是左值引用。引用定义的机制是将引用和变量对象绑定起来,使得引用称为变量的另外一个名字,但是此时的变量对象可以不初始化。由于定义引用需要将引用和变量对象进行绑定,因此引用必须初始化,且一旦绑定了一个对象,引用就不能再绑定另外一个对象了。引用不是对象,它只是变量对象的一个别名,因此不能定义引用的引用或指向引用的指针。由于引用是和变量对象是绑定起来的,因此通常情况下引用的类型和绑定对象的类型要一致(除了两种情况:1)初始化常量引用,可以采用任意表达式作为初始值,只要能够转换成引用类型;2)virtual类的动态编译)。
4)const和常量表达式constexpr
const限定符的作用是用于限制变量的类型。一般情况下有两种情况:1)默认情况下,const对象只能在文件内有效。多个文件出现相同的const变量时,等同于不同文件中独立定义的const变量。2)当const变量初始值不是一个常量表达式且需要实现多个文件共享变量,需要在一个文件中定义const变量,其他文件中声明并使用它(声明和定义变量时都需要加上extern const标识符)。
常量引用:也称为对const的引用,是将引用绑定到const对象上。C++规定允许将非常量的对象,字面量和一般表达式绑定给一个常量引用,只要右端的值能够转化为引用的类型即可。但是,在不同类型转换的过程中,其实引用绑定的是一个临时量,而非我们希望绑定的那个数据,具体例子如下所示:
double var=3.14; ------------> const int temp=var;
const int &p=var; _______> const int &p=temp;
建议:使用引用绑定对象时,养成引用和绑定对象类型一致的习惯。
常量表达式(constexpr)指的是值不会改变且在编译过程中能够得到计算结果的表达式。一般来说,可以使用算术类型,引用和指针等字面值类型的变量来初始化常量表达式。除此之外,可以地址固定不变的对象来初始化常量表达式。对于constexpr类型的指针初始值必须为nullptr(0)、存储于某个固定地址的对象或超出函数范围之外的变量(如static和global变量)。
C++11规定可以采用constex来验证变量的值是否为常量表达式,初始化常量表达式的值必须为常量或constexpr函数。
***知识点补充1:字,字节和位的区别?
位:即bit,是计算机用来存储数据的最小单元,取值为0或1;
字节:即byte,是计算机可寻址的最小内存块,一个字节等于8bit;(牵涉到的知识点:定义数据的大小)
字:即word,是计算机存储的基本单元,通常由几个字节组成;(牵涉到的知识点:数据对齐方式和计算机的位数)
***知识点补充2:变量,对象和值之间的关系?
变量:提供一个具体名字的,可供程序操作的存储空间。
对象:具有某种类型的内存空间(数据类型+内存空间)。
值:只读的数据。
已命名的对象才称为变量。
***知识点补充3:变量的命名规则?
变量的命名规则有以下四个建议:1)变量名体现实际含义;2)变量名一般使用小写;3)自定义的类名以大写字母开头;4)如果出现多个单词,单词之间采用下划线连接。
***只是补充点4:指向常量的指针/引用,常量指针,顶层const,底层const区别?
指向常量的指针/引用:指针指向的/引用绑定的对象为常量,此时不能用指针/引用去改变常量对象的值。
指针常量:指针的地址不变,指向的对象数据可以发生改变,必须初始化。
顶层const:定义的对象是常量(如常量指针,常量内置定义类型);
底层const:定义对象指向的值或者绑定的值为常量(如指针常量,指向常量的引用);