1. auto关键字
在写代码时,我们常常会遇到定义变量时变量的类型名太长的情况,例如:
namespace lwj { struct Stack { Stack() { _a = nullptr; _top = 0; } int* _a; int _top; }; } int main() { lwj :: Stack st; lwj :: Stack st_bak = st; return 0; }
我们发现,变量st
、st_bak
的类型名实在是太长了,有没有什么办法解决呢?
C++引入了auto
这个关键字来解决这个问题。
7.1 auto的功能
auto
关键字可以自动识别变量的类型。
例如:
lwj :: Stack st; auto st_bak = st; int a = 1; auto a_bak = a; auto b = 1.0; //typeid可以打印一个变量的类型 cout << typeid(st).name() << endl; cout << typeid(st_bak).name() << endl; cout << typeid(a).name() << endl; cout << typeid(a_bak).name() << endl; cout << typeid(b).name() << endl;
output:
struct lwj::Stack struct lwj::Stack int int double
1.2 关于auto关键字的细节
- 使用
auto
关键字必须初始化:
auto num; //会报错:“num”: 类型包含“auto”的符号必须具有初始值设定项
- 这是因为:
在编译阶段编译器需要根据初始化表达式来推导auto的实际类型。因此auto并非是一种“类型”的声明,而是一个类型声明时的“占位符”,编译器在编译期会将auto替换为变量实际的类型。
- 用
auto
关键字初始化指针变量时,*
可带可不带:声明引用时,&
必须带上
int a = 1; auto ptr = &a; auto* ptr_bak = &a; auto& num = a; cout << typeid(ptr).name() << endl; cout << typeid(ptr_bak).name() << endl; cout << typeid(num).name() << endl;
- output:
int * int * int
- 在同一行定义多个变量
在同一行用auto
关键字定义多个变量时,这些变量必须是相同的类型。例如:
auto num1 = 1, num2 = 2.0; /* 会报错: error C3538: 在声明符列表中,“auto”必须始终推导为同一类型 message : 可能是“int” message : 或 “double” */
auto
关键字不能做函数形参
例如:
void Func(auto num1){} //会报错:参数不能为包含“auto”的类型 //因为auto并不能确定num1的类型
auto
关键字不能声明数组
例如:
auto Num[3] = { 1, 2, 3 }; //会报错: /* “auto [3]”: 数组不能具有其中包含“auto”的元素类型 error C3535: 无法推导“auto [3]”的类型(依据“initializer list”) error C2440: “初始化”: 无法从“int”转换为“std::initializer_list<int>” message : 无构造函数可以接受源类型,或构造函数重载决策不明确 */
2. 范围for
在C++中,我们可以用这样一个循环来输出一个数组:
int Num[] = { 1, 2, 3, 4, 5, 6, 7, 8 }; for (auto i : Num) { cout << i << ' '; }
- 这样的for循环叫做
范围for
for (auto i : Num)
中,:
前的内容表示用于范围内迭代的变量,例如上面的代码,就是依次取数组Num
的数据赋值给i
:
后的内容就表示循环迭代的范围。
我们可以用下面的操作实现将数组内的每个数变为原来的两倍:
//将用于迭代的变量声明为引用,这样每次迭代i就是数组内每个数据的别名 for (auto& i : Num) { i *= 2; }
2.1 限制条件
要使用范围for
,就要确保迭代的范围时明确的。
例如下面的用法就是错误的:
void Print(int* nums) { //nums是一个指针,没有明确的迭代范围。用法错误 for (int i : nums) cout << i << ' '; } int main() { int Num[] = { 1, 2, 3, 4, 5, 6, 7, 8 }; Print(Num); return 0; }
3. 指针空值nullptr
先来看下面的代码:
void Func(int* ptr) { cout << "int*" << endl; } void Func(int num) { cout << "int" << endl; } int main() { Func(NULL); Func((int*)NULL); return 0; }
output:
int int*
这下有些小伙伴就会疑惑了:
以前我们学习C语言时,初始化指针变量都是这么定义的:int* ptr = NULL
。我们用NULL
初始化指针变量,为什么**NULL
会被认定为整形**呢?
- 实际上,
NULL
实际上是库中的宏定义:
#define NULL 0
- 我们也可以用
typeid
来查看一下NULL
的类型:
cout << typeid(NULL).name() << endl;
- output:
int
因此,为了避免上述的尴尬,在C++中,如果要让一个指针为空时,我们可以用关键字nullptr
。例如:
int* ptr = nullptr;
至此,关于C++的特性我们就已经有了基本的了解。
下一个篇章,我们将开启对C++类和对象的学习,感兴趣的小伙伴可以订阅此专栏。
本篇完。