《C++ Primer 第五版》 阅读过程查漏补缺 chapter 2

C++ Primer 第五版 阅读过程查漏补缺 chapter 2

变量的定义和声明

声明: 使得名字为程序所知,

定义:负责创建与名字相关的实体。

如果想要声明一个变量而非定义它,就需要在变量名前加上关键字__extern__。

eg. 	extern int i; 	//声明i而非定义
		int j;			//声明并且定义j

然而,如果给extern标记的变量赋予了初始值,则进行了定义。

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

复合类型

引用和指针都是c++的复合类型。他们的相似和区别如下:

相同不同
引用实现了对某个对象的间接访问
一般情况引用类型需要和绑定的对象严格匹配
1. 引用在定义时就要进行和对象的绑定,一经绑定无法修改
2. 引用本身不是一个对象,仅仅是一个别名,没有实际地址
3. 引用只能绑定在某个对象上,不能绑定在字面值或者计算结果
指针实现了对某个对象的间接访问
一般情况引用类型需要和绑定的对象严格匹配
1. 指针本身就是一个对象,允许对指针赋值访问
2. 指针无需在定义时赋初值,而且在其生命周期,可以多次指向不同对象
3. 指针存放的是对象地址,所以赋值时要用取址符&获取对象地址
4. 使用指针时,需要使用解引用符*来访问对象

注: 可以有指向指针的引用,不能有指向引用的指针

int i = 42;
int *p;
int *&r = p;		// r是一个指向指针p的引用
r = &i;				// 给指针p赋值
*r = 0;				// 得到p指向的对象并赋值

空指针:nullptr (c++11新标准引入) 等同于初始化为字面值0。

void* 指针: 一种特殊的指针类型,可以用于存放任意对象的地址。我们可以用void*指针进行指针比较、作函数输入或输出,或者赋值给别的void*指针,但是我们不能直接操作它所指向的对象

const类型

const对象一般情况下仅在文件内有效。当多个文件中出现多个const,则说明是在多个文件中分别定义了不同的对象。

如果想要在多个文件中声明或使用某个const对象,那就需要在定义和声明时都加上extern关键字。

const的引用

前面提到引用必须严格和绑定的对象进行匹配,int配int,double配double,但是在const中,针对const的引用是允许用任意表达式作为初始值的,只要其结果可以转换为引用的类型就可以。

eg. 
	double dval = 3.14;			// 
	const int &ri = dval;		// 此时ri为3

当然此时对ri是无法进行赋值操作的,而且此时 编译器中实质发生的是这样的过程:

	double dval = 3.14;			
	const int temp = dval;			// temp是一个临时量对象
    const int &ri = temp;			// ri实际引用的是一个临时量对象,所以显然无法对它进行更改

引入了_临时量_这一概念之后,就很好理解“对const的引用可能引用一个并非const对象”的概念了。

    int i = 42;	
    int &r1 = i;		   		// 引用r1是一个普通的引用,绑定了i
    const int &r2 = i;			// 引用r2是一个对const的引用,表面绑定了i,实质绑定的是一个临时量对象
    r1 = 0;						// 此时i还可以通过r1更改
    r2 = 0;						// 这里就会报错,因为r2是无法对i进行任何更改的。
指针与const

普通指针类型无法指向常量。只有指向常量的指针才可以指向常量类型。指向常量类型的指针写作:const 数据类型 *ptr

前面同样提到指针类型必须和它指向的对象的类型一致,但是指向常量的指针,也是可以指向一个非常量的对象的。

eg.
	double i = 3.14;	// 非const
	const double *cpter = &i;	//指向非常量对象,但是无法通过cpter改变

常量指针(const pointer):const允许把指针本身定为常量。常量指针必须初始化, 一但初始化完成,指针就和它所指向的地址绑定了。但是指针指向的变量本身是可以改变的,换言之如果指向的是变量而不是常量,我们仍然可以使用*ptr进行访问或修改。常量指针写作:数据类型 *const ptr;

常量指针(顶层const)指向常量的指针(底层const)指向常量的常量指针 (右边的const是顶层const 左边的const是底层const)
指针对象是一个常量指针指向的对象是一个常量两者都是常量
可以通过解引用符*修改指向的变量无法通过解引用符*修改指向的变量无法通过解引用符*修改指向的变量
无法指向其他的对象可以指向其他的对象无法指向其他的对象
声明时必须初始化声明时不必定义声明时必须初始化

顶层const和底层const

底层const顶层const
定义指针和引用的复合类型的基本类型部分是常量任意的对象是常量
拷贝操作拷入拷出的对象必须都是相同的底层const,或者可以相互转换(非常量可以转为常量,反之不行)不受影响

底层const和顶层const的实质理解是这样的:

对于一般对象,只存在顶层const

对于指针,由于指针包含了本身这个对象和它所指向的对象两个对象,所以指针本身的const称之为顶层const,指针指向的对象的const称之为底层const

对于引用,引用本身不是对象,所以只存在底层const

constexpr和常量表达式

常量表达式指的是在编译过程就能得到计算结果的表达式

声明为constexpr的变量一定是一个常量,而且必须用常量表达式初始化

一个constexpr指针的初始值必须为nullptr或者0,或者某个存储在固定地址的对象

指针和constexpr
constexpr int *q = nullptr 		// q是一个指向整数的常量指针,等同于 int *const q = nullptr

constexpr可以把它所定义的对象置为顶层const。同时,constexpr指针既可以指向常量也可以指向非常量。但是当它指向一个变量名时,它的定义必须在函数体外

int j = 0;
constexpr int i = 42;			//i的类型时整型常量
// i和j必须定义在函数体之外
constexpr const int *p = &i;	// p是常量指针,指向整型常量i
constexpr int *p1 = &j;			// p1是常量指针,指向整数j

处理类型之类型别名

指针、常量和类型别名
eg.
	typedef char *pstring;
	const pstring cstr = 0;			// cstr是指向char的常量指针  类似于char *const cstr = 0;而不是直接带入的const char *cstr
	const pstring *ps;				// ps是一个指针,指向了一个对象,该对象是一个指向char类型的常量指针

总之不能直接将typedef带入进行理解。

处理类型之auto和decltype

c++11新标准引入的新的类型说明符auto和类型指示符decltype。

  1. auto 让编译器通过初始值来推算变量的类型
    1. auto定义的变量必须具有初始值
    2. auto能在一条语句中声明多个变量,但是该语句中所有变量的初始基本数据类型必须一致。
  2. decltype 编译器分析表达式并得到它的类型,但是不计算表达式的值
    1. decltype如果使用的是一个不加括号的变量,则得到的结果就是该变量的类型
    2. decltype如果使用的是一个加括号的变量 ,则编译器会把它当作表达式,得到的结果是引用类型
autodecltype
相同都可以通过编译器获得变量类型都可以通过编译器获得变量类型
不同1. 跟引用相关时,auto采用的是引用对象的值
2. 在处理顶层const时,auto会自动忽略掉顶层const,只保留底层const
3. 跟解引用*相关时,auto采用的是对对象地址进行解引用后的值
1. 跟引用相关时,decltype采用的是对象的引用
2. 在处理顶层const时,decltype会保留顶层const
3. 跟解引用相关时,decltype采用的是对对象的引用
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值