类型别名声明
-
类型别名是一个名字,它是某种类型的同义词。
- 使用类型别名的用处:让复杂的类型名字变得简单明了、易于理解和使用,还有助于程序员清楚地知道使用该类型的真实目的。
-
有两种方法可用于定义类型别名。(1)关键字typedef;(2)别名声明using。
-
关键字typedef:含有typedef的声明语句定义的不再是变量而是类型别名。
- (注意!!!)typedef是有作用域的。例如typedef double DOU;在size()函数中有效,但在main()函数中无效。
#include<iostream>
using namespace std;
typedef double DOUBLE;
void size() {
typedef double DOU;
DOU d = 12.121212;
cout << d << endl;
}
int main(int argc, char* argv[]) {
DOUBLE d = 12.121212;
cout << d << endl;
//DOU d = 12.121212; //错误:未定义标识符"DOU"
getchar();
return 0;
}
-
别名声明(using 声明)来定义类型别名:
- (注意!!!)using声明是有作用域的。例如using DOU = double;在size()函数中有效,但在main()函数中无效。
#include<iostream>
using namespace std;
using DOUBLE = double;
void size() {
using DOU = double;
DOU d = 12.121212;
cout << d << endl;
}
int main(int argc, char* argv[]) {
DOUBLE d = 12.121212;
cout << d << endl;
//DOU d = 12.121212; //错误:未定义标识符"DOU"
size();
getchar();
return 0;
}
auto类型说明符
-
编程时常常需要把表达式的值赋给变量,这就要求在声明变量的时候清楚地知道表达式的类型。但在实际应用中,能够清楚地获知表达式的类型并不容易。为了解决这个问题,C++11新标准引入了auto类型说明符,用它就能让编译器替我们去分析表达式所属的类型。
-
auto让编译器通过初始值来推算变量的类型。显然,auto定义的变量必须有初始值:
#include<iostream>
using namespace std;
int main(int argc, char* argv[]) {
//auto i; //无法推导"auto"类型(需要初始值设定项)
int a1 = 10;
double a2 = 10.5;
auto res = a1 + a2; //res的类型为double
cout << res << endl; //20.5
getchar();
return 0;
}
-
复合类型、常量和auto:编译器推断出来的auto类型有时候和初始值的类型并不完全一样,编译器会适当地改变结果类型使其更符合初始化规则。
-
首先,使用引用其实就是使用引用的对象,特别是当引用被用作初始值时,真正参与初始化的其实是引用对象的值。此时编译器以引用对象的类型作为auto的类型:
#include<iostream>
using namespace std;
int main(int argc, char* argv[]) {
int i = 0, &r = i;
auto a = r; //a的类型为int
getchar();
return 0;
}
-
其次,auto一般会省略顶层const,同时底层const则会保留下来,比如当初始值是一个指向常量的指针时:
- (注意!!!)语句auto e = &ci;中, e是一个指向整数常量的指针(对常量对象取地址是一种底层const)
#include<iostream>
using namespace std;
int main(int argc, char* argv[]) {
int i = 0, &r = i;
const int ci = i, &cr = ci;
auto b = ci; //b是一个整数(ci的顶层const特性被忽略了)
auto c = cr; //c是一个整数(cr是ci的别名,ci本身是一个顶层const,顶层const特性被忽略了)
auto d = &i; //d是一个整型指针(整数的地址就是指向整数的指针)
auto e = &ci; //e是一个指向整数常量的指针(对常量对象取地址是一种底层const)
getchar();
return 0;
}
- 如果希望推出来的类型是一个顶层const,需要明确指出:
const int ci = 10;
const auto f = ci; //ci的推演类型是int,f是const int
decltype类型指示符
-
有时候,希望从表达式的类型推断出要定义的变量的类型,但是不想用该表达式的值初始化变量。
-
C++11新标准引入了第二种类型说明符decltype,作用:选择并返回操作数的数据类型。
扫描二维码关注公众号,回复: 3887730 查看本文章 -
decltype处理顶层const和引用的方式与auto有些许不同。
-
如果decltype使用的表达式是一个变量,则decltype返回该变量的类型。
#include<iostream>
using namespace std;
int main(int argc, char* argv[]) {
int i = 0, &r = i;
const int ci = i, &cr = ci;
decltype(ci) x = 0; //x的类型是const int
decltype(cr) y = x; //y的类型是const int&
//decltype(cr) z; //错误:z是一个引用,必须初始化
getchar();
return 0;
}
-
如果decltype使用的表达式不是一个变量,则decltype返回表达式结果对应的类型。
-
如果表达式的内容是解引用操作,则decltype将得到引用类型。正如我们所熟悉的,解引用指针可以得到指针所指的对象,而且还能给这个对象赋值。因此,decltype(*p)的结果类型是int&,而非int。
#include<iostream>
using namespace std;
int main(int argc, char* argv[]) {
int i = 42, *p = &i, &r = i;
decltype(r + 0) b; //正确:加法的结果是int,因此b是一个(未初始化的)int
//decltype(*p) c; //错误:c是int&,必须初始化
getchar();
return 0;
}
- 切记:decltype((variable))(注意是双层括号)的结果永远是引用,而decltype(variable)结果只有当variable本身就是一个引用时才是引用。
#include<iostream>
using namespace std;
int main(int argc, char* argv[]) {
int i = 10;
//decltype((i)) d; //错误:d是int&,必须初始化
decltype(i) e; //正确:e是一个(未初始化的)int
getchar();
return 0;
}