文章目录
4.C语言过渡到C++(下)4.1 auto 关键字(C++11)4.1.1 为什么要用 auto?4.1.2 什么是 auto?4.1.3 auto 的使用 4.2 基于范围的 for 循环(C++11)4.3 指针空值 nullptr (C++11) 希望读者们多多三连支持小编会继续更新你们的鼓励就是我前进的动力!
基于当前 C++11 的广泛应用,这里优先介绍几个 C++ 内容,方便后续讲解类和对象及 STL 库?
4.C语言过渡到C++(下)
4.1 auto 关键字(C++11)
4.1.1 为什么要用 auto?
随着后续 C++ 语法的越来越深入,类型的长度可能会越来越长,因为在一些情境下是不允许把全部命名空间全部打开,所以在写类型时可能会遇到以下问题:
• 类型难于拼写
• 含义不明确导致容易出错
⌨️比如后续学到迭代器有这么个类型
std::map<std::string, std::string>::iterator
或许有聪明的人会想到直接用 typedef 给类型取别名不就好了,使用typedef给类型取别名确实可以简化代码,但是 typedef 有会遇到新的难题:
在编程时,常常需要把表达式的值赋值给变量,这就要求在声明变量的时候清楚地知道表达式的类型,然而有时候要做到这点并非那么容易,而且 typedef 只能定死变量的别名,auto 是自动推断的,因此 C++11 给 auto 赋予了新的含义
4.1.2 什么是 auto?
早期的 auto:使用auto修饰的变量,是具有自动存储器的局部变量
C++11 的新 auto:根据该变量初始化表达式的类型来自动确定变量自身的类型
?值得注意的是:auto不再是一个存储类型指示符,而是作为一个新的类型指示符来指示编译器,auto声明的变量必须由编译器在编译时期推导而得
int TestAuto(){return10;}int main(){int a = 10;auto b = a;auto c = 'a';auto d = TestAuto();cout<< typeid(b).name() <<endl;cout<< typeid(c).name() <<endl;cout<< typeid(d).name() <<endl;//auto e; 无法通过编译,使用auto定义变量时必须对其进行初始化return 0;}
这里 typeid().name() 用于输出类型,后续会学到。分别输出 int、char、int
?值得注意的是:使用 auto 定义变量时必须对其进行初始化,在编译阶段编译器需要根据初始化表达式来推导 auto 的实际类型
因此 auto 并非是一种“类型”的声明,而是一个类型声明时的“占位符”,编译器在编译期会将auto替换为变量实际的类型
4.1.3 auto 的使用
?auto 与指针和引用结合起来使用
int main(){ int x = 10; auto a = &x; auto* b = &x; auto& c = x; cout << typeid(a).name() << endl; cout << typeid(b).name() << endl; cout << typeid(c).name() << endl; *a = 20; *b = 30; c = 40; return 0;}
用 auto 声明指针类型时,用 auto 和 auto* 没有任何区别,但用 auto 声明引用类型时则必须加&
?在同一行定义多个变量
void TestAuto(){ auto a = 1, b = 2; auto c = 3, d = 4.0; // 该行代码会编译失败,因为c和d的初始化表达式类型不同}
当在同一行声明多个变量时,这些变量必须是相同的类型,否则编译器将会报错,因为编译
器实际只对第一个类型进行推导,然后用推导出来的类型定义其他变量
?auto 不能作为函数的参数
void TestAuto(auto a){}
此处代码编译失败,auto 不能作为形参类型,因为编译器无法对 a 的实际类型进行推导
?auto 不能直接用来声明数组
void TestAuto(){ int a[] = {1,2,3}; auto b[] = {4,5,6};}
数组在声明时,其类型不仅仅取决于数组元素的类型,还与数组的大小有关,使用auto无法准确传达出这个数组大小的信息
4.2 基于范围的 for 循环(C++11)
?遍历数组的普通方法:
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 循环遍历数组:
void TestFor(){int array[] = { 1, 2, 3, 4, 5 };for(auto& e : array) e *= 2; for(auto e : array) cout << e << " "; return 0;}
解读一下这个代码,就是依次取数组中的数据赋给 e,这样的代码简洁易读
?值得注意的是:该语法糖自动迭代,自动结束;适用于所有数组,后面的容器也会用到;与普通循环类似,可以用continue来结束本次循环,也可以用break来跳出整个循环;数组作为形参时提供的是地址,不能用语法糖
4.3 指针空值 nullptr (C++11)
在良好的C/C++编程习惯中,声明一个变量时最好给该变量一个合适的初始值,否则可能会出现不可预料的错误,比如未初始化的指针,如果一个指针没有合法的指向,我们基本都是按照如下方式对其进行初始化:
void TestPtr(){int* p1 = NULL;int* p2 = 0;// ……}
NULL 实际是一个宏,在传统的 C **头文件(stddef.h)**中
⌨️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,变成调用 f(int),所以为了避免这种情况,创建了一个指针 nullptr 专门代指空指针,之前的 NULL更多当作 0 使用
?值得注意的是:
在使用 nullptr 表示指针空值时,不需要包含头文件,因为 nullptr 是 C++11 作为新关键字引入的在C++11中,sizeof(nullptr) 与 sizeof((void*)0) 所占的字节数相同为了提高代码的健壮性,在后续表示指针空值时建议最好使用 nullptr最近天气好冷,大家注意多穿衣服喝热水保暖?