文章导读
本章为C++修炼之练气期最后一篇,为大家整理了C++11中一些新的语法,也是为接下来C++更深一层学习做个铺垫。本章我们将学习 auto 关键字、范围 for 的使用、nullptr 关键字,一起进入新的学习吧~
正文
auto 关键字
什么是 auto
C++ 中引入了新的关键字 auto
,其作用为自动推导类型
。
例如:
int main() { int a = 0; auto b = a; auto c = &a; //打印变量的类型 cout << typeid(b).name() << endl; cout << typeid(c).name() << endl; return 0; }
auto的使用细则
使用 auto 定义变量时必须对其进行初始化,在编译阶段编译器需要根据初始化表达式来推导auto的实际类型。
因此 auto 并非是一种“类型”的声明,而是一个类型声明时的“占位符”,编译器在编译期会将 auto 替换为变量实际的类型
;
//错误示例 auto a;
- 用 auto 声明
指针类型
时,用 auto 和 auto* 没有任何区别
,但用 auto 声明引用类型
时则必须加&
;
int a = 0; auto b = a; auto c = &a; auto& d = a;
- 当
在同一行声明多个变量
时,这些变量必须是相同的类型
,否则编译器将会报错,因为编译器实际只对第一个类型进行推导
,然后用推导出来的类型定义其他变量。
auto a = 1, b = 2; auto c = 3, d = 4.0; // 该行代码会编译失败,因为c和d的初始化表达式类型不同
auto 不能推导的场景
auto
不能作为函数的参数
;
//错误示例 void Func(auto n) { //... }
auto
不能直接用来声明数组
;
//错误示例 auto arr[] = { 1,2,3 };
- 为了避免与
C++98
中的auto
发生混淆,C++11
只保留了auto
作为类型指示符
的用法; auto
在实际中最常见的优势用法就是接下来会讲到的 C++11 提供的新式for循环
,还有lambda 表达式
等进行配合使用;
基于范围的 for 循环
在C++98
中如果要遍历一个数组,可以按照以下方式进行:
void TestFor() { int array[] = { 1, 2, 3, 4, 5 }; for (int i = 0; i < sizeof(array) / sizeof(array[0]); ++i) array[i] *= 2; for (int* p = array; p < array + sizeof(array) / sizeof(array[0]); ++p) cout << *p << endl; }
对于一个有范围的集合而言,由程序员来说明循环的范围是多余的,有时候还会容易犯错误。因此C++11
中引入了基于范围的for循环
。
范围 for 的语法
for 循环后的括号由冒号 :
分为两部分:第一部分是范围内用于迭代的变量
,第二部分则表示被迭代的范围
。例如:
void TestFor() { int array[] = { 1, 2, 3, 4, 5 }; for (auto& e : array) e *= 2; for (auto e : array) cout << e << " "; }
范围 for 的使用条件
- for 循环
迭代的范围
必须是确定的; - 迭代的对象要实现
++
和==
的操作;
对于数组
而言,就是数组中第一个元素
和最后一个元素
的范围;对于类
而言,应该提供begin
和end
的方法,begin和end就是for循环迭代的范围。
//错误示例 void TestFor(int array[]) { for (auto& e : array) cout << e << endl; }
nullptr 关键字
在 C++98 中,我们一般这样初始化指针变量:
int* p = NULL;
NULL实际是一个宏
,在传统的 C头文件stddef.h
中,可以看到如下代码:
#ifndef NULL #ifdef __cplusplus #define NULL 0 #else #define NULL ((void *)0) #endif #endif
可以看到,NULL可能被定义为字面常量0
,或者被定义为无类型指针(void*)
的常量。不论采取何种定义,在使用空值的指针时,都不可避免的会遇到一些麻烦,比如:
void f(int) { cout << "f(int)" << endl; } void f(int*) { cout << "f(int*)" << endl; } int main() { f(0); f(NULL); f((int*)NULL); return 0; }
程序本意是想通过f(NULL)调用指针版本的f(int*)函数,但是由于NULL被定义成0,因此与程序的初衷相悖。
在C++98中,字面常量0既可以是一个整形数字,也可以是无类型的指针(void*)常量,但是编译器默认情况下将其看成是一个整形常量,如果要将其按照指针方式来使用,必须对其进行强转(void*)0。
为了避免出现类似的问题,C++11 中引进了新的关键字 nullptr ,为了提高代码的健壮性,在后续表示指针空值时建议最好使用 nullptr 。