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客户端和服务器功能。本文将深入探讨…

Codeforces Round 912 (Div. 2)

Codeforces Round 912 (Div. 2) A 大等于2依据冒泡排序即可排序&#xff0c;因此判断下1即可 #include <bits/stdc.h>using namespace std;const int N 1e5 10; int a[N];void solve() {int n , m;cin >> n >> m;for(int i 1 ; i < n ; i ){cin >…

有哪些话一听就知道一个程序员是个水货?

前端&#xff1a;你给我传个时间戳吧。 我&#xff1a;什么是时间戳&#xff1f; 前端&#xff1a;啊&#xff1f; 我&#xff1a;哦哦。我自己百度吧。

改dns会有什么影响?

改变DNS&#xff08;Domain Name System&#xff09;会对网络连接和域名解析产生影响。下面是一些可能的影响&#xff1a; 域名解析速度&#xff1a;DNS服务器的选择和性能可能会影响域名解析的速度。如果你更改为更快的DNS服务器&#xff0c;域名解析时间可能会缩短&#xff0…

LeetCode922. Sort Array By Parity II

文章目录 一、题目二、题解 一、题目 Given an array of integers nums, half of the integers in nums are odd, and the other half are even. Sort the array so that whenever nums[i] is odd, i is odd, and whenever nums[i] is even, i is even. Return any answer a…

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.音乐播放——洛雪音乐助手 ​ 洛雪音乐助手是…

什么是原子性?

Lindaaker explained that ‘atomic’ comes from Greek and meaning ‘undividable.’ 参考&#xff1a; JavaOne 2012: How Do Non-Blocking Data Structures Work? 参考&#xff1a; JavaOne 2012: How Do Non-Blocking Data Structures Work? 中文翻译 原子&#xff08;…

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

【算法集训】基础数据结构:六、栈和队列

做这几天的数据结构的题目的时候有很多函数需要填写&#xff0c;这里需要有一个大致的顺序&#xff0c;一般是先补全结构体&#xff0c;也就是创建队列 | 栈&#xff1b; 而后初始化&#xff0c;设置初值create&#xff08;&#xff09;函数&#xff0c;再然后C语言需要释放&am…

常见的响应状态码

状态码英文描述解释200OK客户端请求成功&#xff0c;即处理成功&#xff0c;这是我们最想看到的状态码302Found指示所请求的资源已移动到由Location响应头给定的 URL&#xff0c;浏览器会自动重新访问到这个页面304Not Modified告诉客户端&#xff0c;你请求的资源至上次取得后…

【MyBatis】拦截查询结果同时动态替换

说明 项目中需要用到响应时替换某些字段的某些值。 代码 package xxx.xxx.xx;import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; import org.apache.ibatis.cache.CacheKey; import org.apach…

智能优化算法应用:基于蜻蜓算法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的图标 会跳…

Qt 剪贴板操作

Qt剪贴板操作 剪贴板的操作经常和前面所说的拖放技术在一起使用,因此我们现在先来说说剪贴板的相关操作。大家对剪贴板都很熟悉。我们可以简单的把它理解成一个数据的存储池,可以把外面的数据放置进去,也可以把里面的数据取出来。剪贴板是由操作系统维护的,所以这提供了跨…

常见的计算机图片格式

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

我对前端/互联网发展的一些看法

写在前面 看这篇文章的标题你们估计也想到了,我就是单纯的水一篇文章,但是以我的尿性也不可能完全水,毕竟我是一个主打实际的博主,我还是希望通过文章输出一些我对技术或者是生活的一些看法,既然是看法,那么就肯定有很多人持有不同的看法,不过我欢迎任何不同的声音,毕竟我也已经…