C++ 11 初识2

一.新的类功能

  

默认成员函数

原来 C++ 类中,有 6 个默认成员函数:

  1.  构造函数
  2.  析构函数
  3. 拷贝构造函数
  4. 拷贝赋值重载
  5.  取地址重载
  6. const 取地址重载


C++11 新增了两个:移动构造函数和移动赋值运算符重载。


针对移动构造函数和移动赋值运算符重载有一些需要注意的点如下:


  如果你没有自己实现移动构造函数,且没有实现析构函数 、拷贝构造、拷贝赋值重载中的任
意一个 。那么编译器会自动生成一个默认移动构造
。 默认生成的移动构造函数,对于内置类
型成员会执行逐成员按字节拷贝,自定义类型成员,则需要看这个成员是否实现移动构造,
如果实现了就调用移动构造,没有实现就调用拷贝构造。


  如果你没有自己实现移动赋值重载函数,且没有实现析构函数 、拷贝构造、拷贝赋值重载中
的任意一个,那么编译器会自动生成一个默认移动赋值。默认生成的移动构造函数,对于内
置类型成员会执行逐成员按字节拷贝,自定义类型成员,则需要看这个成员是否实现移动赋
值,如果实现了就调用移动赋值,没有实现就调用拷贝赋值。 ( 默认移动赋值跟上面移动构造
完全类似 )
  如果 你提供了移动构造或者移动赋值,编译器不会自动提供拷贝构造和拷贝赋值。

二.可变参数模板

2.1 可变参数模板的定义

        C++11的新特性可变参数模板能够让您创建可以接受可变参数的函数模板和类模板。

// Args是一个模板参数包,args是一个函数形参参数包
// 声明一个参数包Args...args,这个参数包中可以包含0到任意个模板参数。
template <class ...Args>
void ShowList(Args... args)
{}

  上面的参数 args 前面有省略号,所以它就是一个可变模版参数,我们把带省略号的参数称为 “ 参数包 ” ,它里面包含了 0 到 N ( N>=0 )个模版参数。我们无法直接获取参数包 args 中的每个参数的,
  只能通过展开参数包的方式来获取参数包中的每个参数,这是使用可变模版参数的一个主要特
点,也是最大的难点,即如何展开可变模版参数.

   但这里可变参数有点抽象,我们只讲用法,不再深入了解。


先看一个简单的例子:

#include<iostream>
using namespace std;template <class ...Args>
void ShowList1(Args... args)
{// 参数个数cout << sizeof...(args) << endl;//计算的是参数包中形参的个数
}int main()
{ShowList1(1, 2, 3, 'x', 1.1);return 0;
}

输出结果:

   

2.2 参数包的展开

2.2.1 递归方式展开

通过递归方式展开参数包,需要提供一个参数包展开的函数和一个递归终止函数。

#include<iostream>
using namespace std;// 递归终止函数
template <class T>
void ShowList(const T& t)
{cout << t << endl;
}
// 展开函数
template <class T, class ...Args>
void ShowList(T value, Args... args)
{cout << value << " ";ShowList(args...);
}
int main()
{ShowList(1);ShowList(1, 'A');ShowList(1, 'A', std::string("sort"));return 0;
}

结果为:

2.2.2  逗号表达式展开参数包

#include<iostream>template<class T>
void print(T tmp){std::cout<<tmp<<std::endl;
}
//可变参数函数模板
template<class...T>
void expand(T...args){//逗号运算符//初始化列表int a[]={(print(args),0)...};
}int main(){expand(1,2,3,4);return 0;
}

  

  expand 函数的逗号表达式: (print(args), 0), 也是按照这个执行顺序, 先执行 print(args), 再得到逗号表达式的结果 0。

  同时, 通过初始化列表来初始化一个变长数组, { (print(args), 0)… }将会展开成( (print(args1),0), (print(args2), 0), (print(args3), 0), etc…), 最终会创建一个元素只都为 0 的数组 inta[sizeof…(args)] 。


三.lambda表达式

  3.1 lambda的概念


        函数指针是在C语言中,不过因为过于麻烦,因此C++中新出了仿函数。sort这个函数就可以根据我们自定义的仿函数来进行对不同的元素排序,不过如果我们需要对很多种自定义类型进行排序,那么就会很麻烦,因此C++11中就又出现了lambda表达式,使之进一步简化。而lambda的底层其实就是仿函数,其出现主要是为了更近一步的简化用法,方便程序员。

 3.2 lambda的使用

   假设我们要对一个自定义类型进行排序,其中有三个元素,分别是名字,价格,评价等,

   现在我们要对他进行排序,但是我们不知道该如何排序,显然,在不同场景中,我们有不同的排序需求,一般而言,我们可以定义三个仿函数。

   但lambda表达式可以这样使用:
 

#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
using namespace std;struct Goods
{string _name; // 名字double _price; // 价格int _evaluate; // 评价Goods(const char* str, double price, int evaluate):_name(str), _price(price), _evaluate(evaluate){}
};int main()
{vector<Goods> v = { { "苹果", 2.1, 5 }, { "香蕉", 3, 4 }, { "橙子", 2.2,3 }, { "菠萝", 1.5, 4 } };sort(v.begin(),v.end(), [](const Goods& g1, const Goods& g2) {return g1._price < g2._price;});sort(v.begin(), v.end(), [](const Goods& g1, const Goods& g2) {return g1._price > g2._price; });sort(v.begin(), v.end(), [](const Goods& g1, const Goods& g2) {return g1._evaluate < g2._evaluate; });sort(v.begin(), v.end(), [](const Goods& g1, const Goods& g2) {return g1._evaluate > g2._evaluate;});return 0;
}

 上述代码的排序问题就是使用C++11中的lambda表达式来解决,可以看出lambda表达式实际是一个匿名函数。

 3.3 lambda表达式语法

 lambda表达式书写格式:

[capture-list] (parameters) mutable -> return-type { statement}  

 lambda表达式各部分说明

  1. [ capture-list ] : 捕捉列表,该列表总是出现在lambda函数的开始位置,编译器根据[]来判断接下来的代码是否为lambda函数,捕捉列表能够捕捉上下文中的变量供lambda函数使用。
  2. (parameters):参数列表。与普通函数的参数列表一致,如果不需要参数传递,则可以连同()一起省略
  3. mutable:默认情况下,lambda函数总是一个const函数,mutable可以取消其常量性。使用该修饰符时,参数列表不可省略(即使参数为空)。
  4. ->returntype:返回值类型。用追踪返回类型形式声明函数的返回值类型,没有返回值时此部分可省略。返回值类型明确情况下,也可省略,由编译器对返回类型进行推导。
  5. {statement}:函数体。在该函数体内,除了可以使用其参数外,还可以使用所有捕获到的变量。


注意:
  在lambda函数定义中,参数列表和返回值类型都是可选部分,而捕捉列表和函数体可以为
空。因此C++11中最简单的lambda函数为:[]{}; 该lambda函数不能做任何事情。


3.4 捕获列表说明

 

  捕获列表决定了上下文中哪些数据可以被lambda使用,以及使用的方式是传值还是传引用。

  1.  [var]:表示值传递方式捕捉变量var
  2.  [=]:表示值传递方式捕获所有父作用域中的变量(包括this)
  3.  [&var]:表示引用传递捕捉变量var
  4. [&]:表示引用传递捕捉所有父作用域中的变量(包括this)
  5.  [this]:表示值传递方式捕捉当前的this指针

注意:

a. 父作用域只包含lambda函数的语句块

 b. 语法上捕捉列表可由多个捕捉项组成,并以逗号分割。
        比如:[=, &a, &b]:以引用传递的方式捕捉变量a和b,值传递方式捕捉其他所有变量[&,a, this]:值传递方式捕捉变量a和this,引用方式捕捉其他变量

 c. 捕捉列表不允许变量重复传递,否则就会导致编译错误。
        比如:[=, a]:=已经以值传递方式捕捉了所有变量,捕捉a就重复传递了

 d. 在块作用域以外的lambda函数捕捉列表必须为空。

 e. 在块作用域中的lambda函数仅能捕捉父作用域中局部变量,捕捉任何非此作用域或者非局部变量都会导致编译报错。

  f. lambda表达式之间不能相互赋值,即使看起来类型相同
 

例如:
 

#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
using namespace std;int main()
{// 最简单的lambda表达式, 该lambda表达式没有任何意义[] {};// 省略参数列表和返回值类型,返回值类型由编译器推导为intint a = 3, b = 4;[=] {return a + 3; };// 省略了返回值类型,无返回值类型auto fun1 = [&](int c) {b = a + c; };fun1(10);cout << a << " " << b << endl;// 各部分都很完善的lambda函数 额外取地址使用bauto fun2 = [=, &b](int c)->int {return b += a + c; };cout << fun2(10) << endl;// 复制捕捉xint x = 10;auto add_x = [x](int a) mutable { x *= 2; return a + x; };cout << add_x(10) << endl;return 0;
}

代码结果为:
   

3.5 lambda的底层逻辑 

  在底层编译器对于lambda表达式的处理方式完全就是按照函数对象的方式处理:如果定义了一个lambda表达式,编译器会自动生成一个类,在该类中重载了operator。

四.包装器

4.1.function包装器

  function包装器也叫适配器。C++中的function本质是一个类模板,也是一个包装器。

        在C++中,有很多类型,既可以是函数,也可以是成员函数、静态成员函数、仿函数,又或者是lambda表达式等等,如此多的类型使用模板就会导致效率低下,因此有了function包装器。

4.1.1包装器语法


std::function在头文件<functional>

// 类模板原型如下

template <class T> function; // undefinedtemplate <class Ret, class... Args>
class function<Ret(Args...)>;


模板参数说明:
Ret: 被调用函数的返回类型
Args…:被调用函数的形参

4.1.2 包装器使用

int f(int a, int b)
{return a + b;
}struct Functor
{
public:int operator() (int a, int b){return a + b;}
};class Plus
{
public:static int plusi(int a, int b){return a + b;}double plusd(double a, double b){return a + b;}
};int main()
{std::function<int(int, int)> func1 = f;cout << func1(1, 2) << endl;std::function<int(int, int)> func2 = Functor();cout << func2(10, 20) << endl;std::function<int(int, int)> func3 = &Plus::plusi;cout << func3(100, 200) << endl;// 非静态成员函数包装std::function<double(Plus, double, double)> func4 = &Plus::plusd;cout << func4(Plus(), 100.11, 200.11) << endl;std::function<int(int, int)> func5 = [](int a, int b) {return a + b; };cout << func5(100, 200) << endl;return 0;
}


代码结果为:

上面的包装器就分别有函数、仿函数、静态成员函数、成员函数和lambda表达式。

4.2  实战价值

逆波兰表达式求值

class Solution {
public:int evalRPN(vector<string>& tokens) {stack<long long> st;map<string, function<int(int, int)>> opFuncMap = {{ "+", [](long long x, long long y){ return x + y; }},{ "-", [](long long x, long long y){ return x - y; }},{ "*", [](long long x, long long y){ return x * y; }},{ "/", [](long long x, long long y){ return x / y; }}};for(auto& str : tokens){// 操作符if(opFuncMap.count(str)){long long right = st.top();st.pop();long long left = st.top();st.pop();st.push(opFuncMap[str](left, right));}// 操作数else{st.push(stoll(str));}}return st.top();}
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/219094.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Python Paramiko库:SSH远程连接与文件传输实战指南

更多资料获取 &#x1f4da; 个人网站&#xff1a;ipengtao.com 在网络管理和系统运维中&#xff0c;SSH&#xff08;Secure Shell&#xff09;是一种广泛用于远程登录和文件传输的协议。Python中的Paramiko库为开发者提供了灵活、强大的SSH客户端和服务器功能。本文将深入探讨…

LeetCode刷题--- 验证二叉搜索树

个人主页&#xff1a;元清加油_【C】,【C语言】,【数据结构与算法】-CSDN博客 http://t.csdnimg.cn/ZxuNL个人专栏&#xff1a;力扣递归算法题 http://t.csdnimg.cn/ZxuNL 【C】 http://t.csdnimg.cn/c9twt 前言&#xff1a;这个专栏主要讲述递归递归、搜索与回溯算法&#x…

分享5款不起眼但非常实用的小工具

​ 时光荏苒&#xff0c;科技日新月异&#xff0c;一些看似不起眼的小工具却可能改变我们的工作方式。下面我们将介绍五款不可错过的小工具&#xff0c;它们能给你带来一些意想不到的效果&#xff0c;让你的工作更加高效便捷。 1.音乐播放——洛雪音乐助手 ​ 洛雪音乐助手是…

No module named ‘osgeo’解决办法

from osgeo import gdal 报错&#xff1a;No module named ‘osgeo’ pycharm安装osgeo、GDAL都失败 pip install osgeo失败 最后先下载对应版本的GDAL文件 再cmd命令行中用对应环境的python进行GDAL包安装 1.我将我的Anaconda某个环境文件夹D:\software\pinstall\Anaconda3…

Source Tree回滚 重置 贮藏操作

回滚提交 source tree的回滚提交: 在执行该操作时将会对history中提交的指定节点直接进行回滚,将该节点执行的提交操作撤销(如当前节点是提交文件,执行回滚提交时将会删除该文件,如果当前节点的前面的节点对该节点内容进行修改后,执行回滚提交时需要执行冲突解决),同时生成一次…

智能优化算法应用:基于蜻蜓算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于蜻蜓算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于蜻蜓算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.蜻蜓算法4.实验参数设定5.算法结果6.参考文献7.MA…

【音视频 | H.264】H.264编码详解

&#x1f601;博客主页&#x1f601;&#xff1a;&#x1f680;https://blog.csdn.net/wkd_007&#x1f680; &#x1f911;博客内容&#x1f911;&#xff1a;&#x1f36d;嵌入式开发、Linux、C语言、C、数据结构、音视频&#x1f36d; &#x1f923;本文内容&#x1f923;&a…

使用FluentAvalonia组件库快速完成Avalonia前端开发

前言 工欲善其事必先利其器,前面我们花了几篇文章介绍了Avalonia框架以及如何在Avalonia框架下面使用PrismAvalonia完成MVV模式的开发。今天我们将介绍一款重磅级的Avalonia前端组件库,里面封装了我们开发中常用的组件,这样就不用我们自己再写组件了。专注业务功能开发,提…

1.4 Postman的安装

hello大家好&#xff0c;本小节我们来安装一下Postman&#xff0c;好为我们后续的测试工作做准备。 首先&#xff0c;打开Postman的官网Postman API Platform 然后根据同学们自己电脑的操作系统来下载对应的Postman安装包。我这里拿windows来举例。我们点击windows的图标 会跳…

常见的计算机图片格式

左rgb &#xff08;光源色彩&#xff09; 右cmyk &#xff08;印刷色彩&#xff09; 缺点&#xff0c;不能保存&#xff0c;储存空间太大

螺旋矩阵算法(leetcode第54题)

题目描述&#xff1a; 给你一个 m 行 n 列的矩阵 matrix &#xff0c;请按照 顺时针螺旋顺序 &#xff0c;返回矩阵中的所有元素。示例 1&#xff1a;输入&#xff1a;matrix [[1,2,3],[4,5,6],[7,8,9]] 输出&#xff1a;[1,2,3,6,9,8,7,4,5]示例 2&#xff1a;输入&#xff…

工厂设备维护管理有什么比较好的解决方案?有什么好用的工单管理系统?

生产设备对于工厂来说是十分宝贵的资产。一方面&#xff0c;工厂依赖设备进行生产活动&#xff0c;一旦设备故障就会影响产量&#xff1b;另一方面&#xff0c;工厂中的生产设备一般造价都比较高昂&#xff0c;如果出现故障就会增加工厂的生产成本&#xff1b;再一方面&#xf…

SQL Server 服务启动报错:错误1069:由于登录失败而无法启动服务

现象 服务器异常关机以后&#xff0c;SQL Server服务无法启动了。 启动服务时报错&#xff1a; 错误1069:由于登录失败而无法启动服务 解决办法 我的电脑–控制面板–管理工具–服务–右键MSSQLSERVER–属性–登录–登陆身份–选择"本地系统帐户" 设置完成后&am…

JavaSE基础50题:23. 数组拷贝(数组练习题)

文章目录 概述方法一&#xff1a;运用for循环进行拷贝方法二&#xff1a;Java内置方法进行拷贝方法三&#xff1a;指定区间进行拷贝方法四&#xff1a;数组克隆clone() 概述 数组拷贝。 注意&#xff1a; public static void main(String[] args) {int[] array1 {1,2,3,4};Sy…

Trace 在多线程异步体系下传递

JAVA 线程异步常见的实现方式有&#xff1a; new ThreadExecutorService 当然还有其他的&#xff0c;比如fork-join&#xff0c;这些下文会有提及&#xff0c;下面主要针对这两种场景结合 DDTrace 和 Springboot 下进行实践。 引入 DDTrace sdk <properties><java.…

JavaEE进阶学习: SpringBoot 日志文件

1.日志有什么用 日志的主要作用是记录系统的运行状态、事件和错误信息等。具体来说&#xff0c;日志可以用于以下几个方面&#xff1a; 故障排除&#xff1a;当系统出现故障或错误时&#xff0c;日志可以帮助开发人员定位问题的具体原因和位置&#xff0c;从而更快地修复系统。…

Intellij IDEA 运行maven报错误“CreateProcess error=2, 系统找不到指定的文件“的完美解决方案

一、问题背景 博主正常使用着Intellij IDEA&#xff0c;不知道为什么突然Intellij IDEA报错&#xff0c;错误提示如下&#xff1a; Error:Cannot run program "C:\Program Files\Java\jdk1.8.0_351" 观察Intellij IDEA报错的原因&#xff0c;我们可以知道&#xff1…

【LeetCode刷题-栈】-- 150.逆波兰表达式求值

150.逆波兰表达式求值 方法&#xff1a;使用栈 class Solution {public int evalRPN(String[] tokens) {Stack<Integer> numStack new Stack<>();for(int i 0; i < tokens.length;i){String token tokens[i];if(isNumber(token)){numStack.push(Integer.par…

免费!简单优雅的手机视频制作PR模板抖音素材下载

这是一款多功能的Premiere Pro模板&#xff0c;无论你是为视频、宣传内容还是社交媒体帖子短视频&#xff0c;这个pr模板都会为你的项目增添一丝优雅和专业。适用于广播&#xff0c;俱乐部&#xff0c;音乐会&#xff0c;舞蹈&#xff0c;设计&#xff0c;宣传片&#xff0c;动…

Qt/C++视频监控安卓版/多通道显示视频画面/录像存储/视频播放安卓版/ffmpeg安卓

一、前言 随着监控行业的发展&#xff0c;越来越多的用户场景是需要在手机上查看监控&#xff0c;而之前主要的监控系统都是在PC端&#xff0c;毕竟PC端屏幕大&#xff0c;能够看到的画面多&#xff0c;解码性能也强劲。早期的手机估计性能弱鸡&#xff0c;而现在的手机性能不…