当前位置: 首页 > news >正文

第十四章 重载运算与类型转换

14.1

不同点:重载运算符至少有一个操作数是类类型,而且对于部分运算符它无法保留求值顺序或短路求值属性

相同点:对于一个重载运算符来说,其优先级和结合律与对应的内置运算符保持一致

 

14.2

 1 #include <iostream>
 2 #include <vector> 
 3 #include <string>
 4  
 5 using namespace std;
 6 
 7 class Sales_data { 
 8     friend istream &operator>>(istream &is, Sales_data&);
 9     friend ostream &operator<<(ostream &os, Sales_data&);
10 public:
11     //构造函数 
12     Sales_data() = default;
13     //重载运算符
14     Sales_data &operator+=(const Sales_data&);
15 private:
16     string bookNo;                //书的ISBN 
17     unsigned units_sold = 0;    //售出的本数 
18     double revenue = 0.0;        //销售额
19 };
20 
21 istream &operator>>(istream &is, Sales_data &book)
22 {
23     is >> book.bookNo >> book.units_sold >> book.revenue;
24     return is;
25 }
26 
27 ostream &operator<<(ostream &os, Sales_data &book)
28 {
29     os << book.bookNo << " " << book.units_sold << " " << book.revenue;
30     return os;
31 }
32 
33 Sales_data &Sales_data::operator+=(const Sales_data &rhs)
34 {
35     units_sold += rhs.units_sold;
36     revenue += rhs.revenue;
37     return *this;
38 }
39 
40 Sales_data operator+(const Sales_data &lhs, const Sales_data &rhs)
41 {
42     Sales_data total = lhs;
43     total += rhs;
44     return total;
45 }
46 
47 
48 int main()
49 {
50     Sales_data a;
51     cin >> a;
52     Sales_data b, c;
53     b = a;
54     c = a + b;
55     cout << a << endl << b << endl << c << endl;
56     return 0;
57 }
View Code

 

14.3

(a):使用了内置版本的==,比较两个指针

(b):使用了string重载的==

(c):使用了vector重载的==

(d):使用了string重载的==

 

14.4

应该是类的成员:%=、++、->、()

 

14.9

istream &operator>>(istream &is, Sales_data &book)
{
	is >> book.bookNo >> book.units_sold >> book.revenue;
	if (!is)
		book = Sales_data();
	return is;
}

 

14.10

(a):正确

(b):由于const char*不能转换为double,所以读取操作失败,对象将被赋予默认的状态

 

14.11

存在错误,这个定义函数没有实现对输入数据正确性的判断

如果给定上个练习的(b),则revenue的值将是未定义的

 

14.13

可以定义一个减法运算符

Sales_data &Sales_data::operator-=(const Sales_data &rhs)  
{  
    units_sold -= rhs.units_sold;  
    revenue -= rhs.revenue;  
    return *this;  
}
Sales_data operator-(const Sales_data &lhs, const Sales_data &rhs)  
{  
    Sales_data sub = lhs;  
    sub -= rhs;  
    return sub;  
} 

 

14.14

使用operator+=来定义operator+比较好,可以省去重复完成operator+中做的事

 

14.20

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

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

 

14.21

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

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

缺点:可读性较差

 

14.22

Sales_data &Sales_data::operator=(const string &s)
{
	bookNo = s;
	return *this;
}

 

14.23

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

 

14.26

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

 

14.27

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

StrBlobPtr &StrBlobPtr::operator++()  
{  
    check(curr, " increment past end of StrBlobPtr ");  
    ++curr;  
    return *this;  
}  
StrBlobPtr &StrBlobPtr::operator--()  
{  
    --curr;  
    check(-1, " decrement past begin of StrBlobPtr ");    
    return *this;  
}  

StrBlobPtr StrBlobPtr::operator++(int)  
{  
    StrBlobPtr ret = *this;  
    ++*this;  
    return ret;  
}  
StrBlobPtr StrBlobPtr::operator--(int)  
{  
    StrBlobPtr ret = *this;  
    --*this;  
    return ret;  
} 

 

14.29

对于++和--运算符,无论是前缀版本还是后缀版本,都会改变调用对象本身的值,因此是不能定义成const的。

 

14.31

对于StrBlobPtr类,它的数据成员有两个,分别是weak_ptr<vector<string>>和size_t类型的,前者定义了自己的拷贝构造函数、赋值运算符和析构函数,后者是内置类型。所以该类不需要定义析构函数,从而相应的拷贝构造函数、赋值运算符也不需要定义,使用相应的合成版本即可。

 

14.33

与相应的函数调用运算符的形参数目一致

 

14.34

#include <iostream>
 
using namespace std;

class A {
public:
	string operator()(size_t i, string s1, string s2) const 
	{
		return i % 2 ? s1 : s2;
	}
};

int main()
{
	A a;
	string s = a(1, "odd", "even");
	cout << s << endl; 
    return 0;
}

 

14.35

#include <iostream>
#include <vector> 
#include <string>
 
using namespace std;

class A {
public:
	A(istream &in = cin): is(in) {}
	string operator()()
	{
		string line;
		getline(is, line); 
		if (!is)
			line = "";
		return line;
	}
private:
	istream &is;
};

int main()
{
	A a;
	cout << a() << endl;
    return 0;
}

 

14.36

int main()
{
	A a;
	vector<string> vec;
	string s = a();
	while (s != "") {
		vec.push_back(s);
		s = a();
	}
	for (auto &i : vec)
		cout << i << endl;
    return 0;
}

 

14.37

#include <iostream>
#include <vector> 
#include <string>
#include <list>
#include <algorithm>
 
using namespace std;

class A {
public:
	A() = default;
	A(int i): val(i) {}
	bool operator()(const int &a)
	{
		return val == a;
	}
private:
	int val;
};

int main()
{
	list<int> lst = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
	//将lst中值为2的元素替换为22 
	replace_if(lst.begin(), lst.end(), A(2), 22); 
    return 0;
}

 

14.38

#include <iostream>
#include <fstream>
#include <vector> 
#include <string>
#include <list>
#include <algorithm>
 
using namespace std;

class A {
public:
	int operator()(const string &s)
	{
		return s.size();
	}
};

int main()
{
	ifstream in("data.txt");
	int arr[30] = {0};
	A a;
	string word;
	while (in >> word) {
		int pos = a(word);
		++arr[pos];
	}
	for (int i = 1; i != 11; ++i)
		cout << "长度为" << i << "的单词的个数是:" << arr[i] << endl;
	return 0; 
}

 

14.39

#include <iostream>
#include <fstream>
#include <vector> 
#include <string>
#include <list>
#include <algorithm>
 
using namespace std;

class A {
public:
	bool operator()(const string &s)
	{
		if (s.size() < 10)
			return true;
		return false;
	}
};

int main()
{
	ifstream in("data.txt");
	int num1 = 0, num2 = num1;
	A a;
	string word;
	while (in >> word) {
		bool flag = a(word);
		if (flag)	++num1;
		else ++num2;
	}
	cout << "长度小于10的单词的个数是:" << num1 << endl;
	cout << "长度大于10的单词的个数是:" << num2 << endl;
	return 0; 
}

 

14.40

class A {
public:
	bool operator()(const string &s1, const string &s2)
	{
		return s1.size() < s2.size();
	}
}; 

class B {
public:
	A(int i): sz(i) {} 
	bool operator()(const string &s)
	{
		return s.size() >= sz;
	}
private:
	int sz;
};

class C {
public:
	void operator()(const string &s)
	{
		cout << s << " ";
	}
};

void biggies(vector<string> &words, vector<string>::size_type sz)
{
	stable_sort(words.begin(), words.end(), A());
	auto wc = find_if(words.begin(), words.end(), B(sz));
	for_each(wc, words.end(), C());
}

 

14.41

在C++11中,lambda是通过匿名的函数对象来实现的,因此我们可以把lambda看作是对函数对象在使用方式上进行的简化。当代码需要一个简单的函数,并且这个函数并不会在其他地方被使用时,就可以使用lambda来实现,此时它所起的作用类似于匿名函数。但如果这个函数需要多次使用,并且它需要保存某些状态的话,使用函数对象更合适一些。

即,lambda表达式方便创建、使用,不需要额外的为调用对象声明类;在一次性需要使用函数对象时使用lambda,在多次需要使用到相同的函数对象时使用类。

 

14.42

	vector<int> ivec{520, 1020, 1030};
	vector<string> svec{"pooh", "pooh", "pool", "pooh", "poow"};
	auto num = count_if(ivec.begin(), ivec.end(), bind(greater<int>(), _1, 1024));
	auto it = find_if(svec.begin(), svec.end(), bind(not_equal_to<string>(), _1, "pooh"));
	transform(ivec.begin(), ivec.end(), ivec.begin(), bind(multiplies<int>(), _1, 2));

 

14.43

int main()
{
	vector<int> ivec{520, 1020, 1030};
	int div;
	cin >> div;
	//返回取余结果为0的数的个数 
	int num = count_if(ivec.begin(), ivec.end(), bind(modulus<int>(), _1, div));
	if (!num)
		cout << "全部可整除" << endl;
	else	cout << "不能全部被整除" << endl; 
	return 0; 
}

 

14.44

#include <iostream>
#include <map>
#include <functional>

using namespace std;

map<string, function<int (int, int)>> binops;

class multiply {
public:
	int operator()(int a, int b) const { return a * b; }
};

int add(int a, int b)
{
	return a + b;
}

auto divide = [](int a, int b) { return a / b; };

void func()
{
	binops.insert({"+", add});
	binops.insert(make_pair("-", minus<int>()));
	binops.insert(pair<string, function<int (int, int)>>("*", multiply()));
	binops.insert(map<string, function<int (int, int)>>::value_type("/", divide));
	binops.insert({"%", [](int a, int b) { return a % b; }});
}

int main()
{
	func();
	cout << "请按照此形式(如:a + b)输入计算表达式:\n";
	int a, b;
	string s;
	while (cin >> a >> s >> b) {
		cout << binops[s](a, b) << endl;
		cout << "请按照此形式(如:a + b)输入计算表达式:\n";
	}
	return 0;
} 

 

 

14.45

	operator string() const { return bookNo; }
	operator double() const { return revenue; }

 

14.46

Sales_data不应该定义这两种类型转换运算符,因为对于类来说,它包含三个数据成员:bookNo,units_sold和revenue,只有三者在一起才是有效的数据。但是如果确实想要定义这两个类型转换运算符的话,应该把它们声明成explicit的,这样可以防止sales_data 在默写情况下被默认转换成string或double类型,这有可能导致意料之外的运算结果。

 

14.47

operator const int();:将对象转换成const int,没有意义,因为只有在接受const int值的地方才能够使用

operator int() const:将对象转换成int值,const 表示转换时不会修改对象数据

 

14.50

对于int ex1 = ldObj;,它需要把LongDouble类型转换成int类型,但是LongDouble并没有定义对应的类型转换运算符,因此它会尝试使用其他的来进行转换。题中给出的两个都满足需求,但编译器无法确定那一个更合适,因此会产生二义性错误。

对于float ex2 = ldObj;,它需要把LongDouble转换成float类型,而我们恰好定义了对应的类型转换运算符,因此直接调用operator float()即可。

 

14.51

这里会优先调用void calc(int);

因为double转换为int是标准类型转换,而转换为LongDouble则是转换为用户自定义类型,实际上调用了转换构造函数,因此前者优先。

 

14.52

ans1:

对于ld=si+ld,由于LongDouble不能转换为SmallInt,因此Smallint的成员operator+和friend operator都不可行。

由于Smallint不能转换为LongDouble,LongDouble的成员operator+和非成员operator+也都不可行。

由于SmallInt可以转换为int, LongDouble了可以转换为float和double,所以内置的operator+(int, float)和operator+(int, double)都可行,会产生二义性。

对于ld=ld+si,类似上一个加法表达式,由于Smallint不能转换为double,LongDouble也不能转换为SmallInt,因此SmallInt的成员operator+和两个非成员operator+都不匹配。

LongDouble的成员operator+可行,且为精确匹配。
SmallInt可以转换为int,longDouble可以转换为float和double,因此内置的operator+(float, int)和operator(double, int)都可行。但它们都需要类型转换,因此LongDouble的成员operator+优先匹配。

ans2:

ld=si+ld;二义性,si将转换为int,但ld可以转换为double也可以使float

ld=ld+si;精确匹配LongDouble operator+(const SmallInt &);,虽然使用后面的也可以,但是需要转换,所以前者更好

 

14.53

内置的operator+(int, double)是可行的,而3.14可以转换为int,然后再转换为SmallInt,所以SmallInt的成员operator+也是可行的。两者都需要进行类型转换,所以会产生二义性。改为:double d = s1 +Smallint(3.14);即可。

 

转载于:https://www.cnblogs.com/xzxl/p/7768689.html

相关文章:

  • 使用类的思想来重构asp网站开发
  • android129 zhihuibeijing 聊天机器人
  • 【转】nios II架构uclinux的过程
  • 开发人员学Linux(4):使用JMeter对网站和数据库进行压力测试
  • 项目选题报告
  • [转载]精益求精Sybase数据库标题大包括-6
  • Android基础:SQLites数据库事物处理的优越性
  • DB2 9 利用斥地(733 测验)认证指南,第 9 部分: 用户定义的例程(2)
  • JS区别IE6、IE7、IE8之间的方法
  • 基础算法10:过滤器(Filter)对指定路径不进行过滤
  • Asp.net用户多次登录问题
  • 如何应对被地下的Oracle口令加密算法(1)
  • Haproxy+Keepalived+Jboss集群实施架构一例
  • Solaris10下载、安设和设置装备摆设(2)
  • 深入浅出多线程系列之六:事件驱动异步模式(EAP,WebClient,BackgroundWorker)
  • php的引用
  • [LeetCode] Wiggle Sort
  • Elasticsearch 参考指南(升级前重新索引)
  • express + mock 让前后台并行开发
  • Java多态
  • Linux后台研发超实用命令总结
  • PAT A1050
  • react-core-image-upload 一款轻量级图片上传裁剪插件
  • SpingCloudBus整合RabbitMQ
  • Travix是如何部署应用程序到Kubernetes上的
  • Vue UI框架库开发介绍
  • vuex 学习笔记 01
  • windows下使用nginx调试简介
  • Zepto.js源码学习之二
  • 浏览器缓存机制分析
  • 猫头鹰的深夜翻译:Java 2D Graphics, 简单的仿射变换
  • 微信小程序--------语音识别(前端自己也能玩)
  • 为视图添加丝滑的水波纹
  • 想晋级高级工程师只知道表面是不够的!Git内部原理介绍
  • 栈实现走出迷宫(C++)
  • Nginx惊现漏洞 百万网站面临“拖库”风险
  • 不要一棍子打翻所有黑盒模型,其实可以让它们发挥作用 ...
  • (01)ORB-SLAM2源码无死角解析-(56) 闭环线程→计算Sim3:理论推导(1)求解s,t
  • (32位汇编 五)mov/add/sub/and/or/xor/not
  • (Redis使用系列) Springboot 使用redis实现接口Api限流 十
  • (二)pulsar安装在独立的docker中,python测试
  • (附源码)python房屋租赁管理系统 毕业设计 745613
  • (附源码)spring boot智能服药提醒app 毕业设计 102151
  • (附源码)计算机毕业设计ssm高校《大学语文》课程作业在线管理系统
  • (三) prometheus + grafana + alertmanager 配置Redis监控
  • (转)ABI是什么
  • .NET Standard 支持的 .NET Framework 和 .NET Core
  • .NET/C# 避免调试器不小心提前计算本应延迟计算的值
  • //解决validator验证插件多个name相同只验证第一的问题
  • @Autowired和@Resource的区别
  • [ JavaScript ] JSON方法
  • [ MSF使用实例 ] 利用永恒之蓝(MS17-010)漏洞导致windows靶机蓝屏并获取靶机权限
  • [Asp.net mvc]国际化
  • [codevs 1296] 营业额统计
  • [Erlang 0129] Erlang 杂记 VI 2014年10月28日