第 14 章 操作符重载与类型转换

练习 14.1:

区别:

  • 如果一个运算符函数是成员函数,则它的第一个运算对象绑定到隐式的this指针上,因此,成员运算符函数的参数数量比运算符的运算对象总数少一个。
  • 重载运算符函数,或者是类的成员,或者至少含有一个类类型的参数。
  • 重载运算符不保证运算对象的求值顺序,例如对&&和||的重载版本不再具有“短路求值”的特性,两个操作数都要求值,而且不规定操作数的求值顺序。

相同点:

重载运算符与对应的内置操作符具有相同的优先级和结合律。

练习 14.2:

#ifndef EX14_2_H
#define EX14_2_H

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

class Sales_data
{
    friend istream& operator>>(istream&, Sales_data&);
    friend ostream& operator<<(ostream&, Sales_data&);
    friend Sales_data operator+(const Sales_data&, const Sales_data&);
public:
    Sales_data() = default;
    Sales_data(const string& s) : bookNo(s) {}
    Sales_data(const string& s, unsigned n, double p)
        : bookNo(s), units_sold(n), revenue(n* p) {}
    Sales_data(istream& is);
    Sales_data& operator+=(const Sales_data&);

    string isbn()const { return bookNo; }

private:
    double avg_price() const { return units_sold ? revenue / units_sold : 0; }

    string bookNo;
    unsigned units_sold = 0;
    double revenue = 0.0;
};

istream& operator>>(istream&, Sales_data&);
ostream& operator<<(ostream&, Sales_data&);
Sales_data operator+(const Sales_data&, const Sales_data&);

#endif
#include"ex14_2.h"

Sales_data::Sales_data(istream& is)
{
	is >> *this;
}

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

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

ostream& operator<<(ostream& os, Sales_data& data)
{
	os << data.bookNo << " " << data.units_sold << " " << data.revenue << " " 
		<< data.avg_price();
	return os;
}

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

练习 14.3:

"cobble" == "stone";       // 内置版本,字符串字面值的类型是const char[]
svec1[0] == svec2[0];      // string          
svec1 == svec2;            // vector
svec1[0] == "stone";       // string

练习 14.4:

(a) %        对称运算符。非成员

(b) %=      改变对象的状态。成员

(c) ++       改变对象的状态。成员

(d) ->        成员访问箭头。成员

(e) <<       非成员。

(f) &&       对称运算符。非成员

(g) ==      对称运算符。非成员

(h) ()        调用。成员

练习 14.5:

#ifndef EX14_5_H
#define EX14_5_H

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

class Book
{
	friend istream& operator>>(istream&, Book&);
	friend ostream& operator<<(ostream&, const Book&);
	friend bool operator==(const Book&, const Book&);
	friend bool operator!=(const Book&, const Book&);
public:
	Book() = default;
	Book(string bookNo, string name, string author) :
		m_bookNO(bookNo), m_name(name), m_author(author) {}
	Book(istream& is) { is >> *this; }

private:
	string m_bookNO;
	string m_name;
	string m_author;
};

istream& operator>>(istream&, Book&);
ostream& operator<<(ostream&, const Book&);
bool operator==(const Book&, const Book&);
bool operator!=(const Book&, const Book&);

#endif
#include"ex14_5.h"

istream& operator>>(istream& is, Book& book)
{
	is >> book.m_bookNO >> book.m_name >> book.m_author;
	if (!is)
		book = Book();
	return is;
}

ostream& operator<<(ostream& os, const Book& book)
{
	os << book.m_bookNO << " " << book.m_name << " " << book.m_author;
	return os;
}

bool operator==(const Book& lhs, const Book& rhs)
{
	return lhs.m_bookNO == rhs.m_bookNO &&
		lhs.m_name == rhs.m_name &&
		lhs.m_author == rhs.m_author;
}

bool operator!=(const Book& lhs, const Book& rhs)
{
	return !(lhs == rhs);
}

练习 14.6:

// 练习 14.2:
ostream& operator<<(ostream& os, Sales_data& data)
{
	os << data.bookNo << " " << data.units_sold << " " << data.revenue << " " 
		<< data.avg_price();
	return os;
}

练习 14.7:

#ifndef EX14_7_H
#define EX14_7_H

#include<iostream>
#include<memory>
#include<algorithm>
using namespace std;

class String
{
	friend ostream& operator<<(ostream&, const String&);
public:
	String() : elements(nullptr), end(nullptr) {}
	String(const char*);
	String(const String&);
	String& operator=(const String&);
	String(String&&)noexcept;
	String& operator=(String&&)noexcept;
	~String();

	size_t size()const { return end - elements; }

private:
	pair<char*, char*> alloc_n_copy(const char*, const char*);
	void range_initializer(const char*, const char*);
	void free();

	allocator<char> alloc;
	char* elements;
	char* end;
};

ostream& operator<<(ostream&, const String&);

#endif
#include"ex14_7.h"

pair<char*, char*> String::alloc_n_copy(const char* b, const char* e)
{
	auto str = alloc.allocate(e - b);
	return { str, std::uninitialized_copy(b, e, str) };
}

void String::free()
{
	if (elements)
	{
		for_each(elements, end, [this](char& c) { alloc.destroy(&c); });
		alloc.deallocate(elements, end - elements);
	}
}

void String::range_initializer(const char* b, const char* e)
{
	auto newStr = alloc_n_copy(b, e);
	elements = newStr.first;
	end = newStr.second;
}

String::String(const char* s)
{
	char* s1 = const_cast<char*>(s);
	while (*s1)
		++s1;
	range_initializer(s, s1);
}

String::String(const String& rhs)
{
	range_initializer(rhs.elements, rhs.end);
	cout << "Copy construction" << endl;
}

String& String::operator=(const String& rhs)
{
	auto newStr = alloc_n_copy(rhs.elements, rhs.end);
	free();
	elements = newStr.first;
	end = newStr.second;
	cout << "Copy assignment" << endl;
	return *this;
}

String::String(String&& rhs)noexcept : elements(rhs.elements), end(rhs.end)
{
	rhs.elements = rhs.end = nullptr;
}

String& String::operator=(String&& rhs)noexcept
{
	if (this != &rhs)
	{
		free();
		elements = rhs.elements;
		end = rhs.end;
		rhs.elements = rhs.end = nullptr;
	}
	return *this;
}

String::~String() { free(); }

ostream& operator<<(ostream& os, const String& s)
{
	for (auto beg = s.elements; beg != s.end; ++beg)
		os << *beg;
	return os;
}

练习 14.8:

// 练习 14.5:
istream& operator>>(istream& is, Book& book)
{
	is >> book.m_bookNO >> book.m_name >> book.m_author;
	if (!is)
		book = Book();
	return is;
}

练习 14.9:

// 练习 14.2:
istream& operator>>(istream& is, Sales_data& data)
{
	double price = 0.0;
	is >> data.bookNo >> data.units_sold >> price;
	if (is)
		data.revenue = data.units_sold * price;
	else
		data = Sales_data();
	return is;
}

练习 14.10:

#include"ex14_2.h"

int main()
{
	Sales_data data;
	cin >> data;
	cout << data << endl;
	// 0-201-99999-9 10 24.95		正确输出
	// 10 24.95 0-201-99999-9		输出 10 24 22.8 0.95

	return 0;
}

练习 14.11:

没有输入检查。与上题结果一样。

练习 14.12:

// 练习 14.5:
istream& operator>>(istream& is, Book& book)
{
	is >> book.m_bookNO >> book.m_name >> book.m_author;
	if (!is)
		book = Book();
	return is;
}

练习 14.13:

Sales_data类没有其他的算术运算符需要重载了。

练习 14.14:

        operator+有两个const的参数,返回类型为Sales_data类型的一个拷贝。operator+=有一个const的参数返回类型为Sales_data类型的引用。每次不需要在函数内创建临时变量,直接可返回*this。所以调用operator+=来定义operator+会减少临时量的创建而比其他方法更有效。

练习 14.15:

不需要其他的算术运算符需要重载了,因为它的数据成员都是string类型的。

练习 14.16:

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

class StrBlobPtr;
class ConstStrBlobPtr;
// StrBlob类
class StrBlob
{
	typedef vector<string>::size_type size_type;
	friend class StrBlobPtr;
	friend class ConstStrBlobPtr;
	friend bool operator==(const StrBlob&, const StrBlob&);
	friend bool operator!=(const StrBlob&, const StrBlob&);
public:
	StrBlob() : data(make_shared<vector<string>>()) { }
	StrBlob(initializer_list<string> il) :
		data(make_shared<vector<string>>(il)) { }
	StrBlob(const StrBlob& sb) : data(make_shared<vector<string>>(*sb.data)) {}
	StrBlob& operator=(const StrBlob& sb)
	{
		this->data = make_shared<vector<string>>(*sb.data);
		return *this;
	}
	StrBlob(StrBlob&& rhs)noexcept : data(move(rhs.data)) {}
	StrBlob& operator=(StrBlob&& rhs) noexcept
	{
		if (this != &rhs) 
		{
			data = move(rhs.data);
			rhs.data = nullptr;
		}
		return *this;
	}

	StrBlobPtr begin();
	StrBlobPtr end();

	ConstStrBlobPtr cbegin()const;
	ConstStrBlobPtr cend()const;

	size_type size()const { return data->size(); }
	bool empty()const { return data->empty(); }
	void push_back(const string& t) { data->push_back(t); }
	void pop_back()
	{
		check(0, "pop_back on empty StrBlob");
		data->pop_back();
	}
	string& front()
	{
		check(0, "front on empty StrBlob");
		return data->front();
	}
	const string& front()const
	{
		check(0, "front on empty StrBlob");
		return data->front();
	}
	string& back()
	{
		check(0, "back on empty StrBlob");
		return data->back();
	}
	const string& back()const
	{
		check(0, "back on empty StrBlob");
		return data->back();
	}

private:
	shared_ptr<vector<string>> data;
	void check(size_type i, const string& msg)const
	{
		if (i >= data->size())
			throw out_of_range(msg);
	}
};

// StrBlobPtr类
class StrBlobPtr
{
	friend bool operator==(const StrBlobPtr&, const StrBlobPtr&);
	friend bool operator!=(const StrBlobPtr&, const StrBlobPtr&);
public:
	StrBlobPtr() : curr(0) {}
	StrBlobPtr(StrBlob& s, size_t sz = 0) : wptr(s.data), curr(sz) {}
	
    string& deref() const;
    StrBlobPtr& incr();
private:
	// 若检查成功,check返回一个指向vector的shared_ptr
	shared_ptr<vector<string>> check(size_t, const string&)const;
	weak_ptr<vector<string>> wptr;
	size_t curr;    // 在数组中的当前位置
};

shared_ptr<vector<string>> StrBlobPtr::check(size_t i, const string& msg)const
{
	auto ret = wptr.lock();	// vector是否还存在
	if (!ret)
		throw runtime_error("unbound StrBlobPtr");
	if (i >= ret->size())	// 索引值是否合法
		throw out_of_range(msg);
	return ret;		// 否则返回这项vector的shared_ptr
}

string& StrBlobPtr::deref()const
{
	auto p = check(curr, "dereference past end");
	return (*p)[curr];
}

StrBlobPtr& StrBlobPtr::incr()
{
	check(curr, "increment past end of ConstStrBlobPtr");
	++curr;
	return *this;
}

// ConstStrBlobPtr类
class ConstStrBlobPtr
{
	friend bool operator==(const ConstStrBlobPtr&, const ConstStrBlobPtr&);
	friend bool operator!=(const ConstStrBlobPtr&, const ConstStrBlobPtr&);
public:
	ConstStrBlobPtr() : curr(0) {}
	ConstStrBlobPtr(const StrBlob& a, size_t sz = 0) : wptr(a.data), curr(sz) {}

	const string& deref() const;
    ConstStrBlobPtr& incr();
private:
	shared_ptr<vector<string>> check(size_t i, const string& msg)const;
	weak_ptr<vector<string>> wptr;
	size_t curr;
};

shared_ptr<vector<string>> ConstStrBlobPtr::check(size_t i, const string& msg)const
{
	auto ret = wptr.lock();
	if (!ret)
		throw runtime_error("unbound ConstStrBlobPtr");
	if (i >= ret->size())
		throw out_of_range(msg);
	return ret;
}

const string& ConstStrBlobPtr::deref()const
{
	auto p = check(curr, "dereference past end");
	return (*p)[curr];
}

ConstStrBlobPtr& ConstStrBlobPtr::incr()
{
	check(curr, "increment past end of ConstStrBlobPtr");
	++curr;
	return *this;
}

// StrBlob运算符
bool operator==(const StrBlob& lhs, const StrBlob& rhs)
{
	return *lhs.data == *rhs.data;
}

bool operator!=(const StrBlob& lhs, const StrBlob& rhs)
{
	return !(lhs == rhs);
}

// StrBlobPtr运算符
bool operator==(const StrBlobPtr& lhs, const StrBlobPtr& rhs)
{
	return lhs.curr == rhs.curr;
}

bool operator!=(const StrBlobPtr& lhs, const StrBlobPtr& rhs)
{
	return !(lhs == rhs);
}

// ConstStrBlobPtr运算符
bool operator==(const ConstStrBlobPtr& lhs, const ConstStrBlobPtr& rhs)
{
	return lhs.curr == rhs.curr;
}

bool operator!=(const ConstStrBlobPtr& lhs, const ConstStrBlobPtr& rhs)
{
	return !(lhs == rhs);
}

// 成员函数
StrBlobPtr StrBlob::begin() 
{ 
	return StrBlobPtr(*this); 
}

StrBlobPtr StrBlob::end() 
{ 
	return StrBlobPtr(*this, data->size()); 
}

ConstStrBlobPtr StrBlob::cbegin()const 
{ 
	return ConstStrBlobPtr(*this); 
}

ConstStrBlobPtr StrBlob::cend()const 
{ 
	return ConstStrBlobPtr(*this, data->size()); 
}
#include<string>
#include<memory>
#include<initializer_list>
#include<algorithm>
using namespace std;

class StrVec
{
	friend bool operator==(const StrVec&, const StrVec&);
	friend bool operator!=(const StrVec&, const StrVec&);
public:
	StrVec() : elements(nullptr), first_free(nullptr), cap(nullptr) {}
	StrVec(const StrVec&);
	StrVec(initializer_list<string>);
	StrVec& operator=(const StrVec&);
	StrVec(StrVec&&)noexcept;
	StrVec& operator=(StrVec&&)noexcept;
	~StrVec();
	void push_back(const string&);
	size_t size()const { return first_free - elements; }
	size_t capacity()const { return cap - elements; }
	string* begin()const { return elements; }
	string* end()const { return first_free; }

	string& at(size_t pos) const { return *(elements + pos); }

	void reserve(size_t newcapacity);
	void resize(size_t count);
	void resize(size_t count, const string&);

private:
	allocator<string> alloc;
	void chk_n_alloc()
	{
		if (size() == capacity())
			reallocate();
	}
	void reallocate();
	void alloc_n_move(size_t);
	void range_initialize(const string*, const string*);

	pair<string*, string*> alloc_n_copy(const string* beg, const string* end);
	void free();

	string* elements;
	string* first_free;
	string* cap;
};


pair<string*, string*> StrVec::alloc_n_copy(const string* beg, const string* end)
{
	auto pbeg = alloc.allocate(end - beg);
	auto pend = uninitialized_copy(beg, end, pbeg);
	return pair<string*, string*>(pbeg, pend);
}

void StrVec::free()
{
	if (elements)
	{
		for_each(elements, first_free, [this](string& s) {alloc.destroy(&s); });
		alloc.deallocate(elements, cap - elements);
	}
}

void StrVec::range_initialize(const string* beg, const string* end)
{
	auto newdata = alloc_n_copy(beg, end);
	elements = newdata.first;
	first_free = cap = newdata.second;
}

StrVec::StrVec(initializer_list<string> il)
{
	range_initialize(il.begin(), il.end());
}

StrVec::StrVec(const StrVec& rhs)
{
	range_initialize(rhs.begin(), rhs.end());
}

StrVec& StrVec::operator=(const StrVec& rhs)
{
	auto newdata = alloc_n_copy(rhs.begin(), rhs.end());
	free();
	elements = newdata.first;
	first_free = cap = newdata.second;
	return *this;
}

StrVec::~StrVec()
{
	free();
}

void StrVec::push_back(const string& s)
{
	chk_n_alloc();
	alloc.construct(first_free++, s);
}

void StrVec::alloc_n_move(size_t newcapacity)
{
	auto newdata = alloc.allocate(newcapacity);
	auto dest = newdata;
	for (auto beg = elements; beg != first_free; ++beg)
		alloc.construct(dest++, std::move(*beg));
	free();	
	elements = newdata;
	first_free = dest;
	cap = elements + newcapacity;
}

void StrVec::reallocate()
{
	auto newcapacity = size() ? 2 * size() : 1;
	alloc_n_move(newcapacity);
}

void StrVec::reserve(size_t newcapacity)
{
	if (newcapacity <= capacity())
		return;
	alloc_n_move(newcapacity);

}

void StrVec::resize(size_t count)
{
	resize(count, string());
}

void StrVec::resize(size_t count, const string& s)
{
	if (count > size())
	{
		if (count > capacity())
			reserve(2 * count);
		while (first_free != elements + count)
			alloc.construct(first_free++, s);
	}
	else if (count < size())
	{
		while (first_free != elements + count)
			alloc.destroy(--first_free);
	}
}

StrVec::StrVec(StrVec&& rhs)noexcept
	:elements(rhs.elements), first_free(rhs.first_free), cap(rhs.cap)
{
	rhs.elements = rhs.first_free = rhs.cap = nullptr;
}

StrVec& StrVec::operator=(StrVec&& rhs)noexcept
{
	if (this != &rhs)
	{
		free();
		elements = rhs.elements;
		first_free = rhs.first_free;
		cap = rhs.cap;
		rhs.elements = rhs.first_free = rhs.cap = nullptr;
	}
	return *this;
}

bool operator==(const StrVec& lhs, const StrVec& rhs)
{
	return lhs.size() == rhs.size() &&
		equal(lhs.begin(), lhs.end(), rhs.begin());
}

bool operator!=(const StrVec& lhs, const StrVec& rhs)
{
	return !(lhs == rhs);
}
#include<iostream>
#include<memory>
#include<algorithm>
using namespace std;

class String
{
	friend ostream& operator<<(ostream&, const String&);
	friend bool operator==(const String&, const String&);
	friend bool operator!=(const String&, const String&);

public:
	String() : elements(nullptr), last_elem(nullptr) {}
	String(const char*);
	String(const String&);
	String& operator=(const String&);
	String(String&&)noexcept;
	String& operator=(String&&)noexcept;
	~String();

	size_t size()const { return last_elem - elements; }
	char* begin()const { return elements; }
	char* end()const {return last_elem;}

private:
	pair<char*, char*> alloc_n_copy(const char*, const char*);
	void range_initializer(const char*, const char*);
	void free();

	allocator<char> alloc;
	char* elements;
	char* last_elem;
};

pair<char*, char*> String::alloc_n_copy(const char* b, const char* e)
{
	auto str = alloc.allocate(e - b);
	return { str, std::uninitialized_copy(b, e, str) };
}

void String::free()
{
	if (elements)
	{
		for_each(elements, last_elem, [this](char& c) { alloc.destroy(&c); });
		alloc.deallocate(elements, last_elem - elements);
	}
}

void String::range_initializer(const char* b, const char* e)
{
	auto newStr = alloc_n_copy(b, e);
	elements = newStr.first;
	last_elem = newStr.second;
}

String::String(const char* s)
{
	char* s1 = const_cast<char*>(s);
	while (*s1)
		++s1;
	range_initializer(s, s1);
}

String::String(const String& rhs)
{
	range_initializer(rhs.elements, rhs.last_elem);
	cout << "Copy construction" << endl;
}

String& String::operator=(const String& rhs)
{
	auto newStr = alloc_n_copy(rhs.elements, rhs.last_elem);
	free();
	elements = newStr.first;
	last_elem = newStr.second;
	cout << "Copy assignment" << endl;
	return *this;
}

String::String(String&& rhs)noexcept : elements(rhs.elements), last_elem(rhs.last_elem)
{
	rhs.elements = rhs.last_elem = nullptr;
}

String& String::operator=(String&& rhs)noexcept
{
	if (this != &rhs)
	{
		free();
		elements = rhs.elements;
		last_elem = rhs.last_elem;
		rhs.elements = rhs.last_elem = nullptr;
	}
	return *this;
}

String::~String() { free(); }

ostream& operator<<(ostream& os, const String& s)
{
	for (auto beg = s.elements; beg != s.last_elem; ++beg)
		os << *beg;
	return os;
}

bool operator==(const String& lhs, const String& rhs)
{
	return lhs.size() == rhs.size() && equal(lhs.begin(), lhs.end(), rhs.begin());
}
bool operator!=(const String& lhs, const String& rhs)
{
	return !(lhs == rhs);
}

练习 14.17:

// 练习 14.5:
bool operator==(const Book& lhs, const Book& rhs)
{
	return lhs.m_bookNO == rhs.m_bookNO &&
		lhs.m_name == rhs.m_name &&
		lhs.m_author == rhs.m_author;
}

bool operator!=(const Book& lhs, const Book& rhs)
{
	return !(lhs == rhs);
}

练习 14.18:

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

class StrBlobPtr;
class ConstStrBlobPtr;
// StrBlob类
class StrBlob
{
	typedef vector<string>::size_type size_type;
	friend class StrBlobPtr;
	friend class ConstStrBlobPtr;
	friend bool operator==(const StrBlob&, const StrBlob&);
	friend bool operator!=(const StrBlob&, const StrBlob&);
	friend bool operator<(const StrBlob&, const StrBlob&);
	friend bool operator>(const StrBlob&, const StrBlob&);
	friend bool operator<=(const StrBlob&, const StrBlob&);
	friend bool operator>=(const StrBlob&, const StrBlob&);
public:
	StrBlob() : data(make_shared<vector<string>>()) { }
	StrBlob(initializer_list<string> il) :
		data(make_shared<vector<string>>(il)) { }
	StrBlob(const StrBlob& sb) : data(make_shared<vector<string>>(*sb.data)) {}
	StrBlob& operator=(const StrBlob& sb)
	{
		this->data = make_shared<vector<string>>(*sb.data);
		return *this;
	}
	StrBlob(StrBlob&& rhs)noexcept : data(move(rhs.data)) {}
	StrBlob& operator=(StrBlob&& rhs) noexcept
	{
		if (this != &rhs)
		{
			data = move(rhs.data);
			rhs.data = nullptr;
		}
		return *this;
	}

	StrBlobPtr begin();
	StrBlobPtr end();

	ConstStrBlobPtr cbegin()const;
	ConstStrBlobPtr cend()const;

	size_type size()const { return data->size(); }
	bool empty()const { return data->empty(); }
	void push_back(const string& t) { data->push_back(t); }
	void pop_back()
	{
		check(0, "pop_back on empty StrBlob");
		data->pop_back();
	}
	string& front()
	{
		check(0, "front on empty StrBlob");
		return data->front();
	}
	const string& front()const
	{
		check(0, "front on empty StrBlob");
		return data->front();
	}
	string& back()
	{
		check(0, "back on empty StrBlob");
		return data->back();
	}
	const string& back()const
	{
		check(0, "back on empty StrBlob");
		return data->back();
	}

private:
	shared_ptr<vector<string>> data;
	void check(size_type i, const string& msg)const
	{
		if (i >= data->size())
			throw out_of_range(msg);
	}
};

// StrBlobPtr类
class StrBlobPtr
{
	friend bool operator==(const StrBlobPtr&, const StrBlobPtr&);
	friend bool operator!=(const StrBlobPtr&, const StrBlobPtr&);
	friend bool operator<(const StrBlobPtr&, const StrBlobPtr&);
	friend bool operator>(const StrBlobPtr&, const StrBlobPtr&);
	friend bool operator<=(const StrBlobPtr&, const StrBlobPtr&);
	friend bool operator>=(const StrBlobPtr&, const StrBlobPtr&);
public:
	StrBlobPtr() : curr(0) {}
	StrBlobPtr(StrBlob& s, size_t sz = 0) : wptr(s.data), curr(sz) {}

	string& deref() const;
	StrBlobPtr& incr();
private:
	// 若检查成功,check返回一个指向vector的shared_ptr
	shared_ptr<vector<string>> check(size_t, const string&)const;
	weak_ptr<vector<string>> wptr;
	size_t curr;    // 在数组中的当前位置
};

shared_ptr<vector<string>> StrBlobPtr::check(size_t i, const string& msg)const
{
	auto ret = wptr.lock();	// vector是否还存在
	if (!ret)
		throw runtime_error("unbound StrBlobPtr");
	if (i >= ret->size())	// 索引值是否合法
		throw out_of_range(msg);
	return ret;		// 否则返回这项vector的shared_ptr
}

string& StrBlobPtr::deref()const
{
	auto p = check(curr, "dereference past end");
	return (*p)[curr];
}

StrBlobPtr& StrBlobPtr::incr()
{
	check(curr, "increment past end of ConstStrBlobPtr");
	++curr;
	return *this;
}

// ConstStrBlobPtr类
class ConstStrBlobPtr
{
	friend bool operator==(const ConstStrBlobPtr&, const ConstStrBlobPtr&);
	friend bool operator!=(const ConstStrBlobPtr&, const ConstStrBlobPtr&);
	friend bool operator<(const ConstStrBlobPtr&, const ConstStrBlobPtr&);
	friend bool operator>(const ConstStrBlobPtr&, const ConstStrBlobPtr&);
	friend bool operator<=(const ConstStrBlobPtr&, const ConstStrBlobPtr&);
	friend bool operator>=(const ConstStrBlobPtr&, const ConstStrBlobPtr&);
public:
	ConstStrBlobPtr() : curr(0) {}
	ConstStrBlobPtr(const StrBlob& a, size_t sz = 0) : wptr(a.data), curr(sz) {}

	const string& deref() const;
	ConstStrBlobPtr& incr();
private:
	shared_ptr<vector<string>> check(size_t i, const string& msg)const;
	weak_ptr<vector<string>> wptr;
	size_t curr;
};

shared_ptr<vector<string>> ConstStrBlobPtr::check(size_t i, const string& msg)const
{
	auto ret = wptr.lock();
	if (!ret)
		throw runtime_error("unbound ConstStrBlobPtr");
	if (i >= ret->size())
		throw out_of_range(msg);
	return ret;
}

const string& ConstStrBlobPtr::deref()const
{
	auto p = check(curr, "dereference past end");
	return (*p)[curr];
}

ConstStrBlobPtr& ConstStrBlobPtr::incr()
{
	check(curr, "increment past end of ConstStrBlobPtr");
	++curr;
	return *this;
}

// StrBlob运算符
bool operator==(const StrBlob& lhs, const StrBlob& rhs)
{
	return *lhs.data == *rhs.data;
}

bool operator!=(const StrBlob& lhs, const StrBlob& rhs)
{
	return !(lhs == rhs);
}

bool operator<(const StrBlob& lhs, const StrBlob& rhs)
{
	return *lhs.data < *rhs.data;
}

bool operator>(const StrBlob& lhs, const StrBlob& rhs)
{
	return *lhs.data > *rhs.data;
}

bool operator<=(const StrBlob& lhs, const StrBlob& rhs)
{
	return *lhs.data <= *rhs.data;
}

bool operator>=(const StrBlob& lhs, const StrBlob& rhs)
{
	return *lhs.data >= *rhs.data;
}

// StrBlobPtr运算符
bool operator==(const StrBlobPtr& lhs, const StrBlobPtr& rhs)
{
	return lhs.curr == rhs.curr;
}

bool operator!=(const StrBlobPtr& lhs, const StrBlobPtr& rhs)
{
	return !(lhs == rhs);
}

bool operator<(const StrBlobPtr& lhs, const StrBlobPtr& rhs)
{
	return lhs.curr < rhs.curr;
}

bool operator>(const StrBlobPtr& lhs, const StrBlobPtr& rhs)
{
	return lhs.curr > rhs.curr;
}

bool operator<=(const StrBlobPtr& lhs, const StrBlobPtr& rhs)
{
	return lhs.curr <= rhs.curr;
}

bool operator>=(const StrBlobPtr& lhs, const StrBlobPtr& rhs)
{
	return lhs.curr >= rhs.curr;
}

// ConstStrBlobPtr运算符
bool operator==(const ConstStrBlobPtr& lhs, const ConstStrBlobPtr& rhs)
{
	return lhs.curr == rhs.curr;
}

bool operator!=(const ConstStrBlobPtr& lhs, const ConstStrBlobPtr& rhs)
{
	return !(lhs == rhs);
}

bool operator<(const ConstStrBlobPtr& lhs, const ConstStrBlobPtr& rhs)
{
	return lhs.curr < rhs.curr;
}

bool operator>(const ConstStrBlobPtr& lhs, const ConstStrBlobPtr& rhs)
{
	return lhs.curr > rhs.curr;
}

bool operator<=(const ConstStrBlobPtr& lhs, const ConstStrBlobPtr& rhs)
{
	return lhs.curr <= rhs.curr;
}

bool operator>=(const ConstStrBlobPtr& lhs, const ConstStrBlobPtr& rhs)
{
	return lhs.curr >= rhs.curr;
}

// 成员函数
StrBlobPtr StrBlob::begin()
{
	return StrBlobPtr(*this);
}

StrBlobPtr StrBlob::end()
{
	return StrBlobPtr(*this, data->size());
}

ConstStrBlobPtr StrBlob::cbegin()const
{
	return ConstStrBlobPtr(*this);
}

ConstStrBlobPtr StrBlob::cend()const
{
	return ConstStrBlobPtr(*this, data->size());
}
#include<string>
#include<memory>
#include<initializer_list>
#include<algorithm>
using namespace std;

class StrVec
{
	friend bool operator==(const StrVec&, const StrVec&);
	friend bool operator!=(const StrVec&, const StrVec&);
	friend bool operator<(const StrVec&, const StrVec&);
	friend bool operator>(const StrVec&, const StrVec&);
	friend bool operator<=(const StrVec&, const StrVec&);
	friend bool operator>=(const StrVec&, const StrVec&);
public:
	StrVec() : elements(nullptr), first_free(nullptr), cap(nullptr) {}
	StrVec(const StrVec&);
	StrVec(initializer_list<string>);
	StrVec& operator=(const StrVec&);
	StrVec(StrVec&&)noexcept;
	StrVec& operator=(StrVec&&)noexcept;
	~StrVec();
	void push_back(const string&);
	size_t size()const { return first_free - elements; }
	size_t capacity()const { return cap - elements; }
	string* begin()const { return elements; }
	string* end()const { return first_free; }

	string& at(size_t pos) const { return *(elements + pos); }

	void reserve(size_t newcapacity);
	void resize(size_t count);
	void resize(size_t count, const string&);

private:
	allocator<string> alloc;
	void chk_n_alloc()
	{
		if (size() == capacity())
			reallocate();
	}
	void reallocate();
	void alloc_n_move(size_t);
	void range_initialize(const string*, const string*);

	pair<string*, string*> alloc_n_copy(const string* beg, const string* end);
	void free();

	string* elements;
	string* first_free;
	string* cap;
};


pair<string*, string*> StrVec::alloc_n_copy(const string* beg, const string* end)
{
	auto pbeg = alloc.allocate(end - beg);
	auto pend = uninitialized_copy(beg, end, pbeg);
	return pair<string*, string*>(pbeg, pend);
}

void StrVec::free()
{
	if (elements)
	{
		for_each(elements, first_free, [this](string& s) {alloc.destroy(&s); });
		alloc.deallocate(elements, cap - elements);
	}
}

void StrVec::range_initialize(const string* beg, const string* end)
{
	auto newdata = alloc_n_copy(beg, end);
	elements = newdata.first;
	first_free = cap = newdata.second;
}

StrVec::StrVec(initializer_list<string> il)
{
	range_initialize(il.begin(), il.end());
}

StrVec::StrVec(const StrVec& rhs)
{
	range_initialize(rhs.begin(), rhs.end());
}

StrVec& StrVec::operator=(const StrVec& rhs)
{
	auto newdata = alloc_n_copy(rhs.begin(), rhs.end());
	free();
	elements = newdata.first;
	first_free = cap = newdata.second;
	return *this;
}

StrVec::~StrVec()
{
	free();
}

void StrVec::push_back(const string& s)
{
	chk_n_alloc();
	alloc.construct(first_free++, s);
}

void StrVec::alloc_n_move(size_t newcapacity)
{
	auto newdata = alloc.allocate(newcapacity);
	auto dest = newdata;
	for (auto beg = elements; beg != first_free; ++beg)
		alloc.construct(dest++, std::move(*beg));
	free();	
	elements = newdata;
	first_free = dest;
	cap = elements + newcapacity;
}

void StrVec::reallocate()
{
	auto newcapacity = size() ? 2 * size() : 1;
	alloc_n_move(newcapacity);
}

void StrVec::reserve(size_t newcapacity)
{
	if (newcapacity <= capacity())
		return;
	alloc_n_move(newcapacity);

}

void StrVec::resize(size_t count)
{
	resize(count, string());
}

void StrVec::resize(size_t count, const string& s)
{
	if (count > size())
	{
		if (count > capacity())
			reserve(2 * count);
		while (first_free != elements + count)
			alloc.construct(first_free++, s);
	}
	else if (count < size())
	{
		while (first_free != elements + count)
			alloc.destroy(--first_free);
	}
}

StrVec::StrVec(StrVec&& rhs)noexcept
	:elements(rhs.elements), first_free(rhs.first_free), cap(rhs.cap)
{
	rhs.elements = rhs.first_free = rhs.cap = nullptr;
}

StrVec& StrVec::operator=(StrVec&& rhs)noexcept
{
	if (this != &rhs)
	{
		free();
		elements = rhs.elements;
		first_free = rhs.first_free;
		cap = rhs.cap;
		rhs.elements = rhs.first_free = rhs.cap = nullptr;
	}
	return *this;
}

bool operator==(const StrVec& lhs, const StrVec& rhs)
{
	return lhs.size() == rhs.size() &&
		equal(lhs.begin(), lhs.end(), rhs.begin());
}

bool operator!=(const StrVec& lhs, const StrVec& rhs)
{
	return !(lhs == rhs);
}

bool operator<(const StrVec& lhs, const StrVec& rhs)
{
	return lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
}

bool operator>(const StrVec& lhs, const StrVec& rhs)
{
	return rhs < lhs;
}

bool operator<=(const StrVec& lhs, const StrVec& rhs)
{
	return !(rhs < lhs);
}

bool operator>=(const StrVec& lhs, const StrVec& rhs)
{
	return !(lhs < rhs);
}
#include<iostream>
#include<memory>
#include<algorithm>
using namespace std;

class String
{
	friend ostream& operator<<(ostream&, const String&);
	friend bool operator==(const String&, const String&);
	friend bool operator!=(const String&, const String&);
	friend bool operator<(const String&, const String&);
	friend bool operator>(const String&, const String&);
	friend bool operator<=(const String&, const String&);
	friend bool operator>=(const String&, const String&);

public:
	String() : elements(nullptr), last_elem(nullptr) {}
	String(const char*);
	String(const String&);
	String& operator=(const String&);
	String(String&&)noexcept;
	String& operator=(String&&)noexcept;
	~String();

	size_t size()const { return last_elem - elements; }
	char* begin()const { return elements; }
	char* end()const {return last_elem;}

private:
	pair<char*, char*> alloc_n_copy(const char*, const char*);
	void range_initializer(const char*, const char*);
	void free();

	allocator<char> alloc;
	char* elements;
	char* last_elem;
};

pair<char*, char*> String::alloc_n_copy(const char* b, const char* e)
{
	auto str = alloc.allocate(e - b);
	return { str, std::uninitialized_copy(b, e, str) };
}

void String::free()
{
	if (elements)
	{
		for_each(elements, last_elem, [this](char& c) { alloc.destroy(&c); });
		alloc.deallocate(elements, last_elem - elements);
	}
}

void String::range_initializer(const char* b, const char* e)
{
	auto newStr = alloc_n_copy(b, e);
	elements = newStr.first;
	last_elem = newStr.second;
}

String::String(const char* s)
{
	char* s1 = const_cast<char*>(s);
	while (*s1)
		++s1;
	range_initializer(s, s1);
}

String::String(const String& rhs)
{
	range_initializer(rhs.elements, rhs.last_elem);
	cout << "Copy construction" << endl;
}

String& String::operator=(const String& rhs)
{
	auto newStr = alloc_n_copy(rhs.elements, rhs.last_elem);
	free();
	elements = newStr.first;
	last_elem = newStr.second;
	cout << "Copy assignment" << endl;
	return *this;
}

String::String(String&& rhs)noexcept : elements(rhs.elements), last_elem(rhs.last_elem)
{
	rhs.elements = rhs.last_elem = nullptr;
}

String& String::operator=(String&& rhs)noexcept
{
	if (this != &rhs)
	{
		free();
		elements = rhs.elements;
		last_elem = rhs.last_elem;
		rhs.elements = rhs.last_elem = nullptr;
	}
	return *this;
}

String::~String() { free(); }

ostream& operator<<(ostream& os, const String& s)
{
	for (auto beg = s.elements; beg != s.last_elem; ++beg)
		os << *beg;
	return os;
}

bool operator==(const String& lhs, const String& rhs)
{
	return lhs.size() == rhs.size() && equal(lhs.begin(), lhs.end(), rhs.begin());
}
bool operator!=(const String& lhs, const String& rhs)
{
	return !(lhs == rhs);
}

bool operator<(const String& lhs, const String& rhs)
{
	return lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
}

bool operator>(const String& lhs, const String& rhs)
{
	return rhs < lhs;
}

bool operator<=(const String& lhs, const String& rhs)
{
	return !(rhs < lhs);
}

bool operator>=(const String& lhs, const String& rhs)
{
	return !(lhs < rhs);
}

练习 14.19:

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

class Book
{
	friend istream& operator>>(istream&, Book&);
	friend ostream& operator<<(ostream&, const Book&);
	friend bool operator==(const Book&, const Book&);
	friend bool operator!=(const Book&, const Book&);
	friend bool operator<(const Book&, const Book&);
	friend bool operator>(const Book&, const Book&);

public:
	Book() = default;
	Book(string bookNo, string name, string author) :
		m_bookNO(bookNo), m_name(name), m_author(author) {}
	Book(istream& is) { is >> *this; }

private:
	string m_bookNO;
	string m_name;
	string m_author;
};

istream& operator>>(istream& is, Book& book)
{
	is >> book.m_bookNO >> book.m_name >> book.m_author;
	if (!is)
		book = Book();
	return is;
}

ostream& operator<<(ostream& os, const Book& book)
{
	os << book.m_bookNO << " " << book.m_name << " " << book.m_author;
	return os;
}

bool operator==(const Book& lhs, const Book& rhs)
{
	return lhs.m_bookNO == rhs.m_bookNO &&
		lhs.m_name == rhs.m_name &&
		lhs.m_author == rhs.m_author;
}

bool operator!=(const Book& lhs, const Book& rhs)
{
	return !(lhs == rhs);
}

bool operator<(const Book& lhs, const Book& rhs)
{
	return lhs.m_bookNO < rhs.m_bookNO;
}
bool operator>(const Book& lhs, const Book& rhs)
{
	return !(rhs < lhs);
}

练习 14.20:

// 练习 14.2:
Sales_data& Sales_data::operator+=(const Sales_data& rhs)
{
	if (this->isbn() == rhs.isbn())
	{
		this->units_sold += rhs.units_sold;
		this->revenue += rhs.revenue;
		return *this;
	}
}

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

练习 14.21:

// +和+=运算符都使用了Sales_data的临时对象,但这是没有必要的。
Sales_data operator+(const Sales_data& lhs, const Sales_data& rhs)
{
	if (lhs.isbn() == rhs.isbn())
	{
		Sales_data sum;
		sum.bookNo = lhs.bookNo;
		sum.units_sold = lhs.units_sold + rhs.units_sold;
		sum.revenue = lhs.revenue + rhs.revenue;
		return sum;
	}
}

Sales_data& Sales_data::operator+=(const Sales_data& rhs)
{
	if (this->isbn() == rhs.isbn())
	{
		Sales_data temp = *this;
		*this = temp + rhs;
		return *this;
	}
}

练习 14.22:

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

练习 14.23:

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

练习 14.24:

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

class Book
{
	friend istream& operator>>(istream&, Book&);
	friend ostream& operator<<(ostream&, const Book&);
	friend bool operator==(const Book&, const Book&);
	friend bool operator!=(const Book&, const Book&);
	friend bool operator<(const Book&, const Book&);
	friend bool operator>(const Book&, const Book&);

public:
	Book() = default;
	Book(string bookNo, string name, string author) :
		m_bookNO(bookNo), m_name(name), m_author(author) {}
	Book(istream& is) { is >> *this; }
	Book(const Book& book): 
		m_bookNO(book.m_bookNO), m_name(book.m_name), m_author(book.m_author){}
	Book& operator=(const Book& rhs)
	{
		this->m_bookNO = rhs.m_bookNO;
		this->m_name = rhs.m_name;
		this->m_author = rhs.m_author;
		return *this;
	}
	Book(const Book&& book)noexcept: 
		m_bookNO(book.m_bookNO), m_name(book.m_name), m_author(book.m_author) {}
	Book& operator=(const Book& rhs)noexcept
	{
		if (this != &rhs)
		{
			this->m_bookNO = rhs.m_bookNO;
			this->m_name = rhs.m_name;
			this->m_author = rhs.m_author;
		}
		return *this;
	}

private:
	string m_bookNO;
	string m_name;
	string m_author;
};

istream& operator>>(istream& is, Book& book)
{
	is >> book.m_bookNO >> book.m_name >> book.m_author;
	if (!is)
		book = Book();
	return is;
}

ostream& operator<<(ostream& os, const Book& book)
{
	os << book.m_bookNO << " " << book.m_name << " " << book.m_author;
	return os;
}

bool operator==(const Book& lhs, const Book& rhs)
{
	return lhs.m_bookNO == rhs.m_bookNO &&
		lhs.m_name == rhs.m_name &&
		lhs.m_author == rhs.m_author;
}

bool operator!=(const Book& lhs, const Book& rhs)
{
	return !(lhs == rhs);
}

bool operator<(const Book& lhs, const Book& rhs)
{
	return lhs.m_bookNO < rhs.m_bookNO;
}

bool operator>(const Book& lhs, const Book& rhs)
{
	return !(rhs < lhs);
}

练习 14.25:

不需要

练习 14.26:

string& StrBlob::operator[](size_t n)
{
	check(n, "out of range");
	return (*data)[n];
}

const string& StrBlob::operator[](size_t n)const
{
	check(n, "out of range");
	return (*data)[n];;
}

const string& ConstStrBlobPtr::operator[](size_t n) const
{
	auto p = check(n, "out of range");
	return (*p)[n];
}
string& operator[](size_t n) { return elements[n]; }
const string& operator[](size_t n) const { return elements[n]; }
char& operator[](size_t n) { return elements[n]; }
const char& operator[](size_t n) const { return elements[n]; }

练习 14.27:

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

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

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

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

练习 14.28:

ConstStrBlobPtr& ConstStrBlobPtr::operator+=(size_t n)
{
	curr += n;
	check(curr, "increment past end of ConstStrBlobPtr");
	return *this;
}

ConstStrBlobPtr& ConstStrBlobPtr::operator-=(size_t n)
{
	curr -= n;
	check(curr, "decrement past begin of ConstStrBlobPtr");
	return *this;
}

ConstStrBlobPtr ConstStrBlobPtr::operator+(size_t n) const
{
	ConstStrBlobPtr ret = *this;
	ret += n;
	return ret;
}
ConstStrBlobPtr ConstStrBlobPtr::operator-(size_t n) const
{
	ConstStrBlobPtr ret = *this;
	ret -= n;
	return ret;
}

练习 14.29:

因为++和--改变了对象的状态。

练习 14.30:

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

string* StrBlobPtr::operator->()const
{	// 将实际工作委托给解引用运算符
	return &this->operator*();
}

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

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

练习 14.31:
        不需要处理动态内存的分配,因此合成析构函数就足够了。不需要析构函数则也不需要拷贝和赋值操作。因此,合成的版本可以处理所有相应的操作。

练习 14.32:

class StrBlobPtr;

class StrBlobPtr_pointer
{
public:
	StrBlobPtr_pointer() = default;
	StrBlobPtr_pointer(StrBlobPtr* p): pointer(p){}

	StrBlobPtr& operator*();
	StrBlobPtr* operator->();

private:
	StrBlobPtr* pointer = nullptr;
};

StrBlobPtr& StrBlobPtr_pointer::operator*()
{
	return *pointer;
}

StrBlobPtr* StrBlobPtr_pointer::operator->()
{
	return &this->operator*();
}

练习 14.33:

        一个重载的函数调用运算符具有与运算符具有的操作数相同数量的参数。 因此最大值应该在 256 左右。

练习 14.34:

struct Test
{
    int operator()(bool b, int ia, int ib)
    {
        return b ? ia : ib;
    }
};

练习 14.35:

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

class InputString
{
public:
    InputString(istream& i = cin) : is(i) {}
    string operator()()
    {
        string s;
        getline(cin, s);
        return is ? s : string();
    }

private:
    istream& is;
};

int main()
{
    InputString inputstring;
    string s = inputstring();
    cout << s << endl;
}

练习 14.36:

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

class InputString
{
public:
    InputString(istream& i = cin) : is(i) {}
    string operator()()
    {
        string s;
        getline(cin, s);
        return is ? s : string();
    }

private:
    istream& is;
};

int main()
{
    InputString inputstring;
    vector<string> vec;
    for (string s; !(s = inputstring()).empty();)
        vec.push_back(s);
    for (const auto& s : vec)
        cout << s << endl;

    return 0;
}

练习 14.37:

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

class IsEqual
{
public:
    IsEqual(int i) : val(i) {}
    bool operator()(int obj) { return val == obj; }

private:
    int val;
};

int main()
{
    vector<int> vec = { 3,2,6,4,2,1,3,9,5,2 };
    replace_if(vec.begin(), vec.end(), IsEqual(2), 6);

    for (const auto& i : vec)
        cout << i << " ";
    cout << endl;

    return 0;
}

练习 14.38:

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

class CheckString
{
public:
	CheckString(size_t l = 0): sz(l){}
	bool operator()(const string& s)
	{
		return s.size() == sz;
	}

private:
	size_t sz;
};

map<size_t, int> GetStrNum(ifstream& ifs)
{
	vector<string> vec;
	for (string word; ifs >> word;)
	{
		// 去除标点符号
		word.erase(remove_if(word.begin(), word.end(), ispunct), word.end());
		vec.push_back(word);
	}

	map<size_t, int> word_count;
	// 统计特定长度的string数量
	for (size_t n = 1; n <= 10; ++n)
	{
		auto quantity = count_if(vec.begin(), vec.end(), CheckString(n));
		word_count[n] = quantity;
	}
	return word_count;
}

int main()
{
	ifstream ifs("storyDataFile.txt");
	auto word_count = GetStrNum(ifs);
	for (const auto& elem : word_count)
		cout << "string length of " << elem.first << " has " 
			<< elem.second << " words" << endl;

	return 0;
}

练习 14.39:

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

class RangeString
{
public:
	RangeString(size_t l = 0, size_t u = 0) : lower(l), upper(u) {}
	bool operator()(const string& s)
	{
		return s.size() >= lower && s.size() <= upper;
	}

private:
	size_t lower;
	size_t upper;
};

int GetStrNum(ifstream& ifs, size_t l, size_t u)
{
	vector<string> vec;
	for (string word; ifs >> word;)
	{
		// 去除标点符号
		word.erase(remove_if(word.begin(), word.end(), ispunct), word.end());
		vec.push_back(word);
	}

	// 统计特定长度范围的string数量
	auto quantity = count_if(vec.begin(), vec.end(), RangeString(l, u));
	return quantity;
}

int main()
{
	ifstream ifs("storyDataFile.txt");
	cout << GetStrNum(ifs, 1, 9) << endl;
	// 注意:ifstream流状态改变,无法重复调用函数
	//cout << GetStrNum(ifs, 10, 20) << endl;	输出: 0

	return 0;
}

练习 14.40:

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

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

class BiggerEqual
{
public:
    BiggerEqual(size_t l = 0): sz(l){}
    bool operator()(const string& s)
    {
        return s.size() >= sz;
    }
private:
    size_t sz;
};

class Print
{
public:
    Print(ostream& o = cout, char c = ' '): os(o), sep(c){}
    void operator()(const string& s)
    {
        os << s << sep;
    }
private:
    ostream& os;
    char sep;
};

string make_plural(size_t ctr, string const& word, string const& ending)
{
    return (ctr > 1) ? word + ending : word;
}

void elimDups(vector<string>& words)
{
    sort(words.begin(), words.end());
    auto end_unique = unique(words.begin(), words.end());
    words.erase(end_unique, words.end());
}

void biggies(vector<string>& words, vector<string>::size_type sz)
{
    elimDups(words);
    stable_sort(words.begin(), words.end(), ShorterString());
    auto wc = find_if(words.begin(), words.end(), BiggerEqual(sz));
    auto count = words.end() - wc;
    cout << count << " " << make_plural(count, "word", "s") << " of length "
        << sz << " or longer" << endl;
    for_each(wc, words.end(), Print());
    cout << endl;
}

int main()
{
    vector<string> vec{ "fox", "jumps", "over", "quick", "red",
                       "red", "slow",  "the",  "turtle" };
    biggies(vec, 4);
}

练习 14.41:

        当函数不经常使用也不复杂时,可以使用lambda,而当函数被多次调用或者作为lambda实现非常复杂时使用类。

练习 14.42:

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

int main()
{
    vector<int> iv = { 1023, 1024, 1025, 1026 };
    int count = count_if(iv.begin(), iv.end(), bind(greater<int>(), _1, 1024));
    cout << count << endl;

    vector<string> sv = { "pooh", "pony", "pezy", "pooh" };
    auto found = find_if(sv.begin(), sv.end(), 
        bind(not_equal_to<string>(), _1, "pooh"));
    cout << *found << endl;

    transform(iv.begin(), iv.end(), iv.begin(), bind(multiplies<int>(), _1, 2));
    for (int i : iv) 
        cout << i << " ";

    return 0;
}

练习 14.43:

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

int main()
{
    vector<int> iv = { 2, 3, 4 };
    int input = 0;
    while (cin >> input)
    {
        // any_of—如果谓词对范围内的任何一个元素返回true,则返回true,否则返回false。
        auto exist_remainder = any_of(iv.begin(), iv.end(), 
            bind(modulus<int>(), input, _1));
        if(!exist_remainder)
            cout << input << " can be divisible by all elements" << endl;
        else
            cout << input << " can not be divisible by all elements" << endl;
    }

    return 0;
}

练习 14.44:

#include<iostream>
#include<string>
#include<map>
#include<functional>
using namespace std;

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

struct divide
{
    int operator()(int a, int b)
    {
        return a / b;
    }
};

auto mod = [](int a, int b)
{
    return a % b;
};

int main()
{
    map<string, function<int(int, int)>> binops = {
        {"+", add},                                 // 函数指针
        {"-", minus<int>()},                        // 标准库函数对象
        {"/", divide()},                            // 用户定义的函数对象
        {"*", [](int a, int b) {return a * b; }},   // 未命名的lambda
        {"%", mod}                                  // 命名的lambda
    };

    while (true)
    {
        cout << "input num operator num: " << endl;
        int i, j;
        string s;
        cin >> i >> s >> j;
        cout << "= " << binops[s](i, j) << endl;
    }

    return 0;
}

练习 14.45:

#ifndef SALES_DATA_H
#define SALES_DATA_H

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

class Sales_data
{
    friend istream& operator>>(istream&, Sales_data&);
    friend ostream& operator<<(ostream&, Sales_data&);
    friend Sales_data operator+(const Sales_data&, const Sales_data&);
public:
    Sales_data() = default;
    Sales_data(const string& s) : bookNo(s) {}
    Sales_data(const string& s, unsigned n, double p)
        : bookNo(s), units_sold(n), revenue(n* p) {}
    Sales_data(istream& is);
    Sales_data& operator=(const string&);
    Sales_data& operator+=(const Sales_data&);

    explicit operator string()const { return isbn(); }
    explicit operator double()const { return avg_price(); }

    string isbn()const { return bookNo; }

private:
    double avg_price() const { return units_sold ? revenue / units_sold : 0; }

    string bookNo;
    unsigned units_sold = 0;
    double revenue = 0.0;
};

istream& operator>>(istream&, Sales_data&);
ostream& operator<<(ostream&, Sales_data&);
Sales_data operator+(const Sales_data&, const Sales_data&);

#endif
#include"Sales_data.h"

Sales_data::Sales_data(istream& is)
{
	is >> *this;
}

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

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

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

ostream& operator<<(ostream& os, Sales_data& data)
{
	os << data.bookNo << " " << data.units_sold << " " << data.revenue << " "
		<< data.avg_price();
	return os;
}

Sales_data operator+(const Sales_data& lhs, const Sales_data& rhs)
{
	if (lhs.isbn() == rhs.isbn())
	{
		Sales_data sum = lhs;
		sum += rhs;
		return sum;
	}
}
#include"Sales_data.h"

int main()
{
    Sales_data data("Cpp", 4, 30.0);
    cout << data << endl;
    cout << static_cast<string>(data) << endl;
    cout << static_cast<double>(data) << endl;

    return 0;
}

练习 14.46:

        不应该为Sales_data类定义上面两种类型转换运算符,因为这些转换产生误导。应该添加explicit声明以防止隐式转换。

练习 14.47:

struct Integral {
    operator const int();   // 没有意义,编译器会忽略它。
    operator int() const;   // 保证该操作符不会改变对象的状态
};

练习 14.48:

不需要, 没有意义。如果有需要应该声明成explicit,以防止隐式转换。

练习 14.49:

练习 14.50:

struct LongDouble {
    LongDouble(double = 0.0);
    operator double();
    operator float();
};
LongDouble ldObj;
int ex1 = ldObj;    // 二义性: double or float?
float ex2 = ldObj;  // float

练习 14.51:

        double转换为int是标准类型转换;double转换为LongDouble类是构造函数隐式转换;标准类型优先,所以cal(dval)会调用void calc(int)。

练习 14.52:

class SmallInt {
    friend SmallInt operator+(const SmallInt&, const SmallInt&);
public:
    SmallInt(int = 0);
    operator int() const { return val; }
private:
    std::size_t val;
};
 
struct LongDouble {
    LongDouble operator+(const SmallInt&); // 1
    LongDouble(double = 0.0);
    operator double();
    operator float();
};
LongDouble operator+(LongDouble&, double); // 2
 
SmallInt si;
LongDouble ld;
ld = si + ld;    // 二义性错误
ld = ld + si;    // 可以同时使用1和2,但1精确匹配。在2中,SmallInt需要转换为double

练习 14.53:

        适用于内置运算符 operator+(int, double),s1转换为int ;也适用于operator+(const SmallInt&, const SmallInt&),3.14先转为int,再转为SamllInt; 因此产生二义性。

修改使其匹配operator+(const SmallInt&, const SmallInt&):

SmallInt s1;
double d = s1 + SmallInt(3.14);

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:游动-白 设计师:我叫白小胖 返回首页
评论

打赏作者

++Z++

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值