C++中typedef的复杂用法很多,特别容易出现在面试题中,这一章用于总结typedef的用法。
本文仅供个人记录和复习,不用于其他用途
typedef的基本用法
typedef
与define
宏替换不同,它不是简单的文本替换,而是类型替换。我们在开发的过程中,经常会出现类型特别复杂的情况。为了方便,我们通常用typedef
进行简化,减少工作量。最简单的用法是用别名替换类型名,比如typedef int* pI
。很多时候,我们不一定是为了简化类型名,而是为了给类型名起一个别名,方便我们理解。
扩展的用途
在C程序中,我们实例化struct
结构体时,必须用struct + 结构体名 + 变量名
的形式,而在C++中则不需要加上struct
。那么为了简单一点,可以用typedef
简化,这样一来,我们可以直接使用POINT
来创建结构体变量:
|
|
另外呢,在实际开发的过程中,可以使用typedef
来定义与平台无关的类型。比如在win32
平台,int
为4个字节,而当处于Linux
平台时,int
只有2个字节。那么,为了方便起见,可以将int
类型起一个别名:
|
|
这样一来,我们在编程的过程中便直接使用INT
。当平台中的int
类型不再是4个字节时,我们可以使用4个字节的变量来代替它(比如Linux
中的long
类型),不再需要我们手动一个个地在代码中更改。
复杂声明的替换
事实上,typedef
用得最多的还是这个方面。替换时记住一个规则,就是把变量名留到最后,先替换复杂的声明。下面呢,我将举出一些常见的例子:
|
|
这里不是很复杂,直接替换变量名就可以了。
|
|
这个的参数比较复杂,先替换参数,再替换变量名。
|
|
由于指针指向的数组是包含了函数指针,因此先将函数指针替换,再替换变量名。
如何判断一个复杂声明
虽然我上面讲述了如何替换,但大家可能还是不知道,如何判断原来的表达式是什么类型。这里告诉大家一个简单的方法,那就是从变量名开始解读,先往右,碰到括号再往左,然后再跳出括号判断。下面举一些例子:
|
|
从右往左,首先是一个引用,引用的是一个指向int
类型的指针。
|
|
func
是一个指针,跳出括号,发现是一个函数,那么func
是一个函数指针。这个函数的返回值是int
类型,参数是指向int
类型的指针。
|
|
向右看,func
是一个数组,再向左看,这个数组包含的是指针。随后跳出括号,发现是一个函数。那么,func
便是函数指针数组。
|
|
不要被这一长串声明吓住了,先看变量名z
的右边,很显然这是一个函数,这个函数的参数分别是一个int
类型变量和一个函数指针。既然z
是函数,那么肯定有返回值。看看左边,明显是一个函数指针。总的来讲,z是一个函数,有两个参数分别为整型变量和函数指针,返回值为函数指针。
注意事项
既然typedef
不是简单的文本替换,那么必然会存在一些问题。下面的这个例子很好地说明了这一点:
|
|
按照一般的理解所推断,我们会理所当然的认为const CH
就是const char *
,事实上这是不正确的。CH
所代表的类型是指向char
类型的指针,const
所作用的是指针而不是所指向的对象,因此,这里const
应该是对指针进行了限制。
|
|
另外,上面的声明也是错误的,因为typedef
是和auto
、extern
、mutable
、static
、register
等一样的,都是影响对象的存储特性的类型。尽管typedef
并不影响对象的存储,但它确实是这种类型。
typedef和define的区别
翻看了许多资料,我发现了typedef
与define
的一些不同之处。例如:
|
|
上面的s1
、s2
、s3
都被定义为char *
,而s4
则定义成了char
。从根本上来说,typedef
是为类型起别名,而define
只是简单的文本替换。