13.6-14.8读书笔记

news2024/10/5 15:27:08

13.6 对象移动

13.6.1 右值引用

概念: 为了支持移动操作,新标准引入了的一种新的引用类型.所谓右值引用就是必须绑定到右值的引用. 通过&&来获得右值引用

    int i = 42;
    int &r = i;
    int &&rr = i;     // 错误,不能将一个右值引用绑定到一个左值上
    int &r3 = i * 42; // 错误,i*42是个右值
    const int &r3 = i * 42;
    int &&rr2 = i * 42;

标准库move函数

虽然不能将一个右值引用直接绑定到一个左值上,但我们可以显式地将一个左值转换为对应的右值引用类型. 可以通过调用一个名为move的新标准库函数来获得绑定到左值上的右值引用

    int &&rr1 = 42;
    int &&rr3 = std::move(rr1);

移动构造函数和移动赋值运算符

移动构造函数的第一个参数是该类类型的一个引用.这个引用参数在移动构造函数中是一个右值引用

移动赋值运算符执行与析构函数和移动构造函数相同的工作

重载和引用函数

class Foo {
public:
    Foo &operator=(const Foo&) & {
        return *this;
    }
    // 可用于可改变的右值
    Foo sorted() && {
        sort(data.begin(), data.end());
        return *this;
    }
	// 可用于任何类型的foo
    Foo sorted() const & {
        Foo ret(*this);
        sort(ret.data.begin(), ret.data.end());
        return ret;
    }


private:
    vector<int> data;
};

Foo &retFoo() {

    Foo tmp;
    Foo &ret = tmp;
    return ret;
}

Foo retVal() {
    Foo ret;
    return ret;
}
int main()
{
    retVal().sorted();
    retFoo().sorted();
    return 0;
}

14.1 基本概念

在这里插入图片描述

在什么情况下重载的运算符与内置运算符有所区别?在什么情况下重载的运算符又与内置运算符一样?

我们可以直接调用重载运算符函数。重置运算符与内置运算符有一样的优先级与结合性。

ring 和 vector 都定义了重载的== 以比较各自的对象,假设 svec1 和 svec2 是存放 string 的 vector,确定在下面的表达式中分别使用了哪个版本的==?
a) “cobble” == “stone”
(b) svec1[0] == svec2[0]
(c ) svec1 == svec2
(d) "svec1[0] == “stone”

(a) 都不是。
(b) string
(c ) vector
(d) string

14.2 输入和输出运算符

14.2.1 重载输出运算符<<

第一个形参是一个非常量的ostream对象的引用, 第二个形参一般来说是一个常量的引用; 一般要返回它的ostream形参

ostream &operator<<(ostream &os, const Sales_data &item) {
	os << item.isbn() << " " << item.units_old << " " << item.revenue << " " << item.avg_price();
	return os;
}

输入输出运算符必须是非成员函数, 而不能是类的成员函数. 假设输入输出运算符是某个类的成员,则它们也必须是istreamostream的成员. 然而,这两个类属于标准库,并且我们无法为标准库中的类添加任何成员

14.2.2 重载输入运算符

第一个形参运算符将要读取的流的引用,第二个形参是将要读入到的(非常量)对象的引用

istream &operator >> (istream &is, Sales_data &item) {
	double price;
	is >> item.bookNo >> item.unites_sold >> price;
	if (is) {
		item.revenue = item.units_sold * price;
	} else {
		item = Sales_data();
	}
	return is;
}

14.3 算术和关系运算符

通常,我们把算术和关系运算符定义非成员函数以允许对左侧或右侧的运算对象进行转换;

Sales_data operator+(const Sales_data &lhs, const Sales_data &rhs) {
	Sales_data sum = lhs;
	sum += rhs;
	return sum;
}

14.3.1 相等运算符

用来检验两个对象是否相等

bool operator ==(const Sales_data &lhs, const Sales_data &rhs) {
	return lhs.isbn() == rhs.isbn() && lhs.units_sold == rhs.unites_sold && lhs.revenue == rhs.revenue;
}
bool operator !=(const Sales_data &lhs, const Sales_data &rhs) {
	return !(lhs == rhs)	
}

14.4 赋值运算符

和拷贝赋值及移动赋值运算符一样,其他重载赋值运算符也必须释放当前内存空间,再创建一片新空间.

StrVec &StrVec::operator=(initialize_list<string> il)
{
	auto data = alloc_n_copy(il.begin(), il.end());
	free();
	elements = data.first;
	first_free = cap = data.second;
	return *this;
}

复合赋值运算符

Sales_data &Sales_data::operator += (const Sales_data &rhs) {
	units_sold += rhs.units_sold;
	revenue += rsh.revenue;
	return *this;
}

14.5 下标运算符

表示容器的类通常可以通过在容器中的位置访问元素, 这些类一般会定义下标运算符[], 下标运算符必须是成员函数

class StrVec {
public:
	std::string &operator[](std::size_t n) { return elements[n];}
	const std::string &operator[](std::size_t n) const { return elements[n];}
private:
	std::string *elements;
}

14.6 递增和递减运算符

两种运算符使得类可以在元素的序列中前后移动. C++语言并不要求递增和递减运算符必须是类的成员,但是因为它们改变的正好是所操作对象的状态,所以建议将其设定为成员函数

class StrBlobPtr {
public:
	StrBlobPtr &operator++(); //前置运算符
	StrBlobPtr &operator--();	
};

区分前置和后置运算符
后置版本接受一个额外的(不被使用)int类型的形参.

class StrBolbPtr {
public:
	StrBlobPtr operator++(int); //后置运算符
	StrBlobPtr operator--(int);	
};

显式地调用后置运算符

StrBlobPtr p(a1);
p.operator++(0); // 后置版本的operator++;
p.operator++();  // 前置版本的operator++;

14.7 成员访问运算符

class StrBlobPtr {
	sdt::string &operator*() const {
		auto p = check(curr, "dereference past end");
		return (*p)[curr];
	}
	std::string *operator->() const {
		return & this->operator*();
	}
};

14.8 函数调用运算符

如果类重载了函数调用运算符,则我们可以像使用函数一样使用该类的对象

struct absInt {
	int operator()(int val) const {
		return val < 0 ? -val : val;
	}
}
int i = -42;
absInt absObj;
int ui = absObj(i);

14.8.1 lambda是函数对象

lambda表达式产生的类中含有一个重载的函数调用运算符

string words;
stable_sort(word.begin(), word.end(), [](const string &a, const string &b) 
{return a.size() < b.size();});

// 其行为类似于下面这个未命名对象
class ShorterString {
public:
	bool operator() (const string &s1, const string &s2) const {
		return s1.size() < s2.size();
	}
};

// 用类代替lambda表达式后
stable_sort(word.begin(), word.end(), ShorterString());

14.8.2 标准库定义的函数对象

在这里插入图片描述

14.8.3 可调用对象与function

不同类型可能具有相同的调用形式

// 普通函数
int add(int i, int j) {return i + j;}
// lambda,产生一个未命名函数对象类
auto mod = [](int i, int j){ return i % j;}
// 函数对象类
struct divide {}
	int operator()(int denominator, int divisor) {
		return denominator / divisor;
	}
;

// 构建从运算符到函数指针的映射关系,其中函数接受两个int,返回一个int
map<string, int(*)(int, int)> binops;

但是我们不能将mod或者divide存入binops,因为mod是个lambda表达式,而每个lambda有它自己的类类型,与存储在binops中的值的类型不匹配
标准function
在这里插入图片描述

map<string, function<int(int,int)>> binops = {
	{"+", add},
	{"-", std::minus<int>()},
	{"/" devide()},
	{"*", [](int i, int j){return i * j;}},
	{"%", mod}
};

我们的map中包含5个元素,尽管其中可调用的类型各不相同,我们仍然能够把所有这些类型都存储在一个function<int(int,int)>类型中

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

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

相关文章

【python基础_05】面向对象

文章目录1. 类和对象1.1 使用对象组织数据的模版1.2 成员变量和成员方法1.3 实现代码2. 内置方法&#xff08;魔术方法&#xff09;2.1 构造方法&#xff1a;__init__&#xff08;&#xff09;1. 类和对象 1.1 使用对象组织数据的模版 1.2 成员变量和成员方法 1.3 实现代码 1…

jupyter notebook无法启动内核

jupyter notebook无法启动内核问题概述方法一使用Window PowerShell方法二更改文件路径重新启动内核参考问题概述 遇到的问题是在使用jupyter的时候无法正常运行,所以在这里尝试一些办法,在这里进行记录,希望能够帮助到大家 方法一 使用Window PowerShell 首先第一个方法就…

Java IO流 - 释放资源的方式

资源释放的方式 书接上文, 在上一篇文章我们做过一个文件拷贝的练习, 但是在联系中是有释放资源隐患的的, 例如在下面代码中, 在文件释放之前有许多行的逻辑代码; 如果这许多行的逻辑代码有报错, 导致程序不运行, 那么资源就得不到释放 public static void main(String[] args)…

Crack:ActiveReportsJS 3.2.2 EN:ActiveReportsJS

ActiveReportsJS - 高级 JavaScript 报告解决方案 ActiveReportsJS 是一种用于在前端应用程序中可视化数据的报告解决方案。Ω578867473自定义报告布局并将我们的报告设计器和查看器组件集成到 Web 应用程序中&#xff0c;以便在任何平台上预览、导出或打印报告。 使用我们的跨…

WPF+ASP.NET SignalR实现动态折线图

在实际业务中&#xff0c;当后台数据发生变化&#xff0c;客户端能够实时的收到通知&#xff0c;而不是由用户主动的进行页面刷新才能查看&#xff0c;这将是一个非常人性化的设计。有没有那么一种场景&#xff0c;后台数据明明已经发生变化了&#xff0c;前台却因为没有及时刷…

ElementUI——案例2用户管理(基于SpringBoot实现增删改)

1.ElementUI整合SpringBoot前后端分离实现用户增删改查 效果展示 2.前端核心代码 项目目录 main.js引入 import ElementUI from element-ui; import element-ui/lib/theme-chalk/index.css; import router from ./router import axios from axiosVue.prototype.$http ax…

SQL 存储过程

文章目录存储过程简介存储过程的创建及调用存储过程的删除 如何删除存储过程存储过程的优缺点现需要向学生表中插入新的学生数据。但在插入学生数据的时&#xff0c;需要同 时检查老师表里的数据。如果插入学生的老师不在老师表里&#xff0c;则先向老师表中插入一条老师数据&a…

高级IO-多路转接

高级IO 以前的都是拷贝接口。write什么的就是将字符串拷贝到发送缓冲区中。 应用层等待接收缓冲区填写数据的过程算是IO吗&#xff1f;算 IO等待拷贝数据&#xff1b; 真正的IO的过程就是拷贝的过程。比如等待鱼上钩的时候也算是钓鱼(adj)&#xff0c;当把鱼拿上来的时候也…

【Spring篇】代理模式

&#x1f353;个人主页&#xff1a;个人主页 &#x1f352;系列专栏&#xff1a;SSM框架 目录 一、场景模拟 二、提出问题 三、代理模式 1.静态代理 2.动态代理 一、场景模拟 ①声明接口 声明计算器接口Calculator&#xff0c;包含加减乘除的抽象方法 public interface…

hadoop基础搭建(hadoop+hive+hbase+zk)(一)

文章目录一、基础环境&插件安装&#xff08;root&#xff09;二、创建启动脚本&#xff0c;后续使用三、安装JDK&#xff08;root&#xff09;四、安装Hadoop五、安装 rsync&#xff08;root&#xff09;六、网络配置&#xff08;4台服务器&#xff0c;root&#xff09;七、…

使用html2canvas,将页面转换成图片的采坑记录(Web/Taro h5)

使用html2canvas将页面转换成图片的采坑记录 "html2canvas": "^1.4.1","tarojs/taro": "3.4.0-beta.0"问题: 1. 生成的图片很模糊 2. 生成的图片是空白 3. 生成的图片不完整 截图前是这样 截图后这样 截图后的图片图片缺省了一部分…

【消息中间件】1小时快速上手RabbitMQ

前 言 &#x1f349; 作者简介&#xff1a;半旧518&#xff0c;长跑型选手&#xff0c;立志坚持写10年博客&#xff0c;专注于java后端 ☕专栏简介&#xff1a;深入、全面、系统的介绍消息中间件 &#x1f330; 文章简介&#xff1a;本文将介绍RabbitMQ&#xff0c;一小时快速上…

Good Bye 2022: 2023 is NEAR D. Koxia and Game

原题链接&#xff1a;Problem - D - Codeforces 题面&#xff1a; 大概意思就是给你一个数组a和数组b&#xff0c;你自己设计一个数组c&#xff0c;Koxia可以从a[i]、b[i]和c[i]中选一个&#xff0c;而Mahiru只能从另外两个里选一个&#xff0c;问你有多少个数组c一定能使Mah…

给GitHub装扮个性化首页

我的主页 如何配置 需要创建一个仓库&#xff0c;仓库名要跟GitHub的用户名一样,我的已经创建过了 喜欢我的主页可以直接fork然后在自己的仓库修改&#xff0c;如果想自己装扮直接看下一步 地址&#xff1a;https://github.com/linweiqian 开始装扮 下面展示仓库状态统计的设…

工业控制系统安全控制应用缩略语汇总

声明 本文是学习GB-T 32919-2016 信息安全技术 工业控制系统安全控制应用指南. 下载地址 http://github5.com/view/585而整理的学习笔记,分享出来希望更多人受益,如果存在侵权请及时联系我们 工业控制系统安全控制应用缩略语 ICS 工业控制系统&#xff08;Industrial Contro…

线程的高效利用——线程池

文章目录线程的开销线程池的工作方式ThreadPoolExecutor基础线程池结果的处理线程的开销 线程作为一种昂贵的资源&#xff0c;开销包括如下几点&#xff1a; 1、线程的创建与启动的开销。 2、线程的销毁的开销。 3、线程调度的开销。线程的调度会产生上下文切换&#xff0c;从…

skywalking解析-入门

前几天从github上看最近比较火的项目&#xff0c;发现了skywalking&#xff0c;就进行了些了解&#xff0c;发现这个领域自己目前知之甚少&#xff0c;打算通过对源码的分析深入了解一下分布式追踪。首先从对skywalking介绍开始。 目录一、简介二、整体架构三、源码下载四、系统…

spark-RDD学习笔记

本文是19年学生时学习林子雨老师课程中的一些学习笔记&#xff0c;主要内容包括RDD的概念和运行原理,rdd相关编程api接口以及对应的实例。关于RDD的内容&#xff0c;这个笔记描述的2019年年底之前的pyspark版本&#xff0c;2023年年初时在pyspark的实际工作中rdd已经很少用或者…

【Kafka】Kafka概述

一、闲话 这是2023年的第一篇博客&#xff0c;祝大家在新的一年里一帆风顺&#xff0c;身体健康 二、基本要点 1、Kafka概述 Kafka是一个分布式的基于发布/订阅模式的消息队列(Message Queue)&#xff0c;主要用于大数据实时处理领域 2、消息队列的好处 解耦&#xff1a;…

CAS原理、实践、缺陷分析及优化

文章目录CAS介绍CAS在Java中的底层实现Java源码中使用举例自己实际运用乐观锁举例简单的CAS操作ABA问题及优化实践缺陷及优化只能保证单个变量操作原子性当比较失败后,通常需要不断重试,浪费CPUCAS介绍 CAS(Compare And swap),比较并交换,是一种乐观锁.它是解决多线程并行情况…