从书上抄的
第二章
2.1 基本内置类型
略
2.2变量
变量提供一个具名的、可供程序操作的存储空间。C++中的每个变量都有其数据类型,数据类型决定着变量所占空间的大小和布局方式、该空间能存储的值的范围,以及变量能参与的运算。
2.2.1变量定义
初始化
初始化和赋值是完全不同的操作。初始化是创建变量时赋予其一个初始值,而赋值的含义是把对象的当前值擦除,而以一个新值来替代。
列表初始化
c++11,用花括号来初始化变量。
赋值,允许信息丢失。初始化,不允许信息丢失,编译器会报错。
2.2.2变量声明和定义的关系
c++支持分离式编译,即允许将程序分割为若干个文件,每个文件可被独立编译。
如果将程序分为多个文件,则需要有在文件间共享代码的方法。
声明,使得名字为程序所知。定义,负责创建与名字关联的实体。
extern 表示声明外部,给更多地方使用。(支持分离式编译)
若static extern,表示仅在本文件使用
extern 不是定义,而是引入(声明)在其他源文件中定义的非static全局变量。
c++是静态类型语言,在编译阶段检查类型。
编译器负责检查数据类型是否支持要执行的运算,如果试图执行类型不支持的运算,编译器将报错,且不生成可执行文件。
2.3符合类型
复合类型是基于其他类型定义的类型。(主要有:引用和指针)
数据类型 变量名列表;
2.3.1 引用
引用不是对象,只是别名。
2.3.2 指针
与引用类似,指针也实现了对其他对象的间接访问。
赋值和指针
指针和引用都能提供对其他对象的间接访问。区别是:引用不是对象。一旦定义了引用,就无法令其再绑定到另外的对象。
指针和它存放的地址可以修改。可以令它存放新的地址,从而指向一个新的对象。
2.3.3 理解复合类型
变量的定义包括:一个基本数据类型和一组声明符。一条定义语句,虽然基本数据类型只有一个,但是声明符的形式却可以不同。
•int i=1024, *p=&i, &r=i;//
指向指针的指针
指向指针的引用
•int i = 42;
•int *p; //p是一个int型指针
•int *&r = p; //r是一个对指针p的引用
•r=&i; //r引用了一个指针,给r赋值&i就是令p指向i
•*r=0; //解引用r,就是p指向的对象,将i的值改为0
•//从右往左读r的定义。r是引用,int *是引用的对象的类型,即整形指针。
2.4const限定符
•初始化和const
•默认状态下,const对象仅在文件内有效
•当以编译时初始化的方式定义一个const对象时,
•const int bufSize = 512;
•编译器将在编译过程中把用到该变量的地方替换成对应的值。(编译器会找到代码中用到bufSize的地方用512替换。)
•为了执行上述替换,编译器需要知道变量的初始值。如果程序包含多个文件,则每个用了const对象的文件都必须得访问到它的初始值才行。因此,每个用到变量的文件都要有对它的定义。(因此,默认const对象仅在该文件内有效)
•若要在多文件共享const变量,解决办法是添加extern关键字,无论是声明还是定义。
•extern const int bufSize=fcn();//定义并初始化bufSize,需要extern才能被其他文件使用。
•extern const int bufSize;//在头文件的声明,指明bufSize不是文件独有。
•2.4.1 const的引用
•对常量的引用不能被用作修改它所绑定的对象。
•const int ci = 1024; //常量
•const int &r1 = ci; //r1是个引用,绑定的对象是个const int
•int &r2 = ci; //错误.r2是个引用,需要绑定的是int,但是ci是const int.
•//对于非const的int,可以用const引用取绑定他;
•//对于const的int,不能用非const引用绑定他。权限冲突,const int对象本身不可修改,引用也无权修改。//权限可以少,但是不能多。
•//常量引用是对const的引用。
•2.4.2指针和const
•指向常量的指针,不能用于改变其所知对象的值。要想存放常量对象的地址,只能使用指向常量的指针。
•指向常量的指针或引用,不过是自以为是,它们觉得指向了常量,自觉地不去改变对象的值。
•const指针
•指针是对象,引用不是。允许把指针本身定义为常量。常量指针必须初始化。
•把*放在const关键前,用以说明指针是个常量(不变的是指针的值,而不是所指对象的值)。
•int errNumb0;
•int *const curErr = &errNumb; //常量指针curErr,将一直指向errNumb
•const double pi = 3.14159;
•const double *const pip = π //指向常量pi的 常量指针pip。
•2.4.3 顶层const
•顶层const表示指针本身是个常量;
•底层const表示所指对象是个常量。//二者是相互独立的。
•int i = 0; //
•int *const p1 = &i; //不能改变p1的值,顶层const
•const int ci = 42; //不能改变ci的值,对象ci本身是const,顶层const
•const int *p2 = &ci; //允许改变p2的值,底层const。所指对象是const int,不能改所指对象的值。(自以为是)
•const int *const p3 = p2; //不能改变p3的值,也不能改变所指对象的值。
•const int &r = ci; //用于声明引用的const都是底层const
•对执行对象拷贝操作时,顶层const没有限制。
•对底层const有限制:
•int *p = p3; //错误。p3包含底层const的定义而p没有。p可能修改p3所指的对象。
•p2 = p3; //p3是const指针,不改指向。所指对象ci是const int。p2可以接收p3,因为底层const都是const int。且p2指向是非const的,可以改变指向
•p2 = &i; //p2可以改变指向。p2指向const int 是自以为是!自觉不改其值而已。
•int &r = ci; //错误。引用r不自觉地会该const int
•const int &r2 = i;//正确。自以为是。
•2.4.4 constexpr和常量表达式
•常量表达式,值不变,且在编译过程就能得到结果的表达式。
•constexpr 变量
•声明为constexpr类型,以便由编译器验证
•指针和constexpr
•如果constexpr声明中定义了一个指针,则只是对指针const,所指对象不限制。顶层const
2.5.1类型别名
2.5.2auto类型说明符
C++11引入auto类型说明符,用它让编译器分析表达式所述的类型。auto让编译器通过初始值推算变量的类型。
符合类型、常量和auto
•编译器推断auto类型有时和初始值的类型不完全一样,编译器会适当改变使其更符合初始化规则。
•首先,当引用被用作初始值时,真正参与初始化的其实是引用对象的值。
•其次,auto一般会忽略顶层const,保留底层const。当初始值是指针常量时。
•const int ci = i, &cr =ci;
•auto b = ci;
•auto c = cr;
•atuo d = &i;
•auto e = &ci;
•2.5.2auto类型说明符
•C++11引入auto类型说明符,用它让编译器分析表达式所述的类型。auto让编译器通过初始值推算变量的类型。
•符合类型、常量和auto
•编译器推断auto类型有时和初始值的类型不完全一样,编译器会适当改变使其更符合初始化规则。
•首先,当引用被用作初始值时,真正参与初始化的其实是引用对象的值。
•其次,auto一般会忽略顶层const,保留底层const。当初始值是指针常量时。
•const int ci = i, &cr =ci;
•auto b = ci; //b是一个整数(ci的顶层const被忽略)
•auto c = cr; //c是一个整数(cr是ci的别名,ci本身是一个顶层const)
•atuo d = &i; //d是一个整形指针(整数的地址就是指向整数的指针)
•auto e = &ci; //e是一个指向整数常量的指针(对常量对象去地址是一种底层const)
•如果希望推断出auto类型是顶层const,需要手动加:
•const auto f = ci;
•设置auto的引用时,初始值的顶层const属性仍然保留。
•auto &g = ci; //g是const int&,不能为g赋值
•auto &h = 42; //错误//h是int&,不能绑定字面值
•const auto &j = 42; //正确.//j是const int&
•2.5.3decltype类型指示符
•希望从表达式的类型推断出要定义的变量的类型,但是不想用表达式的值。
•declytype的作用是选择并返回操作数的数据类型。
•编译并不实际调用函数f,却能使用调用f时的返回值类型。
•decltype(f()) sum = x; //sum的类型是函数f的返回值类型
•decltype处理顶层const和引用的方式和auto不同。如果decltype使用的表达式是变量,则返回变量的类型。
•decltype和引用
•int i = 42, *p = &i, &r = i;
•decltype(r+0 b); //正确。加法的结果是int,因此b是个未初始化的int
•decltype(*p) c; //错误。c是int&,必须初始化。
•//r是个引用,因此decltype(r)的结果是引用类型。如果想让结果类型是r所指的类型,可以把r作为表达式的一部分如r+0。
•如果表达式的内容是解引用操作,则decltype将得到引用类型。解引用指针可以得到指针所致的对象,而且还能给对象赋值,因此decltype(*p)的结果类型就是int&。
•decltype((i)) d; //错误。d是int&,必须初始化
•decltype(i) e; //正确。e是未初始化的int