• C++特性——auto关键字、范围for、指针空值nullptr


    本篇是关于C++特性的最后一篇。在前面我们学习了C++引用、I/O流、inline内联函数等诸多特性。如果感兴趣,可以看看:
    👉C++特性——命名空间、I/O流以及缺省参数
    👉C++特性——引用与指针详解
    👉C++特性——inline内联函数

    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}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    我们发现,变量stst_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;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    output:

    struct lwj::Stack
    struct lwj::Stack
    int
    int
    double
    
    • 1
    • 2
    • 3
    • 4
    • 5

    1.2 关于auto关键字的细节

    1. 使用auto关键字必须初始化

      auto num;
      //会报错:“num”: 类型包含“auto”的符号必须具有初始值设定项
      
      • 1
      • 2

      这是因为:

      在编译阶段编译器需要根据初始化表达式来推导auto的实际类型。因此auto并非是一种“类型”的声明,而是一个类型声明时的“占位符”,编译器在编译期会将auto替换为变量实际的类型。

    2. 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;
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9

      output:

      int *
      int *
      int
      
      • 1
      • 2
      • 3
    3. 在同一行定义多个变量

      在同一行用auto关键字定义多个变量时,这些变量必须是相同的类型。例如:

      auto num1 = 1, num2 = 2.0;
      /*
      会报错:
          error C3538: 在声明符列表中,“auto”必须始终推导为同一类型
          message : 可能是“int”
          message : 或    “double”
      */
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
    4. auto关键字不能做函数形参

      例如:

      void Func(auto num1){}
      //会报错:参数不能为包含“auto”的类型
      //因为auto并不能确定num1的类型
      
      • 1
      • 2
      • 3
    5. auto关键字不能声明数组

      例如:

      auto Num[3] = { 1, 2, 3 };
      //会报错:
      /*
      	“auto [3]”: 数组不能具有其中包含“auto”的元素类型
      	error C3535: 无法推导“auto [3]”的类型(依据“initializer list”)
      	error C2440: “初始化”: 无法从“int”转换为“std::initializer_list”
      	message : 无构造函数可以接受源类型,或构造函数重载决策不明确
      */
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8

    2. 范围for

    在C++中,我们可以用这样一个循环来输出一个数组:

    int Num[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
    
    for (auto i : Num)
    {
        cout << i << ' ';
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 这样的for循环叫做范围for
    • for (auto i : Num)中,:前的内容表示用于范围内迭代的变量,例如上面的代码,就是依次取数组Num的数据赋值给i
    • :后的内容就表示循环迭代的范围

    我们可以用下面的操作实现将数组内的每个数变为原来的两倍

    //将用于迭代的变量声明为引用,这样每次迭代i就是数组内每个数据的别名
    for (auto& i : Num)
    {
        i *= 2;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    output:

    int
    int*
    
    • 1
    • 2

    这下有些小伙伴就会疑惑了:

    以前我们学习C语言时,初始化指针变量都是这么定义的:int* ptr = NULL。我们用NULL初始化指针变量,为什么**NULL会被认定为整形**呢?

    • 实际上,NULL实际上是库中的宏定义

      #define NULL 0
      
      • 1
    • 我们也可以用typeid来查看一下NULL的类型:

      cout << typeid(NULL).name() << endl;
      
      • 1

      output:

      int
      
      • 1

    因此,为了避免上述的尴尬,在C++中,如果要让一个指针为空时,我们可以用关键字nullptr。例如:

    int* ptr = nullptr;
    
    • 1

    至此,关于C++的特性我们就已经有了基本的了解。
    下一个篇章,我们将开启对C++类和对象的学习,感兴趣的小伙伴可以订阅此专栏。
    本篇完。

  • 相关阅读:
    删除word最后一页之后的空白页
    【转载】快速搭建OpenGL环境!!!Windows10 + Visual Studio 2019 搭建OpenGL环境
    虚拟环境与Django版本区别
    LeetCode 四数相加II 哈希
    SpringBoot访问静态资源
    仿热血江湖游戏类43
    (一)devops持续集成开发——jenkins安装及基本使用
    python连接redis库
    【数据结构】二叉树的遍历
    【Java】常用API——Object、StringBuilder、包装类
  • 原文地址:https://blog.csdn.net/l315225/article/details/134010243