C++11详解(四) -- 新的类功能和包装器

embedded/2025/2/10 22:01:32/

文章目录

  • 1.新的类功能
    • 1.1 默认的移动构造和移动赋值
    • 1.2 成员变量声明的时候给缺省值
    • 1.3 default和delete
    • 1.4 final和override
  • 2.STL中⼀些变化
  • 3.包装器
    • 3.1function
    • 3.2例题逆波兰表达式求值(用了function)
      • 题目解析
      • 代码
    • 3.3 bind(绑定)

1.新的类功能

1.1 默认的移动构造和移动赋值

1. 原来C++类中,有6个默认成员函数:构造函数/析构函数/拷贝构造函数/拷贝赋值重载/取地址重载/const 取地址重载,最后重要的是前4个,后两个用处不大,默认成员函数就是我们不写编译器会生成一个默认的。C++11 新增了两个默认成员函数,移动构造函数和移动赋值运算符重载
2. 如果你没有自己实现移动构造函数且没有实现析构函数 、拷贝构造、拷贝赋值重载中的任意一个。那么编译器会自动生成一个默认移动构造。默认生成的移动构造函数,对于内置类型成员会执行逐成员按字节拷贝自定义类型成员,则需要看这个成员是否实现移动构造,如果实现了就调用移动构造,没有实现就调用拷贝构造。
3. 默认移动赋值跟上面的移动构造完全类似
4. 如果你提供了移动构造或者移动赋值,编译器不会自动提供拷贝构造和拷贝赋值

class Person
{
public:Person(const char* name = "", int age = 0):_name(name), _age(age){}
private:string _name;int _age;
};int main()
{Person s1;// 构造Person s2 = s1;// 拷贝构造Person s3 = std::move(s1);// 移动构造Person s4;s4 = std::move(s2);return 0;
}

1.2 成员变量声明的时候给缺省值

public:
Person(const char* name = "", int age = 0)
:_name(name)
, _age(age)
{}
private:
bit::string _name;
int _age = 1;
// 声明的时候给缺省值
// 显示地给了age就不会用缺省值了

1.3 default和delete

1. C++11可以让你更好的控制要使用的默认函数。假设你要使用某个默认的函数,但是因为一些原因这个函数没有默认生成。比如:我们提供了拷贝构造,就不会生成移动构造了那么我们可以使用default关键字显示指定移动构造生成
default为强制生成

class Person
{
public:Person(const char* name = "张三", int age = 1):_name(name), _age(age){}Person(const Person& p) = default;Person(Person&& p) = default;// 写了析构就无法生成移动构造,所以用default强制生成移动构造~Person(){}private:string _name;int _age;
};void func(ostream& out)
{}int main()
{Person s1;Person s2 = s1;Person s3 = std::move(s1);Person s4;//s4 = std::move(s2);func(cout);return 0;
}

2. istream和ostream不能进行拷贝构造,必须用引用。
如果能想要限制某些默认函数的生成,在C++98中,是该函数设置成private,并且只声明补丁已,这样只要其他人想要调用就会报错,声明为私有,别人在类外实现就会报错。
在C++11中更简单,只需在该函数声明加上=delete即可,该语法指示编译器不生成对应函数的默认版本,称=delete修饰的函数为删除函数

在这里插入图片描述

void func(ostream& out)
{}int main()
{func(cout);return 0;
}

1.4 final和override

1. final被修饰的父类不能被继承,如果我们不想在子类重写这个虚函数,用final修饰,不能被重写
2. override放在子类重写的虚函数后面去检查是否完成了重写,没有完成重写就会报错
3. 这些在继承和多态中有详解讲解

2.STL中⼀些变化

1. 产生了新容器和新接口,比如unordered_map和unordered_set
2. STL中容器的新接口也不少,最重要的就是右值引用和移动语义相关的push/insert/emplace系列接口和移动构造和移动赋值,还有initializer_list版本的构造等

在这里插入图片描述

3.包装器

3.1function

1. std::function 是一个类模板,也是一个包装器。 std::function 的实例对象可以包装存储其他的可以调用对象,包括函数指针、仿函数、 lambda 、 bind 表达式等,存储的可调用对象被称为 std::function 的目标。若 std::function 不含目标,则称它为空。调用空std::function 的目标导致抛出 std::bad_function_call 异常。

#include<functional>int f(int a, int b)
{return a + b;
}struct Functor
{
public:int operator() (int a, int b){return a + b;}
};// 类
class Plus
{
public:Plus(int n = 10):_n(n){}static int plusi(int a, int b){return a + b;}double plusd(double a, double b){return (a + b) * _n;}
private:int _n;
};int main()
{1.// 包装各种可调用对象// 返回类型和参数的类型要对应// int       int int function<int(int, int)> f1 = f;// 函数指针function<int(int, int)> f2 = Functor();// 仿函数function<int(int, int)> f3 = [](int a, int b) {return a + b; };// lambda2.// 包装类的静态成员函数// 成员函数要指定类域并且前面加&才能获取地址// 静态成员函数可以不加&function<int(int, int)> f4 = &Plus::plusi;cout << f4(1, 1) << endl;3.// 包装普通成员函数,还有一个this指针可以用指针调用 &pdfunction<double(Plus*,double, double)> f5 = &Plus::plusd;Plus pd;cout << f5(&pd, 1.1, 2.2) << endl;可以用对象调用 pdfunction<double(Plus, double, double)> f6 = &Plus::plusd;cout << f6(pd, 1.1, 1.1) << endl;cout << f6(Plus(),1.1,1.1) << endl;可以用右值引用function<double(Plus&&, double, double)> f7 = &Plus::plusd;cout << f7(move(pd), 1.1, 1.1) << endl;cout << f7(Plus(), 1.1, 1.1) << endl;cout << f1(1, 1) << endl;cout << f2(1, 1) << endl;cout << f3(1, 1) << endl;return 0;
}

对于第三点,可以传对象的指针,也可以传对象是为什么?
底层是用.*的运算符,可以用对象直接调用,也可以用对象的指针调用
对象点函数调用
在这里插入图片描述

3.2例题逆波兰表达式求值(用了function)

题目链接

题目解析

遇到数字插入栈,遇到符号出栈,先出的是右操作数,再出的是左操作数,再把结果入栈,如此循环

在这里插入图片描述

代码

class Solution 
{
public:int evalRPN(vector<string>& tokens) {stack<int> st;// function可调用对象的类型map<string,function<int(int,int)>> offunMap = {{"+",[](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;}}};for(auto& str :tokens){// 操作符if(offunMap.count(str)){int right = st.top();st.pop();int left = st.top();st.pop();int ret = offunMap[str](left,right);st.push(ret);}else{st.push(stoi(str));}}return st.top();}
};

3.3 bind(绑定)

1. bind 是一个函数模板,它也是一个可调用对象的包装器,可以把他看做一个函数适配器,对接收的fn可调用对象进行处理后返回一个可调用对象。 bind 可以用来调整参数个数和参数顺序。bind 也在这个头文件中。
2. arg_list中的参数可能包含形如_n的名字,其中n是一个整数,这些参数是占位符,表示newCallable的参数,它们占据了传递给newCallable的参数的位置。数值n表示生成的可调用对象中参数的位置:
_1为newCallable的第一个参数,_2为第二个参数,以此类推。_1/_2/_3…这些占位符放到placeholders的一个命名空间中。
3.根据_1,_2,_3这些调整适配参数

bind参数中第一个传的是可调用对象
可调用对象:lambda,仿函数,函数指针

在这里插入图片描述

调整参数顺序

using placeholders::_1;
using placeholders::_2;
using placeholders::_3;int Sub(int a, int b)
{return (a - b) * 10;
}int main()
{   // 函数指针// _1->a,_2->b// sub1中的第一个位置的参数对应_1,// 第二个位置的参数对应_2auto sub1 = bind(Sub, _1, _2);cout << sub1(10, 5) << endl;// bind 本质返回的一个仿函数对象// 调整参数顺序(不常用)// _1代表第一个实参// _2代表第二个实参auto sub2 = bind(Sub, _2, _1);cout << sub2(10, 5) << endl;return 0;
}

在这里插入图片描述

调整参数个数

int Sub(int a, int b)
{return (a - b) * 10;
}// 调整参数个数 (常⽤)
// a始终是100,绑定了第一个参数
auto sub3 = bind(Sub, 100, _1);
cout << sub3(5) << endl;
// b始终是100,绑定了第二个参数
auto sub4 = bind(Sub, _1, 100);
cout << sub4(5) << endl;

在这里插入图片描述

分别绑定第1,2,3位置的参数

int SubX(int a, int b, int c)
{return (a - b - c) * 10;
}// 分别绑死第123个参数
auto sub5 = bind(SubX, 100, _1, _2);
cout << sub5(5, 1) << endl;auto sub6 = bind(SubX, _1, 100, _2);
cout << sub6(5, 1) << endl;auto sub7 = bind(SubX, _1, _2, 100);
cout << sub7(5, 1) << endl;

成员函数对象进行绑死,就不需要每次都传递了
bind返回的是一个仿函数对象,仿函数对象可以用function进行包装

function<double(Plus&&, double, double)> f6 = &Plus::plusd;
Plus pd;
cout << f6(move(pd), 1.1, 1.1) << endl;
cout << f6(Plus(), 1.1, 1.1) << endl;// bind⼀般⽤于绑死⼀些固定参数
// 绑定了匿名对象的传递
function<double(double, double)> f7 = bind(&Plus::plusd, Plus(), _1, _2);
cout << f7(1.1, 1.1) << endl;

计算复利的lambda

int main()
{// 计算复利的lambda// 复利前一年的利息变成第二年本金// (10000*0.02 + 10000)*0.02 + 10000*0.02 + 10000// 利率  本金  年限// 得到的是利息,总共得到的钱减去本金auto func1 = [](double rate, double money, int year)->double{double ret = money;for (int i = 0; i < year; i++){ret += ret * rate;}return ret - money;};//cout << func1(0.05, 10000000, 30) << endl;// 绑死一些参数,实现出支持不同年利率,不同金额和不同年份计算出复利的结算利息function<double(double)> func3_1_5 = bind(func1, 0.015, _1, 3);function<double(double)> func5_1_5 = bind(func1, 0.015, _1, 5);function<double(double)> func10_1_5 = bind(func1, 0.015, _1, 10);function<double(double)> func3_2_5 = bind(func1, 0.025, _1, 3);function<double(double)> func5_2_5 = bind(func1, 0.025, _1, 5);function<double(double)> func10_2_5 = bind(func1, 0.025, _1, 10);cout << func3_1_5(1000000) << endl;cout << func5_1_5(1000000) << endl;cout << func10_1_5(1000000) << endl;cout << func3_2_5(1000000) << endl;cout << func5_2_5(1000000) << endl;cout << func10_2_5(1000000) << endl;return 0;
}

http://www.ppmy.cn/embedded/161178.html

相关文章

(苍穹外卖)项目结构

苍穹外卖项目结构 后端工程基于 maven 进行项目构建&#xff0c;并且进行分模块开发。 1). 用 IDEA 打开初始工程&#xff0c;了解项目的整体结构&#xff1a; 对工程的每个模块作用说明&#xff1a; 序号名称说明1sky-take-outmaven父工程&#xff0c;统一管理依赖版本&…

《利用原始数据进行深度神经网络闭环 用于光学驻留空间物体检测》论文精读

Deep Neural Network Closed-loop with Raw Data for Optical Resident Space Object Detection 摘要 光学勘测是观测驻留空间物体和空间态势感知的重要手段。随着天文技术和还原方法的应用&#xff0c;宽视场望远镜在发现和识别驻留空间物体方面做出了重大贡献。然而&#x…

记录 | WPF基础学习自定义按钮

目录 前言一、解析Button.TemplateBorder和TemplateBinding 二、代码提供更新时间 前言 参考文章&#xff1a; 参考视频&#xff1a;【WPF入门教程 Visual Studio 2022】WPF界面开发入门 自己的感想 这里涉及到Template模板和事件。主要干两件事&#xff1a;1、template中的重写…

ubuntu server环境下使用mitmproxy代理

近日为了调试AWS连接的一个问题&#xff0c;需要查看HTTPS报文的内容&#xff0c;通过抓包的方式也可以。这里介绍通过mitmproxy的方式。因为是server环境&#xff0c;没有桌面&#xff0c;因此配置的过程是基于shell终端完成的。 安装mitmproxy sudo pip3 install mitmproxy…

周报1.0

补题补题(///&#xffe3;皿&#xffe3;)○&#xff5e; 牛客1(4):ABDG E:双生双宿之错: 小红定义一个数组是“双生数组”&#xff0c;当且仅当该数组大小为偶数&#xff0c;数组的元素种类恰好为 2种&#xff0c;且这两种元素的出现次数相同。例如{1,1,4,4,1,4} 是双生数组…

百度的冰桶算法

百度的冰桶算法&#xff08;Ice Bucket Algorithm&#xff09;是百度搜索引擎用于打击低质量内容的一种算法。该算法主要针对那些通过大量堆砌关键词、内容质量低下、用户体验差的网页进行惩罚&#xff0c;从而提升搜索结果的质量。 冰桶算法的核心目标&#xff1a; 打击低质…

使用PyCharm进行Django项目开发环境搭建

如果在PyCharm中创建Django项目 1. 打开PyCharm&#xff0c;选择新建项目 2.左侧选择Django&#xff0c;并设置项目名称 3.查看项目解释器初始配置 4.新建应用程序 执行以下操作之一&#xff1a; 转到工具| 运行manage.py任务或按CtrlAltR 在打开的manage.pystartapp控制台…

大模型Prompt 提示词攻击,大语言模型安全的潜在威胁

一、简介 Prompt 提示词作为人和大语言模型交互的媒介&#xff0c;被不断提起。提示词攻击是一种新型的攻击方式&#xff0c;包括提示词注入、提示词泄露和提示词越狱。这些攻击方式可能会导致模型生成不适当的内容&#xff0c;泄露敏感信息等。Prompt的构建使得预训练大模型能…