类型别名
类型别名是一个名字,它是某种类型的同义词。使用类型别名可以使复杂的类型名字变得简单明了、易于使用。c++有两种方法用于定义类型别名:typedef和using。
typedef
1 | typedef double wages; //wages是double的同义词 |
2 | typedef wages base,*p; //base是double的同义词,p是double*的同义词 |
关键字typedef作为声明语句中的基本数据类型的一部分出现,含有typedef的声明语句定义的不再是变量而是类型别名。
using
c++11规定了新的别名声明关键字using。
1 | using wages = double; //wagess是double的同义词 |
2 | using p = *double; //p是double*的同义词,即指向double的指针 |
声明成类型别名之后,其基本数据类型可能会发生改变,如果直接将类型别名替换成原本的样子进行理解,可能会发生错误。
1 | using pstring = *char; //pstring表示指向字符的指针 |
2 | const pstring p = nullptr; //p是一个常量指针,不能将其理解为const char*,即指向字符常量的普通指针 |
自动类型
auto
c++11引入了auto类型说明符,让编译器去分析表达式的初始值来推断类型,因此auto定义的变量必须具有初始值。
1 | auto item = item1 + item2; //有item1和item2相加的结果推断出item的类型 |
使用auto也能在一条语句中声明多个变量,因为一条声明语句只能有一个基本数据类型,所以该语句中所有变量的初始基本数据类型必须一致。
1 | auto i = 0,*p = &i; //正确,i是整数,p是整型指针 |
2 | auto sz = 0,pi = 3.14; //错误,sz和pi的基本数据类型不一致 |
编译器推断出来的auto类型可能和初始值的类型并不完全一样,编译器会适当改变结果类型使其更符合初始化规则:
1、对于引用类型作为初始值,编译器以引用对象的类型作为auto的类型。
1 | int i = 0,&r = i; |
2 | auto a = r; //a的类型为int |
2、auto一般会忽略顶层const,保留底层const
1 | const int ci = 0,&cr = &ci; //i是一个整型常量,cr是一个常量引用 |
2 | auto b = ci; //b是一个整数,ci的顶层const被忽略 |
3 | auto c = cr; //c是一个整数,cr是ci的引用,而ci的顶层const被忽略 |
4 | auto d = &ci; //d是一个指向整数常量的指针,对常量对象取地址是一种底层const |
5 | //如果希望推断出的auto类型是一个顶层const,需要明确指出 |
6 | const auto e = ci; //ci的推演类型是int,而e的类型是const int |
如果将引用(或者指针)的类型设置为auto,初始值中的顶层const属性仍然保留,此时在引用(或者指针)中转化为了底层const。
1 | auto &f = ci; //f是一个常量引用,绑定到ci |
2 | auto &g = 1; //错误,不能为非常量引用绑定字面值 |
3 | const auto &h = 1; //正确,可以外常量引用绑定字面值 |
要在一条语句中定义多个变量,需要切记,符号&和*只从属于某个声明符,而非基本数据类型的一部分,因此初始值必须是同一种类型。
1 | //auto的基本数据类型都是int,j是整型,k是整型引用 |
2 | auto j = ci,&k = i; |
3 | //auto的基本数据类型都是const int,m是对整型常量的引用,p是指向整型常量的指针 |
4 | auto &m = ci,*p = &ci; |
5 | //错误,i的基本数据类型是int,而ci是基本数据类型是const int |
6 | auto &n = i,*p = &ci; |
decltype
如果希望从表达式的类型推断出要定义的变量的类型,但是不想用该表达式的值初始化变量,为了满足这类需求,c++11引入了decltype,它的作用是选择并返回操作数的数据类型,在此过程中,编译器分析表达式并得到它的类型,却不实际计算表达式的值。
1 | decltype(f()) sum = x; //sum的类型就是函数f()的返回类型 |
decltype处理顶层const和引用(或者指针)的方式与auto有所不同。
1、如果decltype使用的表达式是一个变量,那么该变量是什么类decltype就返回什么类型(包括顶层const和引用)。
1 | const int ci = 1,&cr = ci; |
2 | decltype(ci) x = 0; //x的类型是const int |
3 | decltype(cr) y = x; //y的类型是const int&,y绑定到x上 |
4 | decltype(cr) z; //错误,z是一个引用,必须初始化 |
注意:引用从来都是作为其所指对象的同义词出现的,只有用来decltype时是一个列外。
2、如果decltype使用的表达式不是一个变量,则decltype返回表达式结果对应的类型。
1 | int i = 1,*p = &i,&r = i; |
2 | decltype(r+0) b; //加法的结果是int类型,因此b的类型是int |
3 | decltype(*p) c; //错误,解引用的结果是引用类型,因此c的类型是int&,必须初始化 |
如果decltype使用的表达式是一个加了括号的变量,编译器会把它当成是一个表达式,此时得到的是引用类型。
1 | decltype((i)) d; //错误,d是int&,必须初始化 |
2 | decltypr(i) e; //正确,e是int |