震惊!5句话搞定所有CPP的复杂类型声明

什么叫搞定:任意给一个类型声明语句,能够判断其是正确的还是错误的,如果是正确的,其是什么含义。
什么叫复杂类型声明:融合指针,引用,const,数组,函数声明,函数指针等各种元素的类型声明。

  1. 对象是一块具有类型的内存空间;
  2. *与&都是可以做为类型修饰符使用,用于修饰类型
  3. const是对象修饰符,用于修饰对象,表示该对象的内容不能改变;
  4. 引用不是对象,引用初始化后与某个对象绑定后不能再解绑;
  5. 从内到外,从右到左阅读复杂的类型声明。

如果能够理解上述5句话的话,所有复杂的类型声明都不在话下,废话不多说,搞几个例子试一试:

1、常量引用(指向常量的引用)
   首先我们知道,引用不是对象,而const是用来修饰对象的,所以不存在使用const去修饰一个引用,而只存在一个引用绑定的对象是const的。

const int &A = B;  //指的是A是一个const int类型的引用。

其实这儿这么说是不严谨的,应该这么说,A认为自己引用的是一个const int类型的对象,其实不一定是。具体区别请看下述实例:

int B = 0;
const int &A = B;
const int B = 0;
const int &A = B;

    下述两段代码在CPP中都是正确的。注意第一段中,引用A的类型与B的类型不是完全匹配的,为什么允许呢?这其中包含着下述逻辑:
   

B不是一个const对象,所以其值是可以被改变的,那么我将A定义为一个与const
int类型对象绑定的引用。A就认为自己引用的是一个const的对象,就不会使用A
去修改这个对象的值,另外对于第一种情况,B做为一个int型的对象,而不是const对象,就算修改都是没有关系的。

如果是下述这样:

const int B = 0;
int &A = B;

A的定义就是错误的,因为下述逻辑:

B是一个const修饰的对象,其内容是不能改变的;但是A却认为自己是与一个int类型的对象绑定的,所以A会去修改B的值,这就违反了CPP的原则了,所以不允许。

再看下述定义:

int & const A = B; 

这个定义就是错误的,无法解释。按照我们从右向左阅读的原则来看,A是一个对象被const修饰的。但是再看&,发现A应该是一个引用,这就矛盾了。根据前面第4句话引用不是对象,所以上述定义是错误的

2、常量指针
    引用不是对象,但是指针是正常对象的。

int B = 0;
int *const A = &B; //A是一个被const修饰的对象,所以A的内容不能够改变。
					//而A的类型是int *,所以A是一个指针,即A指向的位置不能够改变
const int B = 0;
int *const A = &B; 
/*
	这个定义是错误的,与1中的逻辑是一样的。A做为一个指针,其认为自己是指向一个int型的,
	而实际其指向的是一个const int型的,所以如果试图使用A去修改B的值就会发生错误。
*/

3、指向常量的指针

const int B = 0;
const int *A = &B;
/*
	A是一个指针,其指向的是一个const int类型的对象。
*/
int B = 0;
const int *A = &B;
/*
	这个定义也是正确的,与1中逻辑一样:
		A做为一个指针,认为自己是指向const int类型的对象的,虽然其指向的是一个int型的对象,但是并不会使用A去修改B的内容,就算修改也没有关系的。所以这种定义是允许的。
*/

4、底层const与顶层const

顶层const:指针本身是一个常量
底层const:指针指向的对象是一个常量

const int B = 0;
const int *const A = &B;
/*
8个字:从内到外,从右到左

先看最右边的const————说明A是一个对象,而且其内容不能改变。

然后看*————说明A是一个指针,故A指向的位置不能改变的。

然后看const int————说明A指向的是一个int对象,而且这个对象被const修饰。

所以综上:A做为一个指针其指向的位置不能改变,同时A==认为==自己指向的是一个const int对象,所以也不能使用A去改变B的值。
*/

注:A认为自己指向的是一个const的对象,并不代表其真指向的是一个const对象,仅仅只能说明A认为自己不能够去修改其指向的对象的。详见1,2,3中的逻辑分析。

引入数组类型[],函数类型更复杂的类型声明呢?

牢记8个字:从内到外,从右到左。
接下来,我就用这8个字给大家分析一些更加复杂的例子:

int *A[];  
/*
先看最右边[]————说明A是一个数组

再看*————说明A中的元素都是指针

再看int————说明A中的元素都是int型指针
*/
int *A();

/*
	先看最右边()————说明A是一个函数

	再看int *————说明A这个函数返回的是int *类型
*/
int (*A) ();

/*
	从内到外,先看(*A)————说明A是一个指针

	从右到左,再看()————说明这个指针是指向一个函数的

	再看int————说明这个函数返回类型是int型的
*/

再来一个更高水平的,读者可以先自己试一试,再来看我的分析

int (*A(int) ) (int*, int);

/*
跟我一起念,从内到外,从右到左

先看(int)————说明A是一个函数

再看*A(int)————说明A这个函数返回的是一个指针

再看(int*, int)————说明返回的这个指针也指向一个函数,这个函数的形参是int* 与 int类型的

再看最左边的int————说明返回的这个函数其返回类型是int。

综上:A是一个形参为int类型,返回值类型为一个函数指针的函数。
		而其返回的函数指针指向的函数,形参为int * 与 int 类型,返回类型为int。

*/

最后给出一个类似的练习,读者自行分析:

int (*A(int i)) [10];

一些其他的注意点

1、数组的维度是做为数组类型说明的一部分的。
2、函数的类型,由形参类型以及返回类型共同组成的。
3、&符号在CPP中的四种使用方式:
- 按位与运算符
- 取地址运算符
- 函数声明中的形参中表示引用传递
- 用在复合类型中,做为类型修饰符使用,表引用
4、*符号在CPP中的三种使用方式:
- 乘法符号
- 用在复合类型中,做为类型修饰符使用,表指针
- 用来解析指针,做为解引用符

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值