Chapter 14 operator overloading and type conversion

Exercise 14.1:

difference:

  • If an operator function is a member function, its first operand is bound to the implicit this pointer. Therefore, the number of parameters of the member operator function is one less than the total number of operands of the operator.
  • Overloaded operator functions are either members of a class or contain at least one parameter of class type.
  • Overloaded operators do not guarantee the evaluation order of operands. For example, overloaded versions of & & and | no longer have the feature of "short circuit evaluation". Both operands require values, and the evaluation order of operands is not specified.

Similarities:

Overloaded operators have the same priority and association law as the corresponding built-in operators.

Exercise 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;
	}
}

Exercise 14.3:

"cobble" == "stone";       // In the built-in version, the type of string literal is const char []
svec1[0] == svec2[0];      // string          
svec1 == svec2;            // vector
svec1[0] == "stone";       // string

Exercise 14.4:

(a) %          Symmetry operator. Non member

(b) %=        Change the state of the object. member

(c) ++         Change the state of the object. member

(d) ->         Member access arrow. member

(e) <<         Non members.

(f) &&         Symmetry operator. Non member

(g) ==       Symmetry operator. Non member

(h) ()         Call. member

Exercise 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);
}

Exercise 14.6:

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

Exercise 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;
}

Exercise 14.8:

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

Exercise 14.9:

// Exercise 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;
}

Exercise 14.10:

#include"ex14_2.h"

int main()
{
	Sales_data data;
	cin >> data;
	cout << data << endl;
	// 0-201-99999-9 10 24.95 		 Correct output
	// 10 24.95 0-201-99999-9 		 Output 10 24 22.8 0.95

	return 0;
}

Exercise 14.11:

No input check. The result is the same as that in the previous question.

Exercise 14.12:

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

Exercise 14.13:

Sales_ The data class has no other arithmetic operators to overload.

Exercise 14.14:

         Operator + has two const parameters, and the return type is sales_ A copy of the data type. Operator + = there is a const parameter whose return type is sales_ A reference of type data. Every time you do not need to create a temporary variable in the function, you can directly return * this. Therefore, calling operator + = to define operator + will reduce the creation of temporary quantity and be more effective than other methods.

Exercise 14.15:

There is no need to overload other arithmetic operators, because its data members are of type string.

Exercise 14.16:

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

class StrBlobPtr;
class ConstStrBlobPtr;
// StrBlob class
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
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:
	// If the check is successful, check returns a shared to the vector_ ptr
	shared_ptr<vector<string>> check(size_t, const string&)const;
	weak_ptr<vector<string>> wptr;
	size_t curr;    // Current position in the array
};

shared_ptr<vector<string>> StrBlobPtr::check(size_t i, const string& msg)const
{
	auto ret = wptr.lock();	// Does the vector still exist
	if (!ret)
		throw runtime_error("unbound StrBlobPtr");
	if (i >= ret->size())	// Is the index value legal
		throw out_of_range(msg);
	return ret;		// Otherwise, the shared of this vector is returned_ 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
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 operator
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 operator
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 operator
bool operator==(const ConstStrBlobPtr& lhs, const ConstStrBlobPtr& rhs)
{
	return lhs.curr == rhs.curr;
}

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

// Member function
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);
}

Exercise 14.17:

// Exercise 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);
}

Exercise 14.18:

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

class StrBlobPtr;
class ConstStrBlobPtr;
// StrBlob class
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
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:
	// If the check is successful, check returns a shared to the vector_ ptr
	shared_ptr<vector<string>> check(size_t, const string&)const;
	weak_ptr<vector<string>> wptr;
	size_t curr;    // Current position in the array
};

shared_ptr<vector<string>> StrBlobPtr::check(size_t i, const string& msg)const
{
	auto ret = wptr.lock();	// Does the vector still exist
	if (!ret)
		throw runtime_error("unbound StrBlobPtr");
	if (i >= ret->size())	// Is the index value legal
		throw out_of_range(msg);
	return ret;		// Otherwise, the shared of this vector is returned_ 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
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 operator
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 operator
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 operator
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;
}

// Member function
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);
}

Exercise 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);
}

Exercise 14.20:

// Exercise 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;
	}
}

Exercise 14.21:

// +Both the and + = operators use Sales_data, but this is not necessary.
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;
	}
}

Exercise 14.22:

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

Exercise 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;
}

Exercise 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);
}

Exercise 14.25:

unwanted

Exercise 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]; }

Exercise 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;
}

Exercise 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;
}

Exercise 14.29:

Because + + and -- change the state of the object.

Exercise 14.30:

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

string* StrBlobPtr::operator->()const
{	// Delegate the actual work to the dereference operator
	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*();
}

Exercise 14.31:
         There is no need to handle dynamic memory allocation, so synthetic destructors are sufficient. No destructors are required, and no copy and assignment operations are required. Therefore, the synthesized version can handle all corresponding operations.

Exercise 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*();
}

Exercise 14.33:

         An overloaded function call operator has the same number of arguments as the operator has operands. Therefore, the maximum value should be about 256.

Exercise 14.34:

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

Exercise 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;
}

Exercise 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;
}

Exercise 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;
}

Exercise 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;)
	{
		// Remove punctuation
		word.erase(remove_if(word.begin(), word.end(), ispunct), word.end());
		vec.push_back(word);
	}

	map<size_t, int> word_count;
	// Counts the number of string s of a specific length
	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;
}

Exercise 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;)
	{
		// Remove punctuation
		word.erase(remove_if(word.begin(), word.end(), ispunct), word.end());
		vec.push_back(word);
	}

	// Counts the number of string s in a specific length range
	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;
	// Note: the ifstream stream state changes and the function cannot be called repeatedly
	//cout << GetStrNum(ifs, 10, 20) << endl; 	 Output: 0

	return 0;
}

Exercise 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);
}

Exercise 14.41:

         Lambda can be used when functions are not often used or complex, and class can be used when functions are called multiple times or when the implementation as lambda is very complex.

Exercise 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;
}

Exercise 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 - returns true if the predicate returns true for any element in the range, otherwise 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;
}

Exercise 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},                                 // Function pointer
        {"-", minus<int>()},                        // Standard library function object
        {"/", divide()},                            // User defined function object
        {"*", [](int a, int b) {return a * b; }},   // Unnamed lambda
        {"%", mod}                                  // Named 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;
}

Exercise 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;
}

Exercise 14.46:

         Should not be sales_ The data class defines the above two types of conversion operators because these conversions are misleading. explicit declarations should be added to prevent implicit conversions.

Exercise 14.47:

struct Integral {
    operator const int();   // It doesn't make sense. The compiler ignores it.
    operator int() const;   // Ensure that the operator does not change the state of the object
};

Exercise 14.48:

No, it doesn't make sense. If necessary, it should be declared explicit to prevent implicit conversion.

Exercise 14.49:

Exercise 14.50:

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

Exercise 14.51:

         Converting double to int is a standard type conversion; The conversion from double to LongDouble class is an implicit constructor conversion; The standard type takes precedence, so cal(dval) will call void calc(int).

Exercise 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;    // Ambiguous error
ld = ld + si;    // You can use both 1 and 2, but 1 matches exactly. In 2, SmallInt needs to be converted to double

Exercise 14.53:

         Applicable to the built-in operator+(int, double), s1 is converted to int  ; It is also applicable to operator + (const smallint &, const smallint &), 3.14 is converted to int first, and then to SamllInt; Therefore, there is ambiguity.

Modify to match operator + (const smallint &, const smallint &):

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

Tags: C++

Posted on Tue, 23 Nov 2021 00:59:44 -0500 by ghqwerty