现代c++(2)

本文概述了C++11引入的关键特性,如初始化块、限定作用域枚举、final关键字、override和=default等,展示了如何提升代码可读性和编译时检查。此外,还介绍了auto、range-based循环、结构化绑定等高级特性,以及STL容器的新方法,如emplace和try_emplace。

现代c++ 新特性

  • C++11标准中,我们可以使用花括号(即{})对任意类型的变量,无论是局部变量还是类变量进行初始化,而且不用是static类型。
    • *统一的类成员初始化语法 std::initializer_list
  • enumerator
      enum class Color{
          black,
          white,
          yellow
      }
    
    • 由于枚举值white对外部不可见(必须通过Color::white引用),所以可以定义一个同名的white变量。这种枚举变量被称为限定作用域的枚举。
  • C++11新增的一组非常具有标记意义的关键字和语法
    • final

      • final 关键字修饰一个类,这个类将不允许被继承
        class A final {
        };
        
    • override
      C++语法规定,在父类中加了virtual关键字的方法可以被子类重写,子类重写该方法时可以加或不加virtual关键字,
      可能会带来以下两个问题。

      • 当我们阅读代码时,无论子类重写的方法是否添加了virtual关键字,我们都无法直观地确定该方法是否是重写的父类方法。

      • 如果我们在子类中不小心写错了需要重写的方法的函数签名(可能是参数类型、个数或返回值类型),这个方法就会变成一个独立的方法,这可能会违背我们重写父类某个方法的初衷,而编译器在编译时并不会检查到这个错误。

      • 子类方法被 override 关键字修饰,表明该方法重写了父类的同名方法,加了该关键字后,编译器会在编译阶段做相应的检查,如果其父类不存在相同签名格式的类方法,编译器就会给出相应的错误提示。

          正确使用方法
          class A {
            protected:
              virtual void func( int k, int d)
              {
        
              }
          };
           class B :A {
             protected:
              virtual void func(int k, int d) override{
                
              }
           }
        
    • =default

      • 如果一个 C++类没有显式给出构造函数、析构函数、拷贝构造函数、operator=这几类函数的实现,则在需要它们时,编译器会自动生成;或者,在给出这些函数的声明时,如果没有给出其实现,则编译器在链接时会报错。如果使用=default标记这类函数,则编译器会给出默认的实现。
      • =default 最大的作用可能是在开发中简化了构造函数中没有实际初始化代码,“尤其是声明和实现分别属于.h和.cpp文件”
          使用方法
          //a.h
          class A {
            public:
              A() =default();
              ~A()=default();
          };
          //a.cpp
          #include "a.h"
          //不用再写构造函数和析构函数的实现了
        
    • =delete

      • 既然有强制让编译器生成构造函数、析构函数、拷贝构造函数、operator=的语法,那么也应该有禁止编译器生成这些函数的语法,没错,就是=delete。
        在C++98/03规范中,如果我们想让一个类不能被拷贝(即不能调用其拷贝构造函数),则可以将其拷贝构造函数和operator=函数定义成private

        使用方法
        class A {
          public:
            A() =default();
            ~A()=default();
          public:
            A(const A& a)= delete;
            A& operator =(const A& a)=delete;
        };
        
    • auto

      • C++11新标准中修改了其用法,让编译器自己推导一些变量的数据类型,auto 一般用于让编译器自动推导一些复杂的模板数据类型,以简化语法

          std::map<std::string,std::string> sessons;
          session["first"]="001";
          for (std::map<std::string,std::string>::iterator iter = session.begin();iter!=session.end();iter++)
          {
            std::cout<<iter->second<<std::endl;
          }
          for (auto iter = session.begin();iter!=session.end();iter++)
          {
            std::cout<<iter->second<<std::endl;
          }
        
    • Range-based循环语法

      • 在C++98/03规范中,对于一个数组int arr[10],如果我们想要遍历这个数组,则只能使用递增的计数去引用数组中的每个元素for(int i = 0; i<10;i++){}

      • 在C++11规范中有了for-each语法,可以这么写:

          int arr[10]={0};
          for (int i: arr)
          {
            std::cout<<arr[i]<<std::endl;
          }
          std::map<std::string,std::string> sessons;
          session["first"]="001";
          for (auto iter: sessons)
          {
            std::cout<<iter.second<<std::endl;
          }
        
      • for-each 语法中,iter 与容器中元素的数据类型(std::pair<std::string,std::string>)相同,因此使用iter.second可直接引用键值。

      • for-each 语法中,对于复杂的数据类型,迭代器是原始数据的拷贝,而不是原始数据的引用。

        • 解决方法 `for (auto& iter: sessons)
      • 自定义对象支持for-each语法:

        • 至少实现 Iterator begin();Iterrator end();
    • 结构化绑定

      • 与定义结构体相比,无论是通过std::pair的first、second还是std::tuple的std::get方法来获取元素子属性,这些代码都是难以维护的,其根本原因是 first和second这样的命名不能做到见名知意。
      • 结构化绑定语法
      auto [a,b,c] = expression;
      auto [a,b,c] {expression};
      auto [a,b,c...](expression);
      
      ep1:
         auto [iterator,inserted] = someMap.insert(...);
      ep2:
        double myArray[3]={1.0,2.0,3.0};
        auto[a,b,c]=myArray;
      ep3:
        struct Point{
          double x;
          double y;
        };
        Point myPoint(10.0,20.0);
        auto[myX,myY]= myPoint;
        const auto& [myX,myY]= myPoint;
      
      • 当绑定类型不是基础数据类型时,如果你的本意不是想要得到绑定目标的副本,则为了避免拷贝带来的不必要开销,建议使用引用;如果不需要修改绑定目标,则建议使用const引用。
          std::map<std::string,int> cities;
          cities["beijing"]=0;
          for (const auto&[city,cityNum] : cities)
          {
            std::cout<<city<<cityNum<<std::endl;
          }
      
      • 用于结构化绑定的变量不能使用constexpr修饰或声明为static
    • stl容器新增的实用方法

      • 原位构造元素 emplace和emplace_back

        • 在一个循环里产生一个对象,然后将这个对象放入集合中,这样的代码在实际开发中太常见了。但是这样的代码存在严重的效率问题:循环中的t对象在每次循环时,都分别调用了一次构造函数、拷贝构造函数和析构函数,但实际上,我们的初衷是创建一个对象t,将其直接放入集合中,而不是将t作为一个中间临时产生的对象,调用t的构造函数1次就可以了。C++11提供了一个在这种情形下替代 push_back 的方法——emplace_back。通过使用emplace_back,可以将main函数中的代码改写如下:
        
         std::list<Test> testList;
         for (int i=0;i<10;++i)
         {
           // Test t(1*i,2*i,3*i);
           // testList.push_back_back(t);
           testList.emplace_back(1*i,2*i,3*i);
         }
        

        经过以上改写,在实际执行时只需调用Test类的构造函数10次,大大提高了执行效率。

      • c++17 std::map的try_emplace方法与insert_or_assign方法

        std::map<std::string,int> mapUsersAge{{"aa",1},{"bb",2}};
        mapUsersAge.try_emplace("TOM",26);
        mapUsersAge.insert_or_assign("TOM",26);
      
现代C++程序设计(原书第2)》图文并茂,通俗易懂,真正做到寓教于乐,是一本难得的C++面向对象设计入门教材。 出版者的话 译者序 前言 第1章 C++概述与软件开发 1.1 什么是C语言C++ 1.1.1 C和C++历史回顾 1.1.2 C/C++是一门编译语言 1.1.3 为什么许多程序员都选择C++ 1.2 什么是面向对象 1.2.1 C++程序并不一定是面向对象的 1.2.2 一个简单的面向对象程序示例 1.2.3 面向对象的软件更有优势 1.3 结构化设计与面向对象设计 1.3.1 ATM——结构化设计 1.3.2 采用面向对象方法的ATM——究竟是谁的任务 1.3.3 汽车维护——结构化设计 1.3.4 采用面向对象方法的汽车维护——究竟是谁的任务 1.4 软件开发技术概述 1.5 问题发现与解决 复习题 第2C++的入门知识 2.1 编程基础 2.1.1 算法设计 2.1.2 正确的软件开发步骤 2.2 专业术语及工程创建 2.3 C++程序的一般格式 2.3.1 “Hello World!”程序 2.3.2 “How’s the Weather?”程序 2.4 程序的数据及数据类型 2.4.1 C++的数据类型 2.4.2 容器=数据类型,标签=变量名 2.4.3 数据类型修饰符 2.4.4 问题分析:整型数据究竟有多大 2.5 C++中的变量声明 2.5.1 C++的命名规则 2.5.2 在哪里声明变量 2.6 C++中的运算符 2.6.1 计算路程的程序 2.6.2 从键盘输入程序所需数据 2.6.3 赋值运算符 2.6.4 运算符的优先级 2.6.5 数据类型及其存储的值 2.6.6 算术运算符 2.6.7 自增运算符和自减运算符 2.6.8 复合赋值运算符 2.7 #define、const和数据类型转换 2.7.1 #define预处理指令 2.7.2 const修饰符 2.7.3 const比#define好吗 2.7.4 数据类型转换 2.8 关于键盘输入和屏幕输出的更多内容 2.8.1 转义序列 2.8.2 ios格式标记 2.8.3 流的IO控制符 2.9 开始使用类和对象、C++string类 2.10 练习 复习题 第3章 控制语句和循环 3.1 关系运算符和逻辑运算符 3.2 if语句 3.2.1 if-else语句 3.2.2 问题分析:在if语句中使用大括号 3.2.3 if-else if-else语句 3.2.4 低效的编程方法 3.2.5 if-else程序示例 3.2.6 嵌套if-else语句 3.2.7 条件运算符“?” 3.3 switch语句 3.4 循环 3.4.1 括号的用法 3.4.2 无限循环 3.5 for循环 3.5.1 不要改变循环索引 3.5.2 for循环示例 3.6 while循环 3.7 do while循环 3.8 跳转语句 3.8.1 break语句 3.8.2 continue语句 3.9 问题发现与解决 3.9.1 五个常见错误 3.9.2 调试程序 3.10 C++类与vector类 3.11 总结 3.12 练习 复习题 第4章 函数一:基础 4.1 C++中的函数 4.1.1 只由一个main函数构成的程序 4.1.2 包含多个函数的程序 4.1.3 函数是个好东西 4.1.4 三个重要的问题 4.2 函数:基本格式 4.3 函数的编写要求 4.3.1 你想住在C++旅馆中吗 4.3.2 函数为先 4.3.3 函数声明或函数原型 4.3.4 函数定义、函数标题行与函数体 4.3.5 函数调用 4.3.6 传值调用 4.3.7 问题分析:未声明的标识符 4.4 重载函数 4.5 具有默认输入参数列表的函数 4.6 局部变量、全局变量和静态变量 4.6.1 局部变量 4.6.2 块范围 4.6.3 全局变量 4.6.4 危险的全局变量 4.6.5 问题分析:全局变量y0、y1与cmath 4.6.6 静态变量 4.7 C++stringstream类 4.8 总结 4.9 练习 复习题 第5章 函数二:变量地址、指针以及引用 5.1 数据变量和内存 5.1.1 sizeof运算符 5.1.2 预留内存 5.1.3 计算机内存和十六进制 5.2 取地址运算符& 5.3 指针 5.4 函数、指针以及间接运算符 5.4.1 解决思路 5.4.2 指针和函数 5.4.3 有效处理大型数据 5.5 函数和引用 5.5.1 复习:两种机制 5.5.2 为什么要强调指针的重要性 5.6 queue类 5.7 总结 5.8 练习 复习题 第6章 数组 6.1 使用单个数据变量 6.2 数组基础 6.2.1 数组的索引值从0开始 6.2.2 使用for循环和数组来实现的电话账单程序 6.2.3 数组的声明和初始化 6.2.4 数组越界==严重的问题 6.2.5 vector与数组的比较 6.3 数组和函数 6.3.1 每个数组都有一个指针 6.3.2 数组指针 6.3.3 向函数传递数组:最开始的引用调用 6.3.4 利用数组和函数生成随机数并进行排序 6.4 C字符串,也称为字符数组 6.4.1 字符数组的初始化 6.4.2 null字符 6.4.3 C字符串的输入 6.4.4 C++中提供的字符数组函数 6.5 多维数组 6.5.1 二维数组的初始化 6.5.2 嵌套的for循环和二维数组 6.5.3 利用二维数组来实现Bingo游戏 6.6 多维数组和函数 6.6.1 改进的Bingo卡片程序 6.6.2 白雪公主:利用二维数组来存储姓名 6.7 利用数据文件对数组赋值 6.8 总结 6.9 练习 复习题 第7章 类和对象 7.1 我们所了解的类和对象 7.2 编写自己的类 7.2.1 入门实例:自定义日期类 7.2.2 第一个C++类:Date类 7.2.3 揭开类的生命之谜 7.2.4 set和get函数的作用与VolumeCalc类 7.2.5 PICalculator类 7.3 作为类成员的对象 7.4 类的析构函数 7.5 对象数组 7.6 重载运算符与对象 7.7 指针、引用和类 7.7.1 指针和引用实例 7.7.2 处理日期和时间的程序实例 7.8 总结 7.9 练习 复习题 第8章 继承和虚函数 8.1 为什么继承如此重要 8.1.1 IceCreamDialog实例 8.1.2 Counter类实例 8.2 继承基础 8.2.1 Counter和DeluxeCounter实例 8.2.2 保护成员 8.2.3 员工、老板和CEO 8.3 访问控制符的规范和多继承 8.4 继承、构造和析构 8.4.1 构造函数和析构函数回顾 8.4.2 基类和派生类的默认构造函数——没有参数 8.4.3 在重载的构造函数中使用参数 8.4.4 基类和派生类的析构函数 8.4.5 医生也是人 8.4.6 关于派生类和基类构造函数的规则 8.5 多态和虚函数 8.5.1 多态——同一个接口,不同的行为 8.5.2 什么是虚函数 8.5.3 虚函数的作用 8.6 总结 8.7 练习 复习题 附录A 学习使用Visual C++2005Express Edition 附录B C++关键字表 附录C C++运算符 附录D ASCII码 附录E 位、字节、内存和十六进制表示 附录F 文件输入/输出 附录G 部分C++类 附录H 多文件程序 附录I Microsoft visual C++2005Express Edit
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值