【C++11新特性】类的新功能,可变模板参数,包装器

news/2024/5/19 7:41:23/文章来源:https://blog.csdn.net/qq_51492202/article/details/126994736

文章目录

  • 一、类的新功能
    • 1.default
    • 2.delete
  • 二、可变参数模板
    • 1.参数包
    • 2.参数包的插入与解析
      • (1)参数包的个数
      • (2)添加参数解析
    • (3)逗号表达式展开
    • (4)emplace_back
  • 三、包装器
    • 1.function(封装)
    • 2.bind(绑定)

一、类的新功能

1.default

在继承与多态中,我们介绍了final与override,这里我们介绍两个新的使用的方法。

class Person
{
private:string _name;int _age;
public:Person(string& s, int& a):_name(s),_age(a){}Person(Person& p){_name = p._name;_age = p._age;}
};
int main()
{Person p;
}

在这里插入图片描述
当没有默认构造函数的时候,Person p会发生报错。如果我们希望编译器在我们实现了构造函数的基础上再自己实现一个默认构造函数的话,就需要使用default关键字了,在类中加上:

	Person() = default;

此时就可以构造成功了,default的作用是通知编译器自动生成一个默认构造函数。
同理,拷贝构造函数和析构函数也可以使用default让编译器自己实现。

2.delete

delete一般在单例模式中使用,单例模式中不允许使用拷贝构造函数,在C++98中,可以将拷贝构造函数设为私有。
但是并不能保证类内不去调用拷贝构造函数,因此C++11引入了delete。

class Person
{
private:string _name;int _age;
public:Person(string& s, int&& a):_name(s),_age(a){}Person(Person& p) = delete;
};
int main()
{string s("aaa");Person p(s,12);Person p1(p);
}

此时拷贝构造函数就无法调用了,编译器也无法自动生成。

二、可变参数模板

1.参数包

在STL容器中,插入函数不只有push_back等,还有一种插入函数:emplace_back()
在这里插入图片描述
它的参数是Args&&…,它表示的就是一个可变参数列表,注意&&是一个万能引用。Args是一个参数包,可以包含很多个参数:

2.参数包的插入与解析

(1)参数包的个数

template<class ...Args>
void ShowArgs(Args...args)
{cout << sizeof...(args) << endl;//注意这里打印的是args的个数
}
int main()
{int a=2;ShowArgs(1);ShowArgs(1, "aaa");ShowArgs(1, a, "dddd");
}

在这里插入图片描述
通常配合着模板一起使用,我们其中Args为一个可变参数包类型,args为参数包,我们可以向其中传入多个不同类型的参数
要打印参数个数,使用的是sizeof…()这一奇怪的结构。
语法比较简单,那么函数内部该如何换取各个参数呢?这就需要对参数包进行解析。

(2)添加参数解析

可以添加一个参数模板然后使用递归来进行解析:

template<class T>
void ShowArgs(const T& val)//重载函数,用于终止
{cout << typeid(val).name() << endl;
}
template<class T, class ...Args >//添加一个模板参数T,每一次向它传入剩下的可变参数列表
void ShowArgs(T val,Args...args)
{cout << typeid(val).name() << ":" << val << endl;ShowArgs(args...);//cout << sizeof...(args) << endl;//注意这里打印的是args的个数
}
int main()
{int a=2;ShowArgs(1);cout << endl;ShowArgs(1, "aaa");cout << endl;ShowArgs(1, a, "dddd");
}

在这里插入图片描述

(3)逗号表达式展开

template<class T>
void ShowArgs(const T& val)
{cout << typeid(val).name() << endl;
}
template<class ...Args>
void PrintArgs(Args...args)
{int arr[] = { (ShowArgs(args),0)... };cout << endl;
}
int main()
{PrintArgs(1, 'a', 2.2);
}	

expand函数中的逗号表达式:(printarg(args), 0),也是按照这个执行顺序,先执行printarg(args),再得到逗号表达式的结果0。同时还用到了C++11的另外一个特性——初始化列表, 通过初始化列表来初始化一个变长数组, {(printarg(args), 0)…} 将会展开成 ((printarg(arg1),0),(printarg(arg2),0), (printarg(arg3),0), etc… ) ,最终会创建一个元素值都为0的数组int arr[sizeof…(Args)] 。
由于是逗号表达式,在创建数组的过程中会先执行逗号表达式前面的部分printarg(args)打印出参数,也就是说在构造int数组的过程中就将参数包展开了,这个数组的目的纯粹是为了在数组构造的过程展开参数包。

(4)emplace_back

emplace_back对于push_back的优势就在于支持可变参数列表,显得更加灵活一些:

	list<pair<int, char>> mylist;mylist.push_back(make_pair(1, 'a'));mylist.emplace_back(make_pair(2, 'b'));//mylist.push_back(1, 'v');//不能自动构建pairmylist.emplace_back(3, 'o');//可以自动构建pair

emplace_back支持可变参数,拿到构建pair对象的参数后自己去创建对象,那么除了用法上,和push_back没什么太大的区别。传左值对比 – push_back没有区别;传右值对比 – push_back是构造+移动构造 emplace_back是直接构造形态有区别,如果push_back/emplace_back的参数对象及其成员都实现了移动构造,本质区别不大, 因为构造出来+移动构造,和直接构造成本差不多, 但是如果push_back/emplace_back的参数对象及其成员没有实现移动构造,那么emplace_back还是直接构造,push_back则是构造+拷贝构造(没有移动构造编译器会调用拷贝构造),因此代价就大了.
稳妥一点呢用emplace_back更好,因为它可以不依赖参数对象是否提供移动构造。

三、包装器

包装器的本质是一个类模板。

1.function(封装)

double f(double i)
{return i / 2;
}
struct Functor
{double operator()(double d){return d / 3;}
};
template<class F,class T>
T useF(F f, T x)
{static int count = 0;cout << "count:" << ++count << endl;cout << "count:" << &count << endl;return f(x);
}
int main()
{cout << useF(f, 11.1) << endl;cout << useF(Functor(), 1) << endl;cout << ([](double d)->double {return d / 4; }, 11.1);
}

看这样一段代码,有一个模板函数,当同时向它的F传入函数,仿函数,以及lambda表达式的时候会实例化三个模板。
我们希望它只实例化出一个模板,需要使用function,它被包含在functional这个头文件中。
在这里插入图片描述
发现count的值都是0,地址各不相同,说明实例化了三份模板。
此时就需要使用func函数:

	function<double(double)> func1 = f;cout << useF(func1, 11.1) << endl;function<double(double)> func2 = Functor();cout << useF(func2, 1.1) << endl;function<double(double)> func3 = [](int d)->int {return d / 4; };cout << useF(func3, 12.1) << endl;

在这里插入图片描述
注意,包装器只有在类型相同,并且传入参数类型也相同的时候,才只会初始化一份。其他情况还是初始化多份。

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()
{function<int(int, int)> f1 = f;cout << f1(1, 2) << endl;function<int(int, int)> f2 = Functor();cout << f2(1, 2) << endl;function<int(int, int)> f3 = &Plus::plusi;cout << f3(1, 2) << endl;function<double(Plus, double, double)> f4 = &Plus::plusd;cout << f4(Plus(),1, 2) << endl;
}

在封装类中的函数时,对于静态函数来说,需要指明类域,最后的取地址可以加也可以不加。
对于普通函数来说,需要在参数中加一个类类型,用于接收一个对象(因为需要对象来调用函数),通常传入一个匿名对象。
需要使用取地址符,为了便于记忆,通常静态函数和动态函数都加取地址符。

2.bind(绑定)

绑定函数的作用有两个,一个是改变参数顺序,还有就是改变参数个数。

int sub(int a, int b)
{return a - b;
}
function<int(int, int)> f1 = sub;
cout << f1(10, 3) << endl;
function<int(int, int)> f2 = bind(sub, placeholders::_2, placeholders::_1);//将两个参数调换位置
cout << f2(10, 3) << endl;

通过bind函数中的placeholders参数,可以调换参数位置:
在这里插入图片描述
bind还可以改变参数个数:

	function<int(int, int)> f5 = bind(&Sub::add,s, placeholders::_1, placeholders::_2);//即使用add来进行占位cout << f5(10, 3) << endl;

在这里插入图片描述
此时第一个参数为add是被写死了的。

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

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

相关文章

Feign的简单介绍及配置参数

contextId用于区分实例,类似beanName

mysql存储过程的写法

示例表 area_code_2022 &#xff1a; DROP TABLE IF EXISTS area_code_2022; CREATE TABLE area_code_2022 ( code bigint(12) unsigned NOT NULL COMMENT 区划代码, name varchar(128) NOT NULL DEFAULT COMMENT 名称, level tinyint(1) NOT NULL COMMENT 级别1-5,省市…

python识别选中文本

目标&#xff1a;识别鼠标选中区域的文本 be like : 这是我在模拟键鼠操作时遇到的情况&#xff0c;我需要根据某个位置返回的值进行判断&#xff0c;但是只是依赖pyautogui是做不到的。 方法一 经过上网冲浪寻找答案&#xff0c;被告知了此方法&#xff0c;经测试可行 impor…

Django项目想要在 Python Console里面进行操作 报错找不到对应模块

Django项目想要在 Python Console里面进行操作 报错找不到对应模块 问题描述 ModuleNotFoundError: No module named django ’ 问题原因 在进行对 Python console操作 进行管理查询要导入对应的模块&#xff0c;但是和项目中的models.py文件中的 导包引入 冲突了 导致在Py…

可持久化Trie

可持久化指的是可以记录所有的历史版本&#xff0c;即记录下来每一步操作后的状态 下图模拟过程 题目&#xff1a; 最大异或和 给定一个非负整数序列 a&#xff0c;初始长度为 N。 有 M 个操作&#xff0c;有以下两种操作类型&#xff1a; A x&#xff1a;添加操作&#xff0…

uniapp自用速查表 - 我的常用组件

纯私人class&#xff0c;公开文章是方便置顶.... <!-- 自定义导航栏 占位空间 --> <view class"navigationStyleCustomHeight alwaysOnTopBox0 bgColorForTheme"></view> <!-- 自定义导航栏 --> <view class"alwaysOnTopBox1 myNav…

java正则表达式简单使用

String email = "13072558368"; email = email.replaceAll("(\\d{3})\\d{6}(\\d{2})", "$1****$2"); System.out.println("email=" + email); email=130****68从第三个开始,计算6个数字,其中计算的6个数字用*替换String mobile = &q…

java public、protected、default、private

java 的访问控制符为了控制类还有类对应方法的访问做限制。如上的图表总结了类方法的访问控制范围,其实类的访问控制范围也是类似的情况。声明为public则不管外部包还是内部都能够访问,如果为default则只能本包内能够访问 关于类方法的访问范围,我们比较熟悉的是private还有…

java基于ssm的自助旅游管理系统

传统的旅游方式存在着漫无目的的寻找住、吃等问题&#xff0c;这样游客很累&#xff0c;也十分浪费时间。因此一个专门用来给游客介绍一些地方的景点、吃、住、特产等信息的在线旅游网站将给游客的出行选择带来极大的方便快捷。人们迫切能有一个旅游网站&#xff0c;解决旅游过…

linux软件包管理 实验报告

实验任务 对软件包进行一些基础操作 实验环境 一台centos7实验步骤 1.下载一个软件包进行实验 将软件包拖进去 查看是否存在 因为只是下载了软件包,并没有安装所以用qa并不能查找到软件包 2.查看安装包的基本信息 3.查看软件包安装在哪个路径 4.安装软件包 确认是否安装…

短期逆风造成了小鹏汽车的股价持续暴跌和错误定价

来源&#xff1a;猛兽财经 作者&#xff1a;猛兽财经 小鹏汽车2022年第二季度财务业绩分析 小鹏汽车近期发布的2022年第二季度财报显示&#xff0c;营收超过预期&#xff0c;但收益未达到预期。第二季度营收为11.1亿美元&#xff0c;略高于预期&#xff0c;而每股收益亏损为0.…

node-sass安装报错及其解决方案

一、下载依赖报错 这里报错了也就没后面的剧情了,就像电视剧刚开局主角就嗝屁了,看看执行 npm i 的时候报错类容: 二、解决方案 1、下载源在国外,更换中国镜像源,删除package.json中的node-sass,分别下载node包和node-sass的依赖包1 //更换淘宝镜像源 2 npm config set re…

【牛客 - 剑指offer】JZ61 扑克牌顺子 两种方案 Java实现

文章目录剑指offer题解汇总 Java实现本题链接题目方案一 哈希表方案二 排序剑指offer题解汇总 Java实现 https://blog.csdn.net/guliguliguliguli/article/details/126089434 本题链接 知识分类篇 - 模拟 - JZ61 扑克牌顺子 题目 题目主要信息 两副扑克牌抽五张&#xff0…

图像处理之直方图均衡

直方图均衡是一种将图像中的灰度分布转换成均匀分布&#xff0c;从而增强图像的对比度的图像处理方法。直方图均衡可以将原本偏白或者偏黑的图像转换成对比度符合人眼视觉的图像。 1 原理 连续空间   连续空间内的图像灰度r∈[0,L−1]&#xff0c;L表示灰度级r\in[0,L-1]&a…

上线记 | 人大金仓助力东莞卫生健康领域核心系统改造升级

随着人工智能、云计算、大数据、机器学习等新兴技术在医疗信息化建设中不断深入&#xff0c;以患者为中心、构建智慧医院、提升医院信息智能化问题迫在眉睫。为进一步深化医改工作&#xff0c;加强妇幼卫生信息管理&#xff0c;东莞市卫生健康局对东莞妇幼卫生信息平台进行了国…

[leetcode top100] 0923 多数元素,反转链表,翻转二叉树,回文链表,移动零

目录 169. 多数元素 - 力扣&#xff08;LeetCode&#xff09; 206. 反转链表 - 力扣&#xff08;LeetCode&#xff09; 226. 翻转二叉树 - 力扣&#xff08;LeetCode&#xff09; 234. 回文链表 - 力扣&#xff08;LeetCode&#xff09; 283. 移动零 - 力扣&#xff08;Le…

2106. 摘水果(每日一难phase-day22)

2106. 摘水果 在一个无限的 x 坐标轴上&#xff0c;有许多水果分布在其中某些位置。给你一个二维整数数组 fruits &#xff0c;其中 fruits[i] [positioni, amounti] 表示共有 amounti 个水果放置在 positioni 上。fruits 已经按 positioni 升序排列 &#xff0c;每个 positi…

3. 链表

链表是一种通过指针串联在一起的线性结构,每一个结点由两部分组成,一个是数据域一个是指针域(存放指向下一个节点的指针),最后一个结点的指针域指向null(空指针的意思)。  1. 链表基础单链表:指针域只指向结点的下一个结点。双链表:每一结点有两个指针域,一个指向下…

记批处理修改计算机名一次蠢操作造成电脑指定的域不存在或无法联系

近日,公司电脑需要修改计算机名(无域控),随意在网上找了一篇修改代码,正常操作右击脚本管理员运行,输入计算机名可正常修改,但是如果运行后不输入计算机名直接点确认,则会造成计算机重启后无法登陆,提示指定的域不存在或无法联系,刚好公司也有这种坑货的存在。虽然不…

java基于ssm 的留学资讯申请网的设计与实现

随着计算机信息化的深入&#xff0c;越来越多的行业使用管理系统来进行管理。出国留学逐渐成为许多大学生的热门选择&#xff0c;但是国外学校多&#xff0c;选择性大&#xff0c;如果从这些信息中&#xff0c;挑选符合自己的学校是非常重要的事情。基于此&#xff0c;开发”萨…