随着程序的越来越复杂,程序中用到的类型也越来越复杂,体现在两个方面:
- 类型名称难于拼写,名字既难记由容易写错,还无法确定其真实目的是什么
- 有时候根本不知道所需要的类型是什么,我们必须从上下文寻求帮助
这时候我们主要有三种解决方案:
- 类型别名
类型别名是一个名字,是某种类型的一个同义词。
传统方法定义别名用的是typedef:
typedef double wages; //wages是double的同义词
wages hourly, weekly; //等同于double hourly, weekly;
C++11标准规定了一种新的办法,即使用别名声明,using:
using wages = double; //wages是double的同义词
wages hourly, weekly; //等同于double hourly, weekly;
这里需要注意的是,假如某个类型别名指代的是复合类型或者常量,那么把它用到声明语句里就会产生意想不到的后果:
typedef char *pstring;
const pstring cstr = 0; //cstr指向char的常量指针
const pstring *ps; //ps是一个指针,它的对象是指向char的常量指针
这里必须要明白,pstring实际上是指向char的指针,所以const pstring就是指向char的常量指针,而非指向常量字符的指针,不能简单的将类型别名替换成他本来的样子:
const char *cstr = 0; //这是对const pstring cstr的错误理解
2.auto类型说明符
在我们编程的时候,常常需要把表达式的值赋值给变量,这要求在声明变量的时候知道表达式的类型,然而这一点是很不容易的,所以C++11引入了auto说明符来帮助我们推断表达式所属的类型,由auto的特性我们知道,auto定义的变量必须有初始值。
这里我们要注意的是,auto可以在同一条语句中声明多个变量,但是一条语句中只能有一个基本数据类型,所以该语句中所有的初始基本数据类型都必须一样:
auto i = 0, *p = &i; //正确,i是整型,p是整型指针
auto sz = 0, pi = 3.14 //错误,sz是整型, pi是浮点型
使用auto我们还必须要注意以下几点:
- 首先,和我们之前所知道的一样,使用引用其实就是使用引用的对象,特别的是,当引用作为初始值的时候,参与初始化的实际上是引用的对象的值。所以,编译器此时以引用对象的类型作为auto的类型:
int i = 0, &r = i;
auto a = r; //a是int型(r是i的别名,而i是int型)
- 其次,auto一般会忽略顶层const,同时底层const会被保留下来:
const int ci = i, &cr = ci;
auto b = ci; //b是int型(ci的顶层const被忽略)
auto c = cr; //c是int型(cr是ci的别名,ci的顶层const被忽略)
auto d = &i; //d是指向int型的指针
auto e = &ci; //e是指向int型常量的指针
- 如果希望推断出来的是一个顶层const,需要明确的指出:
const auto f = ci; //ci的推演类型是int,而f是const int
- 还可以将引用的类型设置为auto,此时原来的初始化规则仍然适用:
auto &g = ci; //g是一个整型常量引用,绑定到ci
auto &h = 42; //错误,非常量引用不可绑定字面值
const auto &j = 42; //正确,常量引用绑定字面值
设置一个auto的引用的时候,初始值中的顶层常量属性仍然保留
- 要在一条语句中定义多个变量,切记,符号&和*只从属于某个声明符,而非基本数据类型的一部分,因此初始值必须是同一种类型:
auto k = ci, &l = i; //k是int型, l是int型引用
auto &m = ci, *p = &ci; //m是int型常量引用,p是指向int型常量的指针
auto &n = i, *p2 = &ci //错误,n是int型引用,而p2必须是指向int型常量的指针,这里确实指向int型的普通指针
3.decltype类型指示符
有时候会碰到这样的情况,我们想用某个表达式的类型定义某个变量,但是不想用该表达式的值初始化这个变量。C++11给我们提供了decltype说明符,它的作用是返回操作数的数据类型。
decltype处理底层const和引用的方式与auto不同。如果decltype使用的表达式是一个变量,那么decltype返回该变量的类型(包括顶层const和引用在内):
const int ci = 0, &cj = ci;
decltype(ci) x = 0; //x的类型是const int
decltype(cj) y = x; //y的类型是const int &
decltype(cj) z; //错误,z的类型是const int &,必须初始化
下面让我们看一组有趣的情况:
int i = 42, *p = &i, &r = i;
decltype(r + 0) b;
decltype(*p) c
在上述的代码中,decltype(r + 0)返回的类型是int型,这是因为,r作为表达式的一部分,r + 0实际上参与运算的是i + 0,返回的是一个具体的值,而非引用,是int型,但是decltype(r)返回的类型是int &,这点需要明白。
最后一点需要懂得的是,如果decltype使用的是一个不加括号的变量,那么得到的结果是这个变量的类型,一旦加上括号,得到的是引用类型:
decltype((i)) d; //错误,d是一个int &,必须初始化
decltype(i) e; //正确,e是一个为初始化的int型变量
网友评论