C++进阶之C++11

个人主页:点我进入主页

专栏分类:C语言初阶  C语言进阶  数据结构初阶    Linux    C++初阶      算法   C++进阶

欢迎大家点赞,评论,收藏。

一起努力,一起奔赴大厂

目录

一.列表初始化

1.1一切皆可用列表初始化

1.2initializer list

二.声明

2.1auto

2.2decltype

2.3nullptr

三.左值和右值

3.1左值引用和右值引用

3.2 左值和右值比较

3.3右值引用场景(移动构造和移动赋值)

3.4完美转发与万能引用

3.5针对move一些补充

四.lambda表达式

4.1基本使用

4.2捕捉列表

五.新的类功能

六.可变参数模板

    6.1输出可变参数包的个数

 6.2使用

6.3emplace_back

七.包装器

        7.1function

                7.1.1基本用法

7.1.2一个应用场景

7.1.3使用类的成员函数的function

7.2bind


一.列表初始化

1.1一切皆可用列表初始化

        在C++11中出现了可以支持使用列表进行初始化,这是为了实现一切皆可用列表进行初始化,直接看代码:

class A
{
public:A(int a, int b):_a(a),_b(b){}
private :int _a;int _b;
};
class B
{
public:B(int a):_a(a){}
private:int _a;
};
int main()
{int array[] = { 1,2,3,4 };//单参数隐式类型转化B b = { 1 };//多参数隐式类型转化A a = { 1,2 };A a1{ 2,3 };A* ptr = new A{ 1,2 };return 0;
}

1.2initializer list

        同时C++11支持initializer list对一些stl进行初始化,例如vector,

vector (initializer_list<value_type> il,
const allocator_type& alloc = allocator_type());allocator_type());

它可以直接用{}进行初始化,这个其实是initializer list的类型,我们看一下代码:

	vector<int> v = { 1,2,3,4 };

出现这种情况业主要是想完成一切皆可用{}初始化,由于不知道vetcor的参数的个数,所以采用这种方式。

二.声明

2.1auto

                在c++98中auto是一个存储类型的说明符,但是这玩意没什么用,所以就修改了它的用法,所以修改为了自动推导类型,看下面代码:

int main()
{int a = 1;auto b = 2;cout << typeid(b).name() << endl;
}

auto还可以作为返回值,看下面:

auto Add(int x, int y)
{return x + y;
}
int main()
{auto a = Add(1, 2);cout << typeid(a).name() << endl;return 0;
}

同样返回值是int。 

2.2decltype

        和auto类似,它作用于表达式上,直接上代码:

int main()
{double a = 1.1;double b = 2.2;decltype(a * b) c;decltype (a) d;cout << typeid(c).name() << endl;cout << typeid(d).name() << endl;return 0;
}

2.3nullptr

        由于在定义时将NULL定义为0,所以有时候会出现一些问题,所以新增添了一个nullptr,看一看源码:

#ifndef NULL
#ifdef __cplusplus
#define NULL 0
#else
#define NULL ((void *)0)
#endif
#endif

三.左值和右值

        很多人有一个对左值和右值有一个误区那就是认为在等号左边是左值,右边是右值,其实这是不准确的,真正区分左值和右值是是否可以取地址,知道如何区分左值和右值重要吗?一点不重要,重要的是对左值和右值的引用。

3.1左值引用和右值引用

int main()
{//3个左值int a = 1;int* ptr = new int(1);const int b = 2;//对左值的引用int& c = a;int*& cptr = ptr;const int& d = b;return 0;
}

右值可以是一些匿名对象,常数,一些函数的返回值,其中对于自定义类型可以称为将亡值,看代码:

int Add(int x, int y)
{return x + y;
}
int main()
{int&& a = 1;int&& b = Add(1, 2);string&& s = string("1111");return 0;
}

3.2 左值和右值比较

        针对左值引用,左值引用不可以引用右值否则会报错,但是const属性的左值可以引用右值,

对于右值,右值引用不可以引用左值,但是可以引用move的左值,看代码:

int main()
{//int& a = 1; 左值引用=右值报错const int& ret1 = 1;//const左值引用=右值int a=1;//int&& ret=a; 右值引用=左值报错string s = "aaaaa";string&& ref2 = move(s);//右值引用=move左值return 0;
}

3.3右值引用场景(移动构造和移动赋值)

        在一些传参数时可以使用右值引用进行传参,右值引用可以大大减少数据的拷贝,例如在string的构造时我们可以使用右值进行构造也就是移动构造,在赋值构造时也让可以使用右值就是移动复制

//移动赋值
string& operator=(string&& s)
{cout << "string& operator=(string&& s) -- 移动语义" << endl;swap(s);return *this;
}
//移动构造
string(string&& s):_str(nullptr)
{cout << "string(string&& s) -- 移动构造" << endl;swap(s);
}

3.4完美转发与万能引用

        完美转发是在函数模板模板中为了保持参数的原有属性设计的,看下面代码:

void Fun(int& x) { cout << "左值引用" << endl; }
void Fun(const int& x) { cout << "const 左值引用" << endl; }
void Fun(int&& x) { cout << "右值引用" << endl; }
void Fun(const int&& x) { cout << "const 右值引用" << endl; }
template<typename T>
void PerfectForward(T&& t)
{Fun(t);
}
int main()
{int a = 1;PerfectForward(a);//左值PerfectForward(1);//右值PerfectForward(move(a));//右值const int b = 2;PerfectForward(b);//const左值PerfectForward(move(b));//const右值
}

结果会和上面的一样吗?并不是,看结果:

这是为什么?这是由于左值还是左值,右值退化为了左值,此时的右值可以取地址了,如何解决呢?完美转发,将模板改为下面:

template<typename T>
void PerfectForward(T&& t)
{Fun(std::forward<T>(t));
}

上面的模板参数就是万能引用,&&不是指右值而是和T进行结合可以有左值也可以右值

3.5针对move一些补充

        一旦使用move他就认为这就是将亡值,会将这个值清空(内置类型不会清空),看下面代码:

int main()
{string s = "aaaaaa";string b = std::move(s);
}

四.lambda表达式

4.1基本使用

        对一个类进行升序排序需要写一个仿函数,看代码:

struct Goods
{string _name; // 名字double _price; // 价格int _evaluate; // 评价Goods(const char* str, double price, int evaluate):_name(str), _price(price), _evaluate(evaluate){}
};
struct GoodsPrice
{bool operator()(Goods& a, Goods& b){return a._price < b._price;}
};
int main()
{vector<Goods> v = { { "苹果", 2.1, 5 }, { "香蕉", 3, 4 }, { "橙子", 2.2,
3 }, { "菠萝", 1.5, 4 } };sort(v.begin(), v.end(), GoodsPrice());return 0;
}

在使用lambda之前先看一下lambda的构成:

 其中返回值(->return-type)可以省略,当没有参数时可以省略参数,看下面表达式来进行升序:

sort(v.begin(), v.end(), [](Goods& a, Goods& b){return a._price < b._price;
});

实际上,lambda就相当于仿函数,当然也可以使用下面的方式进行排序:

auto swap = [](Goods& a, Goods& b) {return a._price < b._price;};
sort(v.begin(), v.end(), swap);

当有参数时可以这使用:

	int a = 1, int b = 2;auto add = [](int& a, int& b) {return a + b;};int c=add(a, b);

4.2捕捉列表

 先看样例:

int main()
{int a = 1, b = 2;auto swap = [a, b]()//mutable{int temp = a;a = b;b = temp;};swap();return 0;
}

这个代码会出现问题,它捕捉了a和b但是这两个时一个拷贝过来的,并且不可修改,当然加一个mutable可以修改,但是不会影响到外面的。因为时拷贝的。

当然给一个&表示引用就可以进行修改

int main()
{int a = 1, b = 2;auto swap = [&a, &b](){int temp = a;a = b;b = temp;};swap();return 0;
}

五.新的类功能

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

 还支持了可以让这些强制生成和强制不生产的关键字,default和delete

例如:

class Person
{
private :int _year;string _name;public:Person(const char* name = "", int age = 0):_name(name), _year(age){}Person(Person&&p) = default;//强制生成Person& operator=(Person&& p) = delete;//强制不生产
};

六.可变参数模板

    6.1输出可变参数包的个数

template< class ...Args>
void PrintArgs( Args&&... args)
{cout << sizeof(args) << endl;
}

注意不可以使用args[i]来进行访问。 

 6.2使用

template<class T>
void PrintArgs(T&& t)
{cout << t << endl;
}
template<class T,class ...Args>
void PrintArgs(T&& t,Args&&... args)
{cout << t << endl; PrintArgs(args...);
}
int main()
{PrintArgs(1);PrintArgs(1, 1.1);PrintArgs(1, 1.1, "aaaa");return 0;
}

6.3emplace_back

        emplace_back相对于insert,push_back有很大优势,它时利用模板参数包进行构造,它直接传入类的参数,直接进行构造,当同时传入相同值时效率一样。尽量使用emplace_back.

七.包装器

        7.1function

                7.1.1基本用法

        直接看一段代码:

int f(int x, int y)
{return x + y;
}
struct F
{int operator()(int x, int y){return x + y;}
};int main()
{//函数function<int(int, int)> f1 = f;cout << f1(1,2)<<endl;//仿函数function<int(int, int)> f2 = F();cout << f2(1, 2) << endl;//lambdafunction<int(int, int)> f3 = [](int x, int y){return x + y;};cout << f3(1, 2) << endl;return 0;
}

包装器function可以对函数,仿函数,lanmbda等进行包装,可以将他们组成一个类,看下面的验证:

template<class T,class K>
void Add(T t,K k)
{static int count = 0;cout << count++ <<  " "<<t(k) << endl;
};
double f(double x)
{return x / 1.1;
}
struct F
{double operator()(double x){return x / 1.1;}
};int main()
{Add(f, 3.3);Add(F(), 3.3);Add([](double x){return x / 1.1;}, 3.3);/*function<double(double)> f1 = f;Add(f1, 3.3);function<double(double)> f2 = F();Add(f2, 3.3);function<double(double)> f3 = [](double x){return x / 1.1;};Add(f3, 3.3);*/return 0;
}

当采用上半部分代码时结果为

这三个分别实例化一个函数,但是采用下半部分时,结果为

说明这三个就实例化了一个函数,包装器可以让他们称为同一个类型。

7.1.2一个应用场景

        将字符+,-,*,/利用map和他们对应的运算进行绑定,看代码:

int main()
{map<string, function<int(int, int)>> m = {{"+",[](int x,int y) {return x + y; }},{"-",[](int x,int y) {return x - y; }},{"*",[](int x,int y) {return x * y; }},{"/",[](int x,int y) {return x / y; }}};int a = 4, b = 2;cout << m["+"](a, b) << endl;cout << m["-"](a, b) << endl;cout << m["*"](a, b) << endl;cout << m["/"](a, b) << endl;
}

运行结果如下: 

7.1.3使用类的成员函数的function

        当成员函数是静态成员函数时,function的方式和其他的一样,当成员函数不是静态时,需要在参数哪里加上我们的this指针,=后写为&类域::成员函数,具体代码为:

class A
{
public:static void Count(){cout << count++ << endl;}void print(int x){cout << num << endl;}
private:static int count;int num=10;
};
int A::count = 0;
int main()
{function<void()> f1 = A::Count;f1();function<void(A*, int)> f2 = &A::print;A a;f2(&a, 1);function<void(A, int)> f3 = &A::print;f3(A(), 1);return 0;
}

7.2bind

        bind是对函数参数进行绑定,它可以实现参数的呼唤也可以实现对一个参数进行绑定,看代码:

void F(const string& s, int x, int y)
{cout << s << "->血: " << x << " 蓝 " << y << endl;
}
int main()
{auto f1 = bind(F, "盖伦",placeholders::_1,placeholders::_2);f1(1, 1);return 0;
}

运行结果为:

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

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

相关文章

U盘数据丢失?一招教你如何使用四种技巧轻松找回!

每一个打工人可能都是被各种文件所困扰的&#xff0c;而且现在不仅仅是工作上&#xff0c;还有学习以及日常的生活记录也需要接触到各类的数据&#xff0c;拿我们平时用软件时产生的文件、图片、视频等等来说&#xff0c;就占据了磁盘的大部分空间&#xff0c;当然有时候也会选…

CTFHub——XSS——反射型

1、反射型&#xff1a; 发现为表单式&#xff0c;猜测哪个可能存在注入漏洞&#xff0c;分别做测试注入发现name框存在xss漏洞 输入发现有回显但不是对方cookie&#xff0c;参考wp发现要用xss线上平台 将xss平台测试语句注入&#xff0c;将得到的url编码地址填入url框&#xf…

《学会 SpringMVC 系列 · 写入拦截器 ResponseBodyAdvice》

&#x1f4e2; 大家好&#xff0c;我是 【战神刘玉栋】&#xff0c;有10多年的研发经验&#xff0c;致力于前后端技术栈的知识沉淀和传播。 &#x1f497; &#x1f33b; CSDN入驻不久&#xff0c;希望大家多多支持&#xff0c;后续会继续提升文章质量&#xff0c;绝不滥竽充数…

MATLAB画散点密度图(附代码和测试数据的压缩包)

1. 有关 Matlab 获取代码关注WZZHHH回复关键词&#xff0c;或者咸鱼关注&#xff1a;WZZHHH123 怀俄明探空站数据解算PWV和Tm&#xff1a;怀俄明探空站数据解算PWV和Tm 怀俄明多线程下载探空站数据&#xff08;包括检查和下载遗漏数据的代码&#xff09;&#xff1a;怀俄明多线…

VMware安装Win10系统(保姆级教程)

需要自己先下载并安装VMware 和Win10系统镜像&#xff1a; VMware官网&#xff1a;VMware - Delivering a Digital Foundation For Businesses Win10下载地址&#xff1a;MSDN,我告诉你 1.新建虚拟机设置 2.启动Win10虚拟机设置 注意&#xff1a; 当出现有字体的时候&#…

一款绿色免费免安装的hosts文件编辑器

BlueLife Hosts Editor 是一款免费的 Hosts 文件编辑工具&#xff0c;主要用于管理和修改电脑系统的 Hosts 文件。该软件具有多种功能&#xff0c;包括添加、删除和更新域名记录&#xff0c;以及调整 IP 与网域名称的交叉对应关系&#xff0c;类似于 DNS 的功能。 该软件特别适…

filebeat

1、作用 1、可以在本机收集日志2、也可以远程收集日志3、轻量级的日志收集系统&#xff0c;可以在非java环境运行。logstash是在jmv环境中运行&#xff0c;资源消耗很大&#xff0c;启动一个logstash要消耗500M左右的内存&#xff0c;filebeat只消耗10M左右的内存。收集nginx的…

Qt 学习第四天:信号和槽机制(核心特征)

信号和槽的简介 信号和插槽用于对象之间的通信。信号和插槽机制是Qt的核心特征&#xff0c;可能是不同的部分大部分来自其他框架提供的特性。信号和槽是由Qt的元对象系统实现的。介绍&#xff08;来自Qt帮助文档Signals & Slots&#xff09; 在GUI编程中&#xff0c;当我们…

使用 Rough.js 创建动态可视化网络图

本文由ScriptEcho平台提供技术支持 项目地址&#xff1a;传送门 使用 Rough.js 创建动态可视化网络图 应用场景 Rough.js 是一个 JavaScript 库&#xff0c;它允许开发人员使用毛边风格创建可视化效果。该库适用于各种应用程序&#xff0c;例如&#xff1a; 数据可视化地图…

计算机基础(Windows 10+Office 2016)教程 —— 第8章 多媒体技术及应用

多媒体技术及应用 8.1 多媒体技术的概述8.1.1 多媒体技术的定义和特点8.1.2  多媒体的关键技术8.1.3 多媒体技术的发展趋势8.1.4 多媒体文件格式的转换8.1.5 多媒体技术的应用 8.2 多媒体计算机系统的构成8.2.1 多媒体计算机系统的硬件系统8.2.2 多媒体计算机系统的软件系统…

APP逆向 day26unidbg下-pdd(anti)案例

一.前言 今天我们讲unidbg的下篇&#xff0c;也就是unidbg基础的最后一个部分&#xff0c;我们上节课也有补环境&#xff0c;比如补java环境&#xff0c;补安卓环境&#xff0c;这节课我们讲的肯定比这些都要难&#xff0c;我会给出一个之前讲过的案例&#xff0c;然后会讲一个…

多 NodeJS 环境管理

前言 对于某个项目依赖特定版本的 NodeJS&#xff0c;或几个项目的 NodeJS 版本冲突时&#xff0c;需要在系统中安装多个版本的 NodeJS&#xff0c;这时可以使用一些工具来进行多个 NodeJS 的管理。 有很多类似的 NodeJS 管理工具&#xff0c;如 nvm, nvs, n 等&#xff0c;接…

深入理解单元测试与JUnit:从基础概念到实践操作

文章目录 前言一、单元测试是什么&#xff1f;单元测试的特点单元测试的好处 二、junit是什么&#xff1f;三、操作步骤1.junit安装2.maven新建项目3. 新建java文件4. 生成测试类5. 编写测试方法6. 测试结果 总结 前言 随着软件开发行业的不断发展&#xff0c;测试的重要性日益…

C++自定义接口类设计器之函数解析二

关键代码 // 解析为函数 bool FunctionCreator::parse(const QString& lineFunc) {auto trimFunc lineFunc.trimmed();auto list trimFunc.split(" ");bool bHasReturn false;// 返回值和函数名解析for (const auto& key : list) {auto trimKey key.trim…

串口应用编程-I.MX6U嵌入式Linux C应用编程学习笔记基于正点原子阿尔法开发板

串口应用编程 串口应用编程介绍 介绍 串口定义:串行接口,数据按顺序传输 串口特点:通信线路简单,距离远,速度较低 应用领域:常用工业接口 Linux系统中的作用 作为标准输入输出设备 系统打印信息输出 用户与系统交互 串口与终端:在Linux系统中,串口被视为一种终端&#…

2024年软件测试岗必问的100+个面试题【含答案】

一、基础理论 1、开场介绍 介绍要领&#xff1a;个人基本信息、工作经历、之前所做过的工作及个人专长或者技能优势。扬长避短&#xff0c;一定要口语化&#xff0c;语速适中。沟通好的就多说几句&#xff0c;沟通不好的话就尽量少说两句。举例如下&#xff1a; 面试官你好&…

前端Web-JavaScript(下)

主要是补全一下JavaScript 基本对象: String对象 语法格式 方式1&#xff1a; var 变量名 new String("…") ; //方式一 例如&#xff1a; var str new String("Hello String"); 方式2&#xff1a; var 变量名 … ; //方式二 例如&#xff1a; var …

【外排序】--- 文件归并排序的实现

Welcome to 9ilks Code World (๑•́ ₃ •̀๑) 个人主页: 9ilk (๑•́ ₃ •̀๑) 文章专栏&#xff1a; 数据结构 我们之前学习的八大排序&#xff1a;冒泡&#xff0c;快排&#xff0c;插入&#xff0c;堆排等都是内排序&#xff0c;这些排序算法处理的都是…

一键生成视频并批量上传视频抖音、bilibili、腾讯(已打包)

GenerateAndAutoupload Github地址&#xff1a;https://github.com/cmdch2017/GenerateAndAutoupload 如何下载&#xff08;找到最新的release&#xff09; https://github.com/cmdch2017/GenerateAndAutoupload/releases/download/v1.0.1/v1.0.1.zip 启动必知道 conf.py …

数论第四节:二元一次不定方程、勾股数

不定方程定义 解不确定的方程称为不定方程。一般化的定义为&#xff1a;不定方程是指未知数的个数多余方程的个数&#xff0c;或未知数受到某种限制&#xff08;如整数、正整数等&#xff09;的方程和方程组。 二元一次不定方程定义 形如axbyc的形式的方程。其中a,b不等于0&…