类型别名
我们可以为类型引入别名,从而引入特殊的含义或者便于使用,比如size_t
。通常来说,引入类型别名有两种方式
typedef
typedef int MyInt;
using
(从C++11开始)using MyInt = int;
使用using
要比typedef
更加优化易读,比如
typedef char MyCharArr[4]; // 读起来比较混乱
using MyCharArr = char[4]; // 读起来清晰明了
我们需要区分类型别名与指针、引用之间的关系
- 应该将指针的类型别名认为视为一个整体,在此基础上如果引入了常量则代表常量指针而不是指向常量的指针,比如
using IntPtr = int *; int x = 3; const IntPtr ptr = &x; // const修饰整个Int * int y = 4; ptr = &y; // 这里会报编译错误
注意这里的
const IntPtr ptr
本质上的类型为int * const
而不是const int *
- 不能通过类型别名构造引用的引用,比如
using RefInt = int &; using RefRefInt = RefInt&; // 这里的类型同样为int &
类型的自动推导
从C++11开始,我们可以通过初始化表达式自动推导对象的类型,比如
auto x = 3.5 + 15l;
但是,我们需要明白自动推导类型并不意味着弱化类型,我们推导出来的对象还是强类型,从类型推导出来之后类型就确定了,后续不可以更改类型
自动推导有几种常见的形式:
-
auto:最常见的形式,但是可能会产生类型退化,比如
int x1 = 3; int & ref = x1; auto ref2 = ref; // 这里的int&退化成了int
-
const auto/constexpr auto:推导出的是常量/常量表达式类型
-
auto &:推导出引用类型,同时避免了类型退化,比如
int x[3] = {1,2,3}; auto x1 = x; // 类型为int* auto & x2 = x; // 类型为 int(&)[3]
-
decltype(exp):返回
exp
对应的表达式的类型,但是不会产生退化,比如decltype(3.5+15l) x = 3.5+15l;
但是需要注意,如果其中的exp是左值的话,decltype会自动加一个引用类型,比如
int x = 3; int * ptr = &x; decltype(*ptr); // 这里的类型为int &
同时还需要注意,如果exp是一个变量名称,那么decltype只会推导出变量的类型,不会添加引用,比如
int x = 3; decltype(x) // 这里的类型为int
如果想要让他加引用的话我们可以对在变量名称外加一个
()
,比如int x = 3; decltype((x)) // 这里的类型为int &
-
decltype(auto):从C++14开始引入,简化了decltype的使用,比如
decltype(3.5+15l) x = 3.5+15l;
可以被简化为
decltype(auto) x = 3.5+15l;
这样做既避免auto引入的类型退化,也避免了decltype必须要重复书写表达式的问题
-
concept auto:从C++20开始支持,表示了一系列的类型,对auto的自动类型推导引入了类型限制,比如
std::integral auto x = 3; //类型为int std::integral auto x = 3.5; //报错,因为3.5不属于整型这个concept
域
域(scope)表示了程序中的一部分,其中的名称
有唯一的意义,比如
void fun(){
int x = 3
}
int main(){
int x = 3;
}
其中的两个x属于不同的域,所以不会发生重复定义的问题。
域分为很多中,典型的比如:
- 全局域(global scope):程序最外围的域,其中定义的是全局对象
- 块域(block scope):使用
{}
所限定的域,其中定义的是局部对象 - 类域、命名空间域等等
域可以进行嵌套,嵌套域中的名称会隐藏,比如
{
int x = 3;
{
int x = 5;
std::cout << x << std::endl; //这里输出的一定是5
}
}
对象的生命周期
对象的生命周期起始于被初始化的时刻,终止于被销毁的时刻,结合域来说的话就是
- 全局对象的生命周期是整个程序的运行期间(广义的概念,不同的全局对象的生命周期根据初始化的顺序有所不同)
- 局部对象的生命周期起始于被初始化的时刻,终止于所在域被执行完成后,比如
{ int x = 3; { std::cout << x << std::endl; //这里输出的一定是3 int x = 5; } }