《C++primer(第五版)》学习之路-第十四章:重载运算与类型转换

 声明:版权所有,转载请标明出处,请勿用于商业用途。  联系信箱:[email protected]


14.1 基本概念


1.

⑴如果类执行IO操作,则定义移位运算符使其与内置类型的IO保持一致。

⑵如果类的某个操作是检查相等性,则定义operator==;如果类有了operator==,意味着它通常也应该有operator!=。

⑶如果类包含一个内在的单序比较操作,则定义operator<;如果类有了operator<,则它也应该含有其他关系操作。

⑷重载运算符的返回类型通常情况下应该与其内置版本的返回类型兼容;逻辑运算符和关系运算符应该返回bool,算术运算符应该返回一个类类型的值,赋值运算符和复合运算符应该返回左侧运算对象的一个引用。


2.下面的准则有助于我们在将运算符定义为成员函数还是普通的非成员函数做出抉择:

⑴赋值(=),下标([]),调用(())和成员访问箭头(->)运算符必须是成员

⑵复合赋值运算符一般来说应该是成员,但并非必须,这一点与赋值运算符略有不同。

⑶改变对象状态的运算符或者与给定类型密切相关的运算符,如递增、递减和解引用运算符,通常应该是成员

⑷具有对称性的运算符可能转换任意一端的运算对象,例如算术、相等性、关系和位运算符等,因此它们通常应该是普通的非成员函数。


14.2 输入和输出运算符


1.输出运算符尽量减少格式化操作

输入输出运算符必须是非成员函数


14.3 算术和关系运算符


1.相等运算符

⑴如果一个类含有判断两个对象是否相等的操作,则它显然应该把函数定义成operator==而非一个普通的命名函数:因为用户肯定希望能使用==比较对象,所以提供了==就意味着用户无须再费时费力地学习并记忆一个全新得函数名字。此外,类定义了==运算符之后也更容易使用标准库容器和算法。

⑵如果类定义了operator==,则该运算符应该能判断一组给定的对象中是否含有重复数据。

⑶通常情况下,相等运算符应该具有传递性,换句话说,如果a==b和b==c都为真,则a==c也应该为真。

⑷如果类定义了operator==,则这个类也应该定义operator!=。对于用户来说,当他们能使用==时肯定也希望能使用!=,反之亦然

⑸相等运算符和不等运算符中的一个应该把工作委托给另一个,这意味着其中一个运算符应该负责实际比较对象的工作,而另一个运算符则只是调用那个真正工作的运算符。


2.关系运算符

⑴定义顺序关系,令其与关联容器中对关键字的要求一致

⑵如果类同时也含有==运算符的话,则定义一种关系令其与==保持一致。特别是如果两个对象是!=的,那么一个对象应该<另外一个


14.8 函数调用运算符


1.函数调用运算符必须是成员函数。一个类可以定义多个不同版本的调用运算符,相互之间应该在参数数量或类型上有所区别。

如果类定义了调用运算符,则该类的对象称作函数对象。因为可以调用这种对象,所以我们说这些对象的“行为像函数一样”。


2. 标准库函数对象

《C++primer(第五版)》学习之路-第十四章:重载运算与类型转换_第1张图片

 

3.

function的操作

头文件

function f;                       f是一个用来存储可调用对象的空function,这些可调用对象的调用形式应该与函数类型T相同

function f(nullptr);          显式地构造一个空function

function f(obj);               在f中存储可调用对象obj的副本

f                                            将f作为条件:当f含有一个可调用对象时为真,否则为假

f(args)                                  调用f中的对象,参数时args

定义为function的成员的类型

result_type                          该function类型的可调用对象返回的类型

argument_type             

first_argument_type

second_argument_type      当T有一个或两个实参时定义的类型,如果T只有一个实参,则argument_type事该类型的同义词;如果T有两个实参,则first_argument_type和second_argument_type分别代表两个实参的类型。


14.9 重载,类型转换与运算符


1.类型转换运算符是泪的一种特殊成员函数,它负责将一个类类型的值转换成其他类型。类型转换函数的一般形式如下所示:

operator type() const;

其中type表示某种类型。



PS:部分练习答案


练习14.2 & 14.6 &14.9 & 14.20

ex14_02.h

#ifndef CP5_ex14_02_h
#define CP5_ex14_02_h

#include 
#include 

class Sales_data
{
		friend std::istream& operator>>(std::istream&, Sales_data&);       // input
		friend std::ostream& operator<<(std::ostream&, const Sales_data&); // output
		friend Sales_data operator+(const Sales_data&, const Sales_data&); // addition

	public:
		Sales_data(const std::string& s, unsigned n, double p): bookNo(s), units_sold(n), revenue(n * p) {}
		Sales_data() : Sales_data("", 0, 0.0f) {}
		Sales_data(const std::string& s) : Sales_data(s, 0, 0.0f) {}
		Sales_data(std::istream& is);

		Sales_data& operator+=(const Sales_data&); // compound-assignment
		std::string isbn() const
		{
			return bookNo;
		}

	private:
		inline double avg_price() const;

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

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

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

#endif

ex14_02.cpp

#include "ex14_02.h"

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

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

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

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

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

练习14.7

ex14_07.h

#ifndef CP5_STRING_H__
#define CP5_STRING_H__

#include 
#include 

class String
{
		friend std::ostream& operator<<(std::ostream&, const String&);

	public:
		String() : String("") {}
		String(const char*);
		String(const String&);
		String& operator=(const String&);
		~String();

		const char* c_str() const
		{
			return elements;
		}
		size_t size() const
		{
			return end - elements;
		}
		size_t length() const
		{
			return end - elements - 1;
		}

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

	private:
		char* elements;
		char* end;
		std::allocator alloc;
};

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

#endif

ex14_07.cpp

#include "ex14_07.h"
#include 
#include 

std::pair 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::range_initializer(const char* first, const char* last)
{
	auto newstr = alloc_n_copy(first, last);
	elements = newstr.first;
	end = newstr.second;
}

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

String::String(const String& rhs)
{
	range_initializer(rhs.elements, rhs.end);
	std::cout << "copy constructor" << std::endl;
}

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

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

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

std::ostream& operator<<(std::ostream& os, const String& s)
{
	char* c = const_cast(s.c_str());
	while (*c) os << *c++;
	return os;
}

ex14_07_TEST.cpp

#include "ex14_07.h"

int main()
{
    String str("Hello World");
    std::cout << str << std::endl;
}

练习14.5 & 14.8 & 14.12 & 14.15 & 14.17 & 14.19 & 14.24 & 14.25 & 14.48 & 14.49

ex14_49.h

#ifndef DATE_H
#define DATE_H

#include 
#include 

class Date
{
		friend bool operator==(const Date& lhs, const Date& rhs);
		friend bool operator<(const Date& lhs, const Date& rhs);
		friend bool check(const Date& d);
		friend std::ostream& operator<<(std::ostream& os, const Date& d);

	public:
		typedef std::size_t Size;

		//! default constructor
		Date() = default;
		//! constructor taking Size as days
		explicit Date(Size days);
		//! constructor taking three Size
		Date(Size d, Size m, Size y) : day(d), month(m), year(y) {}
		//! constructor taking iostream
		Date(std::istream& is, std::ostream& os);

		//! copy constructor
		Date(const Date& d);
		//! move constructor
		Date(Date&& d) noexcept;

		//! copy operator=
		Date& operator=(const Date& d);
		//! move operator=
		Date& operator=(Date&& rhs) noexcept;

		//! destructor
		~Date()
		{
			std::cout << "destroying\n";
		}

		//! members
		Size toDays() const;
		Date& operator+=(Size offset);
		Date& operator-=(Size offset);
		explicit operator bool()
		{
			return (year < 4000) ? true : false;
		}

	private:
		Size day = 1;
		Size month = 1;
		Size year = 0;
};

static const Date::Size YtoD_400 = 146097; // 365*400 + 400/4 -3 == 146097
static const Date::Size YtoD_100 = 36524; // 365*100 + 100/4 -1 ==  36524
static const Date::Size YtoD_4 = 1461; // 365*4 + 1          ==   1461
static const Date::Size YtoD_1 = 365; // 365

//! normal year
static const std::vector monthsVec_n = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

//! leap year
static const std::vector monthsVec_l = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

//! non-member operators:  <<  >>  -   ==  !=  <   <=  >   >=
//!
std::ostream& operator<<(std::ostream& os, const Date& d);
std::istream& operator>>(std::istream& is, Date& d);
int operator-(const Date& lhs, const Date& rhs);
bool operator==(const Date& lhs, const Date& rhs);
bool operator!=(const Date& lhs, const Date& rhs);
bool operator<(const Date& lhs, const Date& rhs);
bool operator<=(const Date& lhs, const Date& rhs);
bool operator>(const Date& lhs, const Date& rhs);
bool operator>=(const Date& lhs, const Date& rhs);
Date operator-(const Date& lhs, Date::Size rhs);
Date operator+(const Date& lhs, Date::Size rhs);

//!  utillities:
bool check(const Date& d);
inline bool isLeapYear(Date::Size y);

//! check if the date object passed in is valid
inline bool check(const Date& d)
{
	if (d.month == 0 || d.month > 12)
		return false;
	else
	{
		//!    month == 1 3 5 7 8 10 12
		if (d.month == 1 || d.month == 3 || d.month == 5 || d.month == 7 ||
		        d.month == 8 || d.month == 10 || d.month == 12)
		{
			if (d.day == 0 || d.day > 31)
				return false;
			else
				return true;
		}
		else
		{
			//!    month == 4 6 9 11
			if (d.month == 4 || d.month == 6 || d.month == 9 || d.month == 11)
			{
				if (d.day == 0 || d.day > 30)
					return false;
				else
					return true;
			}
			else
			{
				//!    month == 2
				if (isLeapYear(d.year))
				{
					if (d.day == 0 || d.day > 29)
						return false;
					else
						return true;
				}
				else
				{
					if (d.day == 0 || d.day > 28)
						return false;
					else
						return true;
				}
			}
		}
	}
}

inline bool isLeapYear(Date::Size y)
{
	if (!(y % 400))
	{
		return true;
	}
	else
	{
		if (!(y % 100))
		{
			return false;
		}
		else
			return !(y % 4);
	}
}
#endif

ex14_49.cpp

#include "ex14_49.h"
#include 

Date::Date(Size days)
{
	//! calculate the year
	Size y400 = days / YtoD_400;
	Size y100 = (days - y400 * YtoD_400) / YtoD_100;
	Size y4 = (days - y400 * YtoD_400 - y100 * YtoD_100) / YtoD_4;
	Size y = (days - y400 * YtoD_400 - y100 * YtoD_100 - y4 * YtoD_4) / 365;
	Size d = days - y400 * YtoD_400 - y100 * YtoD_100 - y4 * YtoD_4 - y * 365;
	this->year = y400 * 400 + y100 * 100 + y4 * 4 + y;

	std::vector currYear =
	    isLeapYear(this->year) ? monthsVec_l : monthsVec_n;

	Size D_accumu = 0, M_accumu = 0;
	std::find_if(currYear.cbegin(), currYear.cend(), [&](Size m)
	{

		D_accumu += m;
		M_accumu++;

		if (d < D_accumu)
		{
			this->month = M_accumu;
			this->day = d + m - D_accumu;

			return true;
		}
		else
			return false;
	});
}

Date::Date(std::istream& is, std::ostream& os)
{
	is >> day >> month >> year;

	if (is)
	{
		if (check(*this))
			return;
		else
		{
			os << "Invalid input! Object is default initialized.";
			*this = Date();
		}
	}
	else
	{
		os << "Invalid input! Object is default initialized.";
		*this = Date();
	}
}

//! copy constructor
Date::Date(const Date& d) : day(d.day), month(d.month), year(d.year)
{
}

//! move constructor
Date::Date(Date&& d) noexcept :
day(d.day), month(d.month), year(d.year)
{
	std::cout << "copy moving";
}

//! copy operator=
Date& Date::operator=(const Date& d)
{
	this->day = d.day;
	this->month = d.month;
	this->year = d.year;

	return *this;
}

//! move operator=
Date& Date::operator=(Date&& rhs) noexcept
{
	if (this != &rhs)
	{
		this->day = rhs.day;
		this->month = rhs.month;
		this->year = rhs.year;
	}
	std::cout << "moving =";

	return *this;
}

//! conver to days
Date::Size Date::toDays() const
{
	Size result = this->day;

	std::vector currYear = isLeapYear(this->year) ? monthsVec_l : monthsVec_n;

	for (auto it = currYear.cbegin(); it != currYear.cbegin() + this->month - 1;
	        ++it)
		result += *it;

	result += (this->year / 400) * YtoD_400;
	result += (this->year % 400 / 100) * YtoD_100;
	result += (this->year % 100 / 4) * YtoD_4;
	result += (this->year % 4) * YtoD_1;

	return result;
}

//! member operators:   +=  -=

Date& Date::operator+=(Date::Size offset)
{
	*this = Date(this->toDays() + offset);
	return *this;
}

Date& Date::operator-=(Date::Size offset)
{
	if (this->toDays() > offset)
		*this = Date(this->toDays() - offset);
	else
		*this = Date();

	return *this;
}

//! non-member operators:  <<  >>  -   ==  !=  <   <=  >   >=

std::ostream& operator<<(std::ostream& os, const Date& d)
{
	os << d.day << " " << d.month << " " << d.year;
	return os;
}

std::istream& operator>>(std::istream& is, Date& d)
{
	if (is)
	{
		Date input = Date(is, std::cout);
		if (check(input)) d = input;
	}
	return is;
}

int operator-(const Date& lhs, const Date& rhs)
{
	return lhs.toDays() - rhs.toDays();
}

bool operator==(const Date& lhs, const Date& rhs)
{
	return (lhs.day == rhs.day) && (lhs.month == rhs.month) &&
	       (lhs.year == rhs.year);
}

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

bool operator<(const Date& lhs, const Date& rhs)
{
	return lhs.toDays() < rhs.toDays();
}

bool operator<=(const Date& lhs, const Date& rhs)
{
	return (lhs < rhs) || (lhs == rhs);
}

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

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

Date operator-(const Date& lhs, Date::Size rhs)
{
	Date result(lhs);
	result -= rhs;

	return result;
}

Date operator+(const Date& lhs, Date::Size rhs)
{
	Date result(lhs);
	result += rhs;

	return result;
}

main.cpp

#include "ex14_49.h"

int main()
{
	Date date(12, 4, 2015);
	if (static_cast(date)) std::cout << date << std::endl;
}

练习14.21

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

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

练习14.22

ex14_22.h

#ifndef CP5_ex14_22_h
#define CP5_ex14_22_h

#include 
#include 

class Sales_data
{
		friend std::istream& operator>>(std::istream&, Sales_data&);
		friend std::ostream& operator<<(std::ostream&, const Sales_data&);
		friend Sales_data operator+(const Sales_data&, const Sales_data&);

	public:
		Sales_data(const std::string& s, unsigned n, double p):bookNo(s), units_sold(n), revenue(n * p) {}
		Sales_data() : Sales_data("", 0, 0.0f) {}
		Sales_data(const std::string& s) : Sales_data(s, 0, 0.0f) {}
		Sales_data(std::istream& is);

		Sales_data& operator=(const std::string&);

		Sales_data& operator+=(const Sales_data&);
		std::string isbn() const
		{
			return bookNo;
		}

	private:
		inline double avg_price() const;

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

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

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

#endif

ex14_22.cpp

#include "ex14_22.h"

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

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

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

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

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

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

main.cpp

#include "ex14_22.h"

int main()
{
    std::string strCp5("C++ Primer 5th");
    Sales_data cp5 = strCp5;
    std::cout << cp5 << std::endl;
}

练习14.23

ex14_23.h

#ifndef CP5_STRVEC_H_
#define CP5_STRVEC_H_

#include 
#include 
#include 

#ifndef _MSC_VER
#define NOEXCEPT noexcept
#else
#define NOEXCEPT
#endif

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(std::initializer_list);
		StrVec(const StrVec&);
		StrVec& operator=(const StrVec&);
		StrVec(StrVec&&) NOEXCEPT;
		StrVec& operator=(StrVec&&) NOEXCEPT;
		~StrVec();

		StrVec& operator=(std::initializer_list);

		void push_back(const std::string&);
		size_t size() const
		{
			return first_free - elements;
		}
		size_t capacity() const
		{
			return cap - elements;
		}
		std::string* begin() const
		{
			return elements;
		}
		std::string* end() const
		{
			return first_free;
		}

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

		void reserve(size_t new_cap);
		void resize(size_t count);
		void resize(size_t count, const std::string&);

	private:
		std::pair alloc_n_copy(const std::string*,
		        const std::string*);
		void free();
		void chk_n_alloc()
		{
			if (size() == capacity()) reallocate();
		}
		void reallocate();
		void alloc_n_move(size_t new_cap);
		void range_initialize(const std::string*, const std::string*);

	private:
		std::string* elements;
		std::string* first_free;
		std::string* cap;
		std::allocator alloc;
};

bool operator==(const StrVec&, const StrVec&);
bool operator!=(const StrVec&, const StrVec&);
bool operator<(const StrVec&, const StrVec&);
bool operator>(const StrVec&, const StrVec&);
bool operator<=(const StrVec&, const StrVec&);
bool operator>=(const StrVec&, const StrVec&);

#endif

ex14_23.cpp

#include "ex14_23.h"
#include  // for_each, equal

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

std::pair StrVec::alloc_n_copy(const std::string* b, const std::string* e)
{
	auto data = alloc.allocate(e - b);
	return {data, std::uninitialized_copy(b, e, data)};
}

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

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

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

StrVec::StrVec(std::initializer_list il)
{
	range_initialize(il.begin(), il.end());
}

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

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

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

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

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

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

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

StrVec::StrVec(StrVec&& s) NOEXCEPT :
elements(s.elements),first_free(s.first_free),cap(s.cap)
{
	s.elements = s.first_free = s.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() &&
	        std::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 std::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);
}

StrVec& StrVec::operator=(std::initializer_list il)
{
	*this = StrVec(il);
	return *this;
}

main.cpp

#include "ex14_23.h"
#include 
#include 

int main()
{
	StrVec vec;
	vec.reserve(6);
	std::cout << "capacity(reserve to 6): " << vec.capacity() << std::endl;

	vec.reserve(4);
	std::cout << "capacity(reserve to 4): " << vec.capacity() << std::endl;

	vec.push_back("hello");
	vec.push_back("world");

	vec.resize(4);

	for (auto i = vec.begin(); i != vec.end(); ++i)
		std::cout << *i << std::endl;
	std::cout << "-EOF-" << std::endl;

	vec.resize(1);

	for (auto i = vec.begin(); i != vec.end(); ++i)
		std::cout << *i << std::endl;
	std::cout << "-EOF-" << std::endl;

	StrVec vec_list {"hello", "world", "pezy"};

	for (auto i = vec_list.begin(); i != vec_list.end(); ++i)
		std::cout << *i << " ";
	std::cout << std::endl;

	// Test operator==
	const StrVec const_vec_list = {"hello", "world", "pezy"};
	if (vec_list == const_vec_list)
		for (const auto& str : const_vec_list) std::cout << str << " ";
	std::cout << std::endl;

	// Test operator<
	const StrVec const_vec_list_small = {"hello", "pezy", "ok"};
	std::cout << (const_vec_list_small < const_vec_list) << std::endl;
}

练习14.30

ex14_30_StrBlob.h

#ifndef CP5_STRBLOB_H_
#define CP5_STRBLOB_H_

#include 
using std::vector;

#include 
using std::string;

#include 
using std::initializer_list;

#include 
using std::make_shared;
using std::shared_ptr;

#include 

#ifndef _MSC_VER
#define NOEXCEPT noexcept
#else
#define NOEXCEPT
#endif

class StrBlobPtr;
class ConstStrBlobPtr;

//=================================================================================
//
//		StrBlob - custom vector
//
//=================================================================================

class StrBlob
{
		using size_type = vector::size_type;
		friend class ConstStrBlobPtr;
		friend class StrBlobPtr;
		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>()) {}
		StrBlob(initializer_list il) : data(make_shared>(il))
		{
		}

		StrBlob(const StrBlob& sb) : data(make_shared>(*sb.data)) {}
		StrBlob& operator=(const StrBlob&);

	StrBlob(StrBlob&& rhs) NOEXCEPT :
		data(std::move(rhs.data)) {}
		StrBlob& operator=(StrBlob&&) NOEXCEPT;

		StrBlobPtr begin();
		StrBlobPtr end();

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

		string& operator[](size_t n);
		const string& operator[](size_t n) 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 push_back(string&& s)
		{
			data->push_back(std::move(s));
		}

		void pop_back();
		string& front();
		string& back();
		const string& front() const;
		const string& back() const;

	private:
		void check(size_type, const string&) const;

		shared_ptr> data;
};

bool operator==(const StrBlob&, const StrBlob&);
bool operator!=(const StrBlob&, const StrBlob&);
bool operator<(const StrBlob&, const StrBlob&);
bool operator>(const StrBlob&, const StrBlob&);
bool operator<=(const StrBlob&, const StrBlob&);
bool operator>=(const StrBlob&, const StrBlob&);

inline void StrBlob::pop_back()
{
	check(0, "pop_back on empty StrBlob");
	data->pop_back();
}

inline string& StrBlob::front()
{
	check(0, "front on empty StrBlob");
	return data->front();
}

inline string& StrBlob::back()
{
	check(0, "back on empty StrBlob");
	return data->back();
}

inline const string& StrBlob::front() const
{
	check(0, "front on empty StrBlob");
	return data->front();
}

inline const string& StrBlob::back() const
{
	check(0, "back on empty StrBlob");
	return data->back();
}

inline void StrBlob::check(size_type i, const string& msg) const
{
	if (i >= data->size()) throw std::out_of_range(msg);
}

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

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

//=================================================================================
//
//		StrBlobPtr - custom iterator of StrBlob
//
//=================================================================================

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& operator++();
		StrBlobPtr& operator--();
		StrBlobPtr operator++(int);
		StrBlobPtr operator--(int);
		StrBlobPtr& operator+=(size_t);
		StrBlobPtr& operator-=(size_t);
		StrBlobPtr operator+(size_t) const;
		StrBlobPtr operator-(size_t) const;

		string& operator[](size_t n);
		const string& operator[](size_t n) const;

	private:
		shared_ptr> check(size_t, const string&) const;

		std::weak_ptr> wptr;
		size_t curr;
};

bool operator==(const StrBlobPtr&, const StrBlobPtr&);
bool operator!=(const StrBlobPtr&, const StrBlobPtr&);
bool operator<(const StrBlobPtr&, const StrBlobPtr&);
bool operator>(const StrBlobPtr&, const StrBlobPtr&);
bool operator<=(const StrBlobPtr&, const StrBlobPtr&);
bool operator>=(const StrBlobPtr&, const StrBlobPtr&);

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

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

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

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

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

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

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

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

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

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

inline string& StrBlobPtr::operator[](size_t n)
{
	auto p = check(n, "dereference out of range.");
	return (*p)[n];
}

inline const string& StrBlobPtr::operator[](size_t n) const
{
	auto p = check(n, "dereference out of range.");
	return (*p)[n];
}

//=================================================================================
//
//		ConstStrBlobPtr - custom const_iterator of StrBlob
//
//=================================================================================

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& s, size_t sz = 0) : wptr(s.data), curr(sz) {}

		const string& operator*() const;
		const string* operator->() const;
		ConstStrBlobPtr& operator++();
		ConstStrBlobPtr& operator--();
		ConstStrBlobPtr operator++(int);
		ConstStrBlobPtr operator--(int);
		ConstStrBlobPtr& operator+=(size_t);
		ConstStrBlobPtr& operator-=(size_t);
		ConstStrBlobPtr operator+(size_t) const;
		ConstStrBlobPtr operator-(size_t) const;

		const string& operator[](size_t n) const;

	private:
		std::shared_ptr> check(size_t, const string&) const;

		std::weak_ptr> wptr;
		size_t curr;
};

bool operator==(const ConstStrBlobPtr&, const ConstStrBlobPtr&);
bool operator!=(const ConstStrBlobPtr&, const ConstStrBlobPtr&);
bool operator<(const ConstStrBlobPtr&, const ConstStrBlobPtr&);
bool operator>(const ConstStrBlobPtr&, const ConstStrBlobPtr&);
bool operator<=(const ConstStrBlobPtr&, const ConstStrBlobPtr&);
bool operator>=(const ConstStrBlobPtr&, const ConstStrBlobPtr&);

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

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

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

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

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

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

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

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

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

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

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

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

#endif

ex14_30_StrBlob.cpp

#include "ex14_30_StrBlob.h"
#include 

//==================================================================
//
//		StrBlob - operators
//
//==================================================================

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 std::lexicographical_compare(lhs.data->begin(), lhs.data->end(), rhs.data->begin(), rhs.data->end());
}

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

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

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

//================================================================
//
//		StrBlobPtr - operators
//
//================================================================

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& x, const StrBlobPtr& y)
{
	return x.curr < y.curr;
}

bool operator>(const StrBlobPtr& x, const StrBlobPtr& y)
{
	return x.curr > y.curr;
}

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

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

//================================================================
//
//		ConstStrBlobPtr - operators
//
//================================================================

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

//==================================================================
//
//		copy assignment operator and move assignment operator.
//
//==================================================================

StrBlob& StrBlob::operator=(const StrBlob& lhs)
{
	data = make_shared>(*lhs.data);
	return *this;
}

StrBlob& StrBlob::operator=(StrBlob&& rhs) NOEXCEPT
{
	if (this != &rhs)
	{
		data = std::move(rhs.data);
		rhs.data = nullptr;
	}

	return *this;
}

//==================================================================
//
//		members
//
//==================================================================

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

main.cpp

#include "ex14_30_StrBlob.h"
#include 

int main()
{
	StrBlob sb1 {"a", "b", "c"};
	StrBlob sb2 = sb1;

	sb2[2] = "b";

	if (sb1 > sb2)
	{
		for (ConstStrBlobPtr iter = sb1.cbegin(); iter != sb1.cend(); ++iter)
			std::cout << *iter << " ";
		std::cout << std::endl;
	}

	ConstStrBlobPtr iter(sb2);
	std::cout << iter->size() << std::endl;
}

练习14.32

ex14_32.h

#ifndef STRBLOBPTR_POINTER_H
#define STRBLOBPTR_POINTER_H

class StrBlobPtr;

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

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

	private:
		StrBlobPtr* pointer = nullptr;
};

#endif

ex14_32.cpp

#include "ex14_32.h"
#include "ex14_30_StrBlob.h"
#include 

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

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

int main()
{
	StrBlob sb {"hello", "world"};
	StrBlobPtr iter = sb.begin();
	StrBlobPtr_pointer p(&iter);
	std::cout << p->deref() << std::endl;
}

练习14.35

#include 
#include 

class GetInput
{
	public:
		GetInput(std::istream& i = std::cin) : is(i) {}
		std::string operator()() const
		{
			std::string str;
			std::getline(is, str);
			return is ? str : std::string();
		}

	private:
		std::istream& is;
};

int main()
{
	GetInput getInput;
	std::cout << getInput() << std::endl;
}

练习14.36

#include 
#include 
#include 

class GetInput
{
	public:
		GetInput(std::istream& i = std::cin) : is(i) {}
		std::string operator()() const
		{
			std::string str;
			std::getline(is, str);
			return is ? str : std::string();
		}

	private:
		std::istream& is;
};

int main()
{
	GetInput getInput;
	std::vector vec;
	for (std::string tmp; !(tmp = getInput()).empty();)
		vec.push_back(tmp);
	for (const auto& str : vec)
		std::cout << str << " ";
	std::cout << std::endl;
}

练习14.37

#include 
#include 
#include 

class IsEqual
{
		int value;

	public:
		IsEqual(int v) : value(v) {}
		bool operator()(int elem)
		{
			return elem == value;
		}
};

int main()
{
	std::vector vec = {3, 2, 1, 4, 3, 7, 8, 6};
	std::replace_if(vec.begin(), vec.end(), IsEqual(3), 5);
	for (int i : vec)
		std::cout << i << " ";
	std::cout << std::endl;
}

练习14.38 & 14.39

#include 
#include 
#include 
#include 
#include 

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

	private:
		std::size_t lower;
		std::size_t upper;
};

int main()
{
	std::ifstream fin("storyDataFile.txt");

	std::size_t quantity9 = 0, quantity10 = 0;
	BoundTest test9(1, 9);
	BoundTest test10(1, 10);

	for (std::string word; fin >> word;)
	{
		if (test9(word)) ++quantity9;
		if (test10(word)) ++quantity10;
	}

	std::cout << quantity9 << ", " << quantity10 << std::endl;
}

练习14.40

#include 
#include 
#include 
#include 

using std::cout;
using std::endl;
using std::string;
using std::vector;
using std::sort;
using std::stable_sort;
using std::for_each;

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

class BiggerEqual
{
		size_t sz_;

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

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

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

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

void biggies(vector& words, vector::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 vec {"fox", "jumps", "over", "quick", "red", "red", "slow",  "the",  "turtle"};
	biggies(vec, 4);
}

练习14.42

#include 
#include 
#include 
#include 
#include 

int main()
{
	using std::placeholders::_1;

	std::vector ivec {1, 111, 1111, 11111};
	int count = std::count_if(ivec.cbegin(), ivec.cend(),  std::bind(std::greater(), _1, 1024));
	std::cout << count << std::endl;

	std::vector svec {"pooh", "pooh", "pezy", "pooh"};
	auto found = std::find_if(svec.cbegin(), svec.cend(), std::bind(std::not_equal_to(), _1, "pooh"));
	std::cout << *found << std::endl;

	std::transform(ivec.begin(), ivec.end(), ivec.begin(), std::bind(std::multiplies(), _1, 2));
	for (int i : ivec) std::cout << i << " ";
	std::cout << std::endl;
}

练习14.43

#include 
#include 
#include 
#include 

int main()
{
	auto data = {2, 3, 4, 5};
	int input;
	std::cin >> input;
	std::modulus mod;
	auto predicator = [&](int i)
	{
		return 0 == mod(input, i);
	};
	auto is_divisible = std::any_of(data.begin(), data.end(), predicator);
	std::cout << (is_divisible ? "Yes!" : "No!") << std::endl;

	return 0;
}

练习14.44

#include 
#include 
#include 
#include 

//! normal function
int add(int i, int j)
{
	return i + j;
}

//! named lambda
auto mod = [](int i, int j)
{
	return i % j;
};

//! functor
struct wy_div
{
	int operator()(int denominator, int divisor)
	{
		return denominator / divisor;
	}
};

//! the map
std::map> binops =
{
	{"+", add},                                //  function pointer
	{"-", std::minus()},                  //  library functor
	{"/", wy_div()},                           //  user-defined functor
	{"*", [](int i, int j)
		{
			return i * j;
		}
	}, //  unnamed lambda
	{"%", mod}                                 //  named lambda object
};

int main()
{
	while (true)
	{
		std::cout << "\npleasr enter: num operator num :\n";
		int n1, n2;
		std::string s;
		std::cin >> n1 >> s >> n2;

		std::cout << binops[s](n1, n2);
	}

	return 0;
}

练习14.45

ex14_45.h

#ifndef CP5_ex14_45_h
#define CP5_ex14_45_h

#include 
#include 

class Sales_data
{
		friend std::istream& operator>>(std::istream&, Sales_data&);
		friend std::ostream& operator<<(std::ostream&, const Sales_data&);
		friend Sales_data operator+(const Sales_data&, const Sales_data&);

	public:
		Sales_data(const std::string& s, unsigned n, double p) : bookNo(s), units_sold(n), revenue(n * p)
		{
		}
		Sales_data() : Sales_data("", 0, 0.0f) {}
		Sales_data(const std::string& s) : Sales_data(s, 0, 0.0f) {}
		Sales_data(std::istream& is);

		Sales_data& operator=(const std::string&);
		Sales_data& operator+=(const Sales_data&);
		explicit operator std::string() const
		{
			return bookNo;
		}
		explicit operator double() const
		{
			return avg_price();
		}

		std::string isbn() const
		{
			return bookNo;
		}

	private:
		inline double avg_price() const;

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

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

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

#endif

ex14_45.cpp

#include "ex14_45.h"

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

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

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

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

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

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

main.cpp

#include "ex14_45.h"

int main()
{
    Sales_data cp5("C++ Primer 5th", 4, 106.5);
    std::cout << cp5 << std::endl;
    std::cout << static_cast(cp5) << std::endl;
    std::cout << static_cast(cp5) << std::endl;
}

练习14.53

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



你可能感兴趣的:(《C++primer(第五版)》学习之路-第十四章:重载运算与类型转换)