C++ Prime 第十四章 重载运算符与类型转换

2023-05-17~2023-05-18

14.1节练习

alt

练习14.1:

相同点:重载后运算符的优先级、结合律不变 不同点:
1、对于重载后的运算符,必须是某个类的成员或者这个运算符的参数必须包含一个类类型
2、可以像调用普通函数一样调用重载后的运算符如 operator+(num1, num2)
3、重载后的运算符中的规则不再保留,如||、&&运算符的短路求值规则不在保留

练习14.2:

#include<iostream>
#include<map>
#include<vector>
#include<algorithm>
#include<utility>
using namespace std;


class Sales_Date {
public:
	friend Sales_Date& operator+(Sales_Date& s1, Sales_Date& s2);
	friend ostream& operator<<(ostream& out, Sales_Date& s);
	friend istream& operator>>(istream& in, Sales_Date& s);
	Sales_Date() = default;
	Sales_Date(const string& no, unsigned sold, double reve) : bookNo(no), units_sold(sold),
		revenue(reve) {};

	Sales_Date& operator+=(Sales_Date& s)
	{
		revenue += s.revenue;
		units_sold += s.units_sold;
		return *this;
	}

	istream& operator+=(istream& in)
	{
		cout << "输入revenue:" << endl;
		in >> revenue;
		cout << "输入units_sold:" << endl;
		in >> units_sold;
		return in;
	}

private:
	string bookNo;
	unsigned units_sold = 0.0;
	int revenue = 0;

};

Sales_Date& operator+(Sales_Date& s1, Sales_Date& s2)
{
	Sales_Date s;
	s.revenue = s1.revenue + s2.revenue;
	s.units_sold = s1.units_sold + s2.units_sold;
	return s;
}

ostream& operator<<(ostream& out, Sales_Date& s)
{
	out << "revenue: " << s.revenue << endl;
	out << "units_sold: " << s.units_sold << endl;
	return out;
}

istream& operator>>(istream& in, Sales_Date& s)
{
	cout << "输入revenue:" << endl;
	in >> s.revenue;
	cout << "输入units_sold:" << endl;
	in >> s.units_sold;
	return in;
}

void test()
{
	Sales_Date s1("qwer", 10, 20);
	Sales_Date s2("qwer", 20, 30);
	Sales_Date s3 = s1 + s2;
	cout << s3 << endl;
	s3 += s1;
	cout << s3 << endl;
	cin >> s3;
	cout << s3 << endl;
}

int main()
{
	test();
	system("pause");
	return 0;
}

练习14.3:

(a):string版本
(b):string版本
(c):vector版本
(d):string版本\

练习14.4:

对于运算符能够任意转换一端的对象的应该作为非成员运算符
非成员运算符:(a)、(b)、(f)、(g)
成员运算符:(b)、(c)、(d)、(e)

练习14.5:

略(基本和练习14.2中的Sales_data一样)

14.2.1节练习

alt

练习14.6:

见练习14.5

练习14.7:

class String
{	friend ostream& operator<<(ostream& out, String& s);
};
ostream& operator<<(ostream& out, String& s)
{
	for (auto iter = s.begin(); iter != s.end(); ++iter)
	{
		out << *iter << endl;;
	}
	return out;
}

练习14.8:

14.2.2节练习

alt

练习14.9:

见练习14.5

练习14.10:

(a)正常输入
(b)输入失败(第三个次输入是double类型,但是输入了一个非double类型的数据),会返回一个初始化的Sales_data对象

练习14.11:

没有检查输入是否成功,如果输入不规范的数据会导致程序退出

练习14.12:

class Book
{
public:
	int No;
};

istream& operator>>(istream& in, Book& b)
{
	in >> b.No;
	if (in)
	{
		return in;
	}
	else
	{
		cout << "输入错误" << endl;
		return in;
	}
}

14.3节练习

alt

练习14.13:

一些复合赋值运算符、定义略

练习14.14:

+= 不需要构造临时对象

练习14.15:

14.3.1节练习

alt

练习14.16:

全都类似Sales_data

bool operator==(const Sales_Date& s1, const Sales_Date& s2)
{
	return s1.bookNo == s2.bookNo && s1.revenue == s2.revenue && 
		s1.units_sold == s1.units_sold;
}

bool operator!=(const Sales_Date& s1, const Sales_Date& s2)
{
	return !(s1 == s2);
}

练习14.17:

14.3.2节练习

alt

练习14.18:

#include<iostream>
#include<vector>
#include<memory>
#include<set>
#include<map>
#include<string>
#include<algorithm>
#include<utility>
#include<initializer_list>
#include<fstream>
#include<sstream>
using namespace std;


class String
{
public:
	friend ostream& operator<<(ostream& out, String& s);
	friend bool operator==(String& s1, String& s2);
	friend bool operator!=(String& s1, String& s2);
	friend bool operator<(String& s1, String& s2);
	friend bool operator<=(String& s1, String& s2);
	friend bool operator>(String& s1, String& s2);
	friend bool operator>=(String& s1, String& s2);
	String() : elements(nullptr), first_free(nullptr), cap(nullptr) {};
	//2、有参构造函数:
	//2.1、参数是const char[]对象
	String(const char* p)
	{
		auto new_data = chk_n_copy(p);
		elements = new_data.first;
		first_free = cap = new_data.second;
	}
	//2.2、参数是initializer_list<char>&
	String(const initializer_list<char>& c)
	{
		auto new_data = chk_n_copy(c.begin(), c.end());
		elements = new_data.first;
		first_free = cap = new_data.second;
	}
	// 添加一个移动构造函数
	String(String&& s) noexcept :elements(s.elements), first_free(s.first_free),
		cap(s.cap)
	{
		cout << "移动构造函数" << endl;
		s.elements = s.first_free = s.cap = nullptr;
	}
	//3、拷贝构造函数
	String(const String& s)
	{
		cout << "拷贝构造函数" << endl;
		auto new_data = chk_n_copy(s.cbegin(), s.cend());
		elements = new_data.first;
		first_free = cap = new_data.second;
	}
	//添加一个移动赋值运算符
	String& operator=(String&& s)
	{
		if (this != &s)
		{
			cout << "移动赋值运算符" << endl;
			free();
			elements = s.elements;
			first_free = s.first_free;
			cap = s.cap;
			s.elements = s.first_free = s.cap = nullptr;
		}
		return *this;
	}
	//4、赋值运算符
	String& operator=(const String& s)
	{
		cout << "赋值运算符" << endl;
		auto new_data = chk_n_copy(s.cbegin(), s.cend());
		free();
		elements = new_data.first;
		first_free = cap = new_data.second;
		return *this;
	}
	//5、析构函数:
	~String() { free(); };
	char* elements;
	char* first_free;
	char* cap;
	//6、size函数
	size_t size() { return first_free - elements; };
	//7、capacity函数
	size_t capacity() { return cap - elements; };
	//8、resize函数
	void resize(size_t num, char c = '\0')
	{
		char* end_iter = nullptr;
		if (size() > num)
		{
			end_iter = first_free - (size() - num);
			for (auto p = first_free; p != end_iter;)
			{
				alloc.destroy(--p);
			}
		}
		else if (num > size() && num <= capacity())
		{
			end_iter = first_free + (num - size());
			for (auto p = first_free; p != end_iter;)
			{
				alloc.construct(p++, c);
			}
		}
		else if (num > size() && num > capacity())
		{
			reallocate_memory(num);
			end_iter = first_free + (num - size());
			for (auto p = first_free; p != end_iter;)
			{
				alloc.construct(p++, c);
			}

		}
		first_free = end_iter ? end_iter : first_free;
	}
	//9、reserve
	void reserve(size_t num) { if (num > capacity()) reallocate_memory(num); };
	//10、push_back函数
	void push_back(char c)
	{
		chk_n_alloc();
		alloc.construct(first_free++, c);
	}
	//11、clear函数
	void clear()
	{
		for_each(elements, first_free,
			[](const char& p) { alloc.destroy(&p);}
		);
		first_free = elements;
	}


	char* begin() const { return elements; };
	char* end() const { return first_free; };
	const char* cbegin() const { return elements; };
	const char* cend() const { return first_free; };
	void test();
private:
	static allocator<char> alloc;
	void free();
	pair<char*, char*> chk_n_copy(const char* p);
	pair<char*, char*> chk_n_copy(const char* b, const char* e);
	void reallocate_memory(size_t num);
	void chk_n_alloc();
};

// 静态对象类外初始化
allocator<char> String::alloc;

//14.1、free函数
inline void String::free()
{
	if (elements)
	{
		for_each(elements, first_free,
			[this](const char& c) { alloc.destroy(&c); }
		);
		alloc.deallocate(elements, cap - elements);
		elements = nullptr;
		first_free = nullptr;
		cap = nullptr;
	}

}

//14.2、chk_n_copy(const char* p))函数
inline pair<char*, char*> String::chk_n_copy(const char* p)
{
	auto elem = p;
	int str_length = 0;
	while (*elem != '\0')
	{
		++str_length;
		++elem;
	}
	auto new_data = alloc.allocate(str_length);
	return { new_data, uninitialized_copy(p, elem, new_data) };
}

//14.2、chk_n_copy(const char* p))函数,重载版本
inline pair<char*, char*> String::chk_n_copy(const char* b, const char* e)
{
	auto new_data = alloc.allocate(e - b);
	return { new_data, uninitialized_copy(b, e, new_data) };
}


//14.3、reallocate_memory(num)函数
inline void String::reallocate_memory(size_t num)
{
	auto new_data = alloc.allocate(num);
	auto dest = new_data;
	auto elem = elements;
	for (size_t i = 0; i < size(); ++i)
	{
		alloc.construct(dest++, std::move(*elem++));
	}
	free();
	elements = new_data;
	first_free = dest;
	cap = elements + num;
}

//14.4、chk_n_alloc函数
inline void String::chk_n_alloc()
{
	if (size() == capacity())
	{
		size_t new_capacity = size() ? size() * 2 : 1;
		reallocate_memory(new_capacity);
	}
}

ostream& operator<<(ostream& out, String& s)
{
	for (auto iter = s.begin(); iter != s.end(); ++iter)
	{
		out << *iter << endl;;
	}
	return out;
}


bool operator==(String& s1, String& s2)
{
	if (s1.size() != s2.size())
	{
		return false;
	}
	auto s1_iter = s1.begin();
	auto s2_iter = s2.begin();
	for (int i = 0; i < s1.size(); ++i)
	{
		if (*s1_iter != *s2_iter)
		{
			return false;
		}
		++s1_iter;
		++s2_iter;
	}
	return true;
}

bool operator!=(String& s1, String& s2)
{
	return !(s1 == s2);
}

bool operator<(String& s1, String& s2)
{
	auto s1_begin = s1.begin();
	auto s2_begin = s2.begin();
	if (s2.size() < s1.size())
	{
		auto same_flag = true;
		for (int i = 0; i < s2.size(); ++i)
		{
			if (*s1_begin > *s2_begin)
			{
				return false;
			}
			++s1_begin;
			++s2_begin;
		}// 循环完只能说明s2并不小于s1,s2有可能等于s1
		// 再次循环测试s2是否==s1
		for (int i = 0; i < s2.size(); ++i)
		{
			--s1_begin;
			--s2_begin;
			if (*s1_begin != *s2_begin)
			{
				same_flag = false;
			}
		}
		if (same_flag)
		{
			return false;
		}
		return true;
	}
	else
	{
		if (s2.size() == s1.size())
		{
			if (s1 == s2)
			{
				return false;
			}
		}

		for (int i = 0; i < s1.size(); ++i)
		{
			if (*s1_begin > *s2_begin)
			{
				return false;
			}
			++s1_begin;
			++s2_begin;
		}
		return true;
	}
	
}

bool operator<=(String& s1, String& s2)
{
	if (s1 == s2)
	{
		return true;
	}
	if (s1 < s2)
	{
		return true;
	}
	return false;
}
bool operator>(String& s1, String& s2)
{
	return s2 < s1;
}
bool operator>=(String& s1, String& s2)
{
	if (s1 == s2)
	{
		return true;
	}
	if (s1 > s2)
	{
		return true;
	}
	return false;
}


void String::test()
{
	chk_n_alloc();
}


int main()
{

	String s1("aaadaaaaaaaaa");
	String s2("aaadaaaaaaaaaa");
	cout << (s1 >= s2) << endl;
	string s3("aaadaaaaaaaaa");
	string s4("aaadaaaaaaaaaa");
	cout << (s3 >= s4) << endl;
	
	system("pause");
	return 0;
}

练习14.19:

14.4节练习

alt

练习14.20:

#include<iostream>
#include<map>
#include<vector>
#include<algorithm>
#include<utility>
using namespace std;


class Sales_Date {
public:
	friend Sales_Date& operator+(Sales_Date& s1, Sales_Date& s2);
	friend ostream& operator<<(ostream& out, Sales_Date& s);
	friend istream& operator>>(istream& in, Sales_Date& s);
	friend bool operator==(const Sales_Date& s1, const Sales_Date& s2);
	friend bool operator!=(const Sales_Date& s1, const Sales_Date& s2);
	Sales_Date() = default;
	Sales_Date(const string& no, unsigned sold, double reve) : bookNo(no), units_sold(sold),
		revenue(reve) {};

	Sales_Date& operator+=(Sales_Date& s)
	{
		revenue += s.revenue;
		units_sold += s.units_sold;
		return *this;
	}

	Sales_Date& operator+=(Sales_Date& s);

	istream& operator<<(istream& in)
	{
		cout << "输入revenue:" << endl;
		in >> revenue;
		cout << "输入units_sold:" << endl;
		in >> units_sold;
		return in;
	}

private:
	string bookNo;
	unsigned units_sold = 0.0;
	int revenue = 0;

};

Sales_Date& operator+(Sales_Date& s1, Sales_Date& s2)
{
	Sales_Date s;
	s.revenue = s1.revenue + s2.revenue;
	s.units_sold = s1.units_sold + s2.units_sold;
	return s;
}


ostream& operator<<(ostream& out, Sales_Date& s)
{
	out << "revenue: " << s.revenue << endl;
	out << "units_sold: " << s.units_sold << endl;
	return out;
}

istream& operator>>(istream& in, Sales_Date& s)
{
	int s1;
	in >> s1;
	if (!in)
	{
		cout << 12 << endl;
	}
	cout << "输入revenue:" << endl;
	in >> s.revenue;
	cout << "输入units_sold:" << endl;
	in >> s.units_sold;
	return in;
}

bool operator==(const Sales_Date& s1, const Sales_Date& s2)
{
	return s1.bookNo == s2.bookNo && s1.revenue == s2.revenue && 
		s1.units_sold == s1.units_sold;
}

bool operator!=(const Sales_Date& s1, const Sales_Date& s2)
{
	return !(s1 == s2);
}


void test()
{

	//Sales_Date s1("qwer", 10, 20);
	//Sales_Date s2("qwer", 20, 30);
	//Sales_Date s3 = s1 + s2;
	//cout << s3 << endl;
	//s3 += s1;
	//cout << s3 << endl;
	//cin >> s3;
	//cout << s3 << endl;
}

int main()
{


	system("pause");
	return 0;
}

练习14.21:

Sales_Date& operator+(Sales_Date& s1, Sales_Date& s2)
{
	Sales_Date s;
	s.revenue = s1.revenue + s2.revenue;
	s.units_sold = s1.units_sold + s2.units_sold;
	return s;
}

Sales_Date& Sales_Date::operator+=(Sales_Date& s)
{
	*this = *this + s;
	return *this;
}

练习14.22:

	Sales_Date& operator=(const string bn)
	{
		bookNo = bn;
		return *this;
	}

练习14.23:

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

练习14.24~14.25:

14.5节练习

练习14.26:

	char& operator[](int i)
	{
		if (i < size())
		{
			return elements[i];
		}
	}

	const char& operator[](int i) const
	{
		if (i < size())
		{
			return elements[i];
		}
	}

14.6节练习

alt

练习14.27:

	StrBlobPtr& operator++()
	{
		check(curr, "increment past end of StrBlobPtr");
		++curr;
		return *this;
	}
	StrBlobPtr& operator--()
	{
		check(curr, "increment past end of StrBlobPtr");
		--curr;
		return *this;
	}
	StrBlobPtr operator++(int)
	{
		auto ret = *this;
		++* this;
		return ret;
	}
	StrBlobPtr operator--(int)
	{
		auto ret = *this;
		--* this;
		return ret;
	}

练习14.28:

	StrBlobPtr operator+(int num)
	{
		auto ret = *this;
		this->curr += num;
		return ret;
	 }

	StrBlobPtr operator-(int num)
	{
		auto ret = *this;
		this->curr -= num;
		return ret;
	}

练习14.29:

需要修改对象本身的属性所以不用const

14.7节练习

alt

练习14.30:

	string& operator*() const
	{
		auto p = check(curr, "dereference......");
		return (*p)[curr];
	}

	string* operator->() const
	{
		
		return &operator*();
	}

练习14.31:

StrBolbPtr的成员分别是智能指针和内置数据类型,所以使用合成的析构函数、赋值运算符、构造函数即可

练习14.32:

class StrBlobPtrPtr
{
public:
	StrBlobPtrPtr(StrBlobPtr& s) : ptr(&s) {};

	StrBlobPtr* operator->()
	{
		return &(*ptr);
	}
private:
	StrBlobPtr* ptr;
};

14.8节练习

alt

练习14.33:

至少一个(隐式接受一个this指针)

练习14.34:

class Test
{
public:
	int operator()(int a, int b, int c)
	{
		if (a == 0)
		{
			return b;
		}
		else
		{
			return c;
		}
	}
};

int main()
{
	Test t;
	cout << t(1, 2, 3) << endl;;
	system("pause");
	return 0;
}

练习14.35:


class PrintString
{
public:
	const string operator()(istream& in)
	{
		string s;
		in >> s;
		if (in)
		{
			return s;
		}
		return "";
	}
};

int main()
{
	PrintString t;
	cout << t(cin) << endl;;
	system("pause");
	return 0;
}

练习14.36:


class PrintString
{
public:
	void operator()(istream& in)
	{
		string s;
		vector<string> vec;

		while (in >> s)
		{
			vec.push_back(s);
		}

		for (auto temp : vec)
		{
			cout << temp << endl;
		}
	}
};

int main()
{
	PrintString t;
	t(cin);

	system("pause");
	return 0;
}

练习14.37:

class isSame
{
public:
	bool operator()(int a)
	{
		return a == 2;
	}
};

int main()
{
	vector<int> vec = { 2, 2, 2, 3, 3, 3, 2, 2 };
	replace_if(vec.begin(), vec.end(), isSame(), 20);
	for (auto temp : vec)
	{
		cout << temp << endl;
	}

	system("pause");
	return 0;
}

14.8.1节练习

alt

练习14.38:

class StringLength
{
public:
	StringLength(int sz) : limit(sz) {};
	bool operator()(string s)
	{
		return s.size() == limit;
	}

private:
	int limit;
};

int main()
{
	vector<string> vec = { "aaaa", "aaaa", "asadaaa", "aaaa", "a", "aa" };
	for (int i = 1; i < 11; ++i)
	{
		cout << "长度=" << i << "有:" <<
			count_if(vec.begin(), vec.end(), StringLength(i)) << endl;
	}

	system("pause");
	return 0;
}

练习14.39:

class StringLength
{
public:
	StringLength(int sz1, int sz2=100) : limit1(sz1), limit2(sz2) {};
	bool operator()(string s)
	{
		return (s.size() > limit1) && (s.size() < limit2);
	}

private:
	int limit1;
	int limit2;
};

int main()
{
	vector<string> vec = { "aaaa", "aaaa", "asadaaa", "aaaa", "aa", "aa" };
	cout << "长度1~9有:" <<
		count_if(vec.begin(), vec.end(), StringLength(1, 9)) << endl;

	cout << "长度大于10有:" <<
		count_if(vec.begin(), vec.end(), StringLength(10)) << endl;

	system("pause");
	return 0;
}

练习14.40:

class Stable_sort
{
public:
	bool operator()(const string& a, const string& b)
	{
		return a.size() < b.size();
	}
};

void biggies(vector<string>& words, vector<string>::size_type sz)
{
	//elimDups(words);
	stable_sort(words.begin(), words.end(), Stable_sort());
	//......基本如Stable_sort一致
}

练习14.41:

通过lambda函数来提供更简单、方便的匿名函数的使用。
对于简单的、一次性的的逻辑函数使用lambda函数。对于需要将函数作为参数传递的也可以使用lambda,对于需要捕获上下文中变量进行功能编写的函数也可以使用lambda免去定义变量的繁琐。
对于复杂需要重复使用的函数对象可以使用类来实现,通过增加类的成员来完成复杂的功能

14.8.2节练习

alt

练习14.42:

(a)

	vector<int> vec = { 100, 10000, 1000 };
	cout << count_if(vec.begin(), vec.end(), bind(greater<int>(), placeholders::_1, 1024));

(b)

	vector<string> vec = { "pooh", "pooh1", "1000" };
	auto ret = find_if(vec.begin(), vec.end(), bind(not_equal_to<string>(), placeholders::_1, "pooh"));
	cout << *ret << endl;

(c)

	vector<int> vec = { 100, 200, 300 };
	auto ret = transform(vec.begin(), vec.end(), vec.begin(),
		bind(multiplies<int>(), placeholders::_1, 2));
	for (auto temp : vec)
	{
		cout << temp << endl;
	}

练习14.43:

使用标准库函数允许的代码结果不正确

	vector<int> vec = { 100, 200, 300 };
	bool ret = all_of(vec.begin(), vec.end(), bind(modulus<int>(), placeholders::_1, 300)) == 0;
	cout << ret << endl;

使用lambda正确

	vector<int> vec = { 100, 200, 300 };
	bool ret = all_of(vec.begin(), vec.end(), [](int num) { return num % 300 == 0; });
	cout << ret << endl;

练习14.8.3

alt

练习14.44:

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

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


int main()
{
	map<string, function<int(int, int)>> binops;
	binops.insert({ "+", add });
	binops.insert({ "-", minus<int>()});
	binops.insert({ "*", Multiplies() });
	binops.insert({ "/", [](int a, int b) {return a / b; } });

	cout << binops["+"](1, 2) << endl;
	cout << binops["-"](1, 2) << endl;
	cout << binops["*"](1, 2) << endl;
	cout << binops["/"](1, 2) << endl;

	system("pause");
	return 0;
}

14.9.1节练习

alt

练习14.45:

返回对应类型的值(string、doule)

练习14.46:

不应该,我们并不需要将string或者其他类型的数据转化成Sales_data

练习14.47:

operator const int()限制返回值不能被修改
operator int() const 函数体的定义内不能对转化对象进行修改

练习14.48:

不需要

练习14.49:

class Book
{
public:
	Book(int tn) : thinkness(tn) {};
	operator bool()
	{
		if (thinkness)
		{
			return thinkness;
		}
		else
		{
			return 0;
		}
	}
private:
	int thinkness;
};


int main()
{
	Book b(10);
	if (b)
	{
		cout << b << endl;
	}

	system("pause");
	return 0;
}

14.9.2节练习

alt

练习14.50:

int ex1初始化失败,operator double()返回double,operator float()返回float,这两者都可以转化成int,产生二义性。 int ex2使用operator float()返回float为ex2赋值

练习14.51:

调用calc(int),LongDouble是自定义数据类型,int是内置类型,优先将double类型的数据转化成int而不是转化成自定义数据类型LongDouble

14.9.3节练习

alt

练习14.52:

ld = si + ld;SmallInt和LongDouble两者没有相互转化的类型转化函数和符合参数的重载运算符,所以只能将is和ld转化成内置数据类型使用内置数据类型相加,si转化成int与ld相加,ld转化成int时产生二义性(operator double()返回double,operator float()返回float,这两者都可以转化成int),
ld = ld + si;符合LongDouble的重载的成员运算符+

练习14.53:

不合法,double d = s1 + 3.14;符合两个函数的参数要求会产生二义性,将s1显示的转化成内置数据类型即可使用static_cast(s1)

C++Prime学习笔记 文章被收录于专栏

勇敢和愚蠢只有一剑之差

全部评论

相关推荐

牛客410815733号:这是什么电影查看图片
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务