欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

c++primer第五版第十九章练习

程序员文章站 2023-03-29 13:59:16
19.1 #include #include void *operator new(std::size_t n){ std::cout << &q...

19.1

#include 
#include 

void *operator new(std::size_t n){
	std::cout << "new(size_t)\n";
	if (void *mem = malloc(n))
		return mem;
	else
		throw std::bad_alloc();
}
void operator delete(void *mem) noexcept{
	std::cout << "delete(void*)\n";
	free(mem);
}
int main()
{
	using namespace std;
	int *a = new int(486);
	cout << a << " " << *a << endl;
	delete a;
	system("pause");
	return 0;
}

19.2
#ifndef H13_39_H_
#define H13_39_H_
#include 
#include 
#include 	//allocator
#include 	//move
#include 
#include 	//for_each
class StrVec
{
	std::allocator alloc;//为所有StrVec对象分配内存用
	void chk_n_alloc()		//如果剩余空间为0就分配新空间
	{
		if (size() == capacity())
			reallocate();
	}
	std::pair alloc_n_copy(const std::string *b, const std::string *e);//创建一个内容为b到e之间的元素的对象,并返回这个对象的一对头尾指针
	void free();//释放所有alloc分配的所有内存
	void reallocate();//移动当前对象的元素到2倍对象大小的新对象里
	std::string *elements;
	std::string *first_free;
	std::string *cap;
public:
	StrVec() :elements(nullptr), first_free(nullptr), cap(nullptr) {}
	StrVec(std::initializer_list il);
	StrVec(const StrVec &s);
	StrVec(StrVec &&s);//13.49
	StrVec &operator=(StrVec &&s);//13.49
	StrVec &operator=(const StrVec &s);
	~StrVec();
	void push_back(const std::string &s);//把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;
	}
};
void StrVec::push_back(const std::string &s)
{
	chk_n_alloc();//确保空间剩余
	alloc.construct(first_free++, s);//在尾后构建一个s(s的拷贝构造函数构造),并把尾后指针first_free指向下一个
}
std::pair StrVec::alloc_n_copy(const std::string *b, const std::string *e)
{
	auto data = alloc.allocate(e - b);//分配并返回n个string对象的地址 string *
	return{ data, std::uninitialized_copy(b, e, data) };//uninit_copy返回尾后指针string *
														//把l~r之间的元素拷贝到data开始的地址,并返回data尾后,然后使用data(begin)和返回值(end)构建一个pair
}
void StrVec::free()
{
	if (elements)//如果不为空
	{
		for (auto p = first_free; p != elements;)
			alloc.destroy(--p);//从最后一个元素开始向前摧毁,调用p的析构函数
							   //for_each(elements, first_free, [this](std::string *s){alloc.destroy(s); });//13.43
		alloc.deallocate(elements, cap - first_free);//释放elements开始的n的string对象的内存
	}
}
StrVec::StrVec(std::initializer_list il)
{
	auto newdata = alloc_n_copy(il.begin(), il.end());
	elements = newdata.first;
	first_free = cap = newdata.second;
}
StrVec::StrVec(const StrVec &s)
{
	auto newdata = alloc_n_copy(s.begin(), s.end());//创建一个s的副本 值
	elements = newdata.first;//把头指向新创建的副本的头
	first_free = cap = newdata.second;//把尾后和内存尾指向副本的尾(以后调用会调用chk_n_alloc,不用担心剩余空间大小)
}
StrVec::StrVec(StrVec &&s) :elements(s.elements), first_free(s.first_free), cap(s.cap)
{
	s.elements = s.first_free = s.cap = nullptr;
}
StrVec &StrVec::operator=(StrVec &&s)
{
	if (this == &s)
		return *this;
	free();
	elements = s.elements;
	first_free = s.first_free;
	cap = s.cap;
	s.elements = s.first_free = s.cap = nullptr;
	return *this;
}
StrVec::~StrVec()
{
	free();//清理当前对象alloc分配的内存
}
StrVec &StrVec::operator=(const StrVec &s)
{
	if (this == &s)
		return *this;
	auto data = alloc_n_copy(s.elements, s.first_free);
	free();
	elements = data.first;
	first_free = cap = data.second;
	return *this;
}
void StrVec::reallocate()
{
	auto newcapacity = size() ? 2 * size() : 1;	//当前空间的两倍大小
	auto newdata = alloc.allocate(newcapacity);	//分配并返回newcapacity个string对象大小的空间
	auto dest = newdata;
	auto elem = elements;//指向当前对象的头
	for (size_t i = 0; i != size(); ++i)
	{
		alloc.construct(dest++, std::move(*elem++));//move会让elem指向的string对象放弃自己的内存管理权并返回,然后construct使用string的移动构造函数构建dest指向的地址
	}												//接受dest会指向newdata的尾后
	free();				//移动完后释放当前对象指向的内存
	elements = newdata;	//指向新头
	first_free = dest;	//指向新尾后		
	cap = elements + newcapacity;	//指向内存尾
}

#endif

#include "head.h"
#include 

void *operator new(std::size_t n)
{
	std::cout << "new(size_t)\n";
	if (void *mem = malloc(n))
		return mem;
	else
		throw std::bad_alloc();
}
void operator delete(void *mem) noexcept
{
	std::cout << "delete(void*)\n";
	free(mem);
}
int main()
{
	using namespace std;
	StrVec str{ "c++","primer","effictive" };
	for (auto it = str.begin(), e = str.end(); it != e; ++it)
		cout << *it << endl;
	system("pause");
	return 0;
}

19.3、19.4

#include 
#include 
using std::cout;
using std::endl;
class A {
public:
	A() { cout << "A()" << endl; }
	virtual ~A(){ cout << "~A()" << endl; }
};
class B :public A {
public:
	B() { cout << "B()" << endl; }
	virtual ~B() { cout << "~B()" << endl; }
};
class C :public B {
public:
	C() { cout << "C()" << endl; }
	virtual ~C() { cout << "~C()" << endl; }
};
class D :public B, public A {
public:
	D() { cout << "D()" << endl; }
	virtual ~D() { cout << "~D()" << endl; }
};

int main()
{
	using namespace std;
	A *pa = new C;
	if (B *pb = dynamic_cast(pa))//a)   T
		cout << "a)	T" << endl;
	else
		cout << "a)	F" << endl;
	B *pbb = new B;
	if (C *pc = dynamic_cast(pbb))//b)   F:pbb指向的对象不包含C对象,返回0
		cout << "b)	T" << endl;
	else
		cout << "b)	F" << endl;
	A *paa = new D;
	if (B *pbbb = dynamic_cast(paa))//c)   T
		cout << "c)	T" << endl;
	else
		cout << "c)	F" << endl;


	try {
		C &cp = dynamic_cast(*pa);//正确,*pa的类型是C
		cout << "cp" << endl;
		C &ccp = dynamic_cast(*paa);//异常,*paa类型是D,不是C或其派生类,D不是C的派生类
		cout << "ccp" << endl;
	}
	catch (std::bad_cast e) {
		cout << e.what() << endl;
	}

	system("pause");
	return 0;
}

19.5

当派生类定义了自己的成员,而我们能操作的只有指向该派生类的基类指针或引用,那么可以使用dynamic_cast进行强制转换成该派生类:

class A{
public:
  ~A(){}
}
class B:public A{
public:
  void print(){...}
}
void f(A *a){
  //想要调用B::print
  B *b=dynamic_cast(a);
  b.print();
}
...
int main(){
  B b;
  A *a=&b;
  f(a);
  

}

19.6、19.7、19.8

//TextQuery.h
#pragma once
#include 
#include 
#include 
#include 
#include 
#include
#include 
#include 
std::string make_plural(size_t, const std::string&, const std::string&);
class QueryResult;
class TextQuery {
public:
	using line_no = std::vector::size_type;
	TextQuery(std::ifstream &is)
	{
		std::string text;
		while (getline(is, text)) 
		{
			file->push_back(text); 
			int n = file->size() - 1;
			std::istringstream line(text); 
			std::string word;
			while (line >> word)
			{
				auto &lines = wm[word];
				if (!lines)
					lines.reset(new std::set);
				lines->insert(n);
			}
		}
	}
	QueryResult query(const std::string &sought) const;
private:
	std::shared_ptr> file;
	std::map>> wm;
};
class QueryResult {
	friend std::ostream& print(std::ostream &os, const QueryResult &qr, TextQuery::line_no min, TextQuery::line_no max)
	{
		os << qr.sought << " occurs " << qr.lines->size() << " "
			<< make_plural(qr.lines->size(), "time", "s") << std::endl;
		for (auto num : *qr.lines) {
			if ((num + 1) >= min && (num + 1) <= max)
				os << "\t(line " << num + 1 << ") "
				<< *(qr.file->begin() + num) << std::endl;
			else if ((num + 1 > max))
				break;
		}
		return os;
	}
public:
	QueryResult(std::string s, std::shared_ptr> p, std::shared_ptr> f) :sought(s), lines(p), file(f) {}
	std::set::iterator begin() const { return lines->begin(); }
	std::set::iterator end() const { return lines->end(); }
	std::shared_ptr> get_file() const { return file; }
private:
	std::string sought;
	std::shared_ptr> lines;
	std::shared_ptr> file;
};

QueryResult TextQuery::query(const std::string &sought) const
{
	static std::shared_ptr> nodata(new std::set);
	auto loc = wm.find(sought);
	if (loc == wm.end())
		return QueryResult(sought, nodata, file);
	else
		return QueryResult(sought, loc->second, file);
}


std::string make_plural(size_t ctr, const std::string &word, const std::string &ending)
{
	return (ctr > 1) ? word + ending : word;
}
//Query.h
#pragma once
#include 
#include 
#include 
#include 
#include 
#include "TextQuery.h"
class Query_base {
	friend void cast_test();
	friend class Query;
protected:
	using line_no = TextQuery::line_no;
	virtual ~Query_base() = default;
private:
	virtual QueryResult eval(const TextQuery&) const = 0;
	virtual std::string rep() const = 0;
};

class WordQuery : public Query_base {
	friend void cast_test();
	friend class Query;
	WordQuery(const std::string &s) : query_word(s) {}
	QueryResult eval(const TextQuery &t) const
	{
		return t.query(query_word);
	}
	std::string rep() const { return query_word; }
	std::string query_word;
};

class Query {
	friend Query operator~(const Query&);
	friend Query operator|(const Query&, const Query&);
	friend Query operator&(const Query&, const Query&);
public:
	Query(const std::string &s) : q(new WordQuery(s)), cnt(new std::size_t(1)) {}; 
	QueryResult eval(const TextQuery &t) const
	{
		return q->eval(t);
	}
	std::string rep() const { return q->rep(); }
	Query(const Query &query) : q(query.q), cnt(query.cnt) { ++*cnt; }
	Query(Query &&query) noexcept : q(query.q), cnt(query.cnt) { query.q = 0; }
	Query& operator=(const Query&);
	Query& operator=(Query&&) noexcept;
	~Query();
private:
	Query(Query_base *query) : q(query), cnt(new std::size_t(1)) {}
	Query_base *q;
	std::size_t *cnt;
};
inline
Query& Query::operator=(const Query &rhs)
{
	++*rhs.cnt;
	if (--*cnt == 0)
	{
		delete q;
		delete cnt;
	}
	q = rhs.q;
	cnt = rhs.cnt;
	return *this;
}
inline
Query& Query::operator=(Query &&rhs) noexcept
{
	if (this != &rhs) {
		cnt = rhs.cnt;
		q = rhs.q;
		rhs.q = 0;
	}
	return *this;
}
inline
Query::~Query()
{
	if (--*cnt == 0) {
		delete q;
		delete cnt;
	}
}
inline std::ostream& operator<<(std::ostream &os, const Query &query)
{
	return os << query.rep();
}

class BinaryQuery : public Query_base {
	friend void cast_test();
protected:
	BinaryQuery(const Query &l, const Query &r, std::string s) :
		lhs(l), rhs(r), opSym(s) {}
	std::string rep() const {
		return "(" + lhs.rep() + " "
			+ opSym + " "
			+ rhs.rep() + ")";
	}
	Query lhs, rhs;
	std::string opSym;
};

class OrQuery : public BinaryQuery {
	friend void cast_test();
	friend Query operator|(const Query&, const Query&);
	OrQuery(const Query &left, const Query &right) :
		BinaryQuery(left, right, "|") {}
	QueryResult eval(const TextQuery &text) const
	{
		auto left = lhs.eval(text), right = rhs.eval(text);
		auto ret_lines = std::make_shared>(left.begin(), left.end());
		ret_lines->insert(right.begin(), right.end());
		return QueryResult(rep(), ret_lines, left.get_file());
	}
};

class AndQuery : public BinaryQuery {
	friend void cast_test();
	friend Query operator&(const Query&, const Query&);
	AndQuery(const Query &left, const Query &right) :
		BinaryQuery(left, right, "&") {}
	QueryResult eval(const TextQuery &text) const
	{
		auto left = lhs.eval(text), right = rhs.eval(text);
		auto ret_lines = std::make_shared>();
		std::set_intersection(left.begin(), left.end(), right.begin(), right.end(),
			std::inserter(*ret_lines, ret_lines->begin()));
		return QueryResult(rep(), ret_lines, left.get_file());
	}
};

class NotQuery : public Query_base {
	friend void cast_test();
	friend Query operator~(const Query&);
	NotQuery(const Query &q) : query(q) {}
	std::string rep() const {}
	QueryResult eval(const TextQuery &text) const
	{
		auto result = query.eval(text);
		auto ret_lines = std::make_shared>();
		auto beg = result.begin(), end = result.end();
		auto sz = result.get_file()->size();
		for (std::size_t n = 0; n != sz; ++n) {
			if (beg == end || *beg != n)
				ret_lines->insert(n);
			else
				++beg;
		}
		return QueryResult(rep(), ret_lines, result.get_file());
	}
	Query query;
};

inline Query operator|(const Query &lhs, const Query &rhs)
{
	return (new OrQuery(lhs, rhs));
}

inline Query operator&(const Query &lhs, const Query &rhs)
{
	return (new AndQuery(lhs, rhs));
}

inline Query operator~(const Query &operand)
{
	return (new NotQuery(operand));
}
//main.cpp
#include 
#include 
#include "Query.h"
using std::cout;
using std::endl;
using std::bad_cast;
void cast_test()
{
	//19.6
	Query_base *pb1 = new AndQuery(Query("value1"), Query("value2"));
	Query_base *pb2 = new OrQuery(Query("value1"), Query("value2"));
	if (AndQuery *pa1 = dynamic_cast(pb1)) {
		cout << "成功" << endl;
	}
	else {
		cout << "失败" << endl;
	}
	if (AndQuery *pa2 = dynamic_cast(pb2)) {
		cout << "成功" << endl;
	}
	else {
		cout << "失败" << endl;
	}
	//19.7
	try {
		AndQuery &ra1 = dynamic_cast(*pb1);
		cout << "成功" << endl;
	}
	catch (bad_cast e) {
		cout << e.what() << endl;
	}
	try {
		AndQuery &ra2 = dynamic_cast(*pb2);
		cout << "成功" << endl;
	}
	catch (bad_cast e) {
		cout << e.what() << endl;
	}
	//19.8
	if (typeid(*pb1) == typeid(*pb2))
		cout << "pd1与pd2指向的对象类型相同" << endl;
	else
		cout << "pd1与pd2的动态类型不相同" << endl;
	if (typeid(*pb1) == typeid(AndQuery))
		cout << "pd1的动态类型是AndQuery" << endl;
	else
		cout << "pd1的动态类型并非是AndQuery" << endl;
	if (typeid(*pb2) == typeid(AndQuery))
		cout << "pd2的动态类型是AndQuery" << endl;
	else
		cout << "pd2的动态类型并非是AndQuery" << endl;
}
int main()
{
	cast_test();
	system("pause");
	return 0;
}

19.9
#include 
#include 
#include 
class Sales_data {};
class Base {
public:
	virtual ~Base() {}
};
class Derived:public Base {};
std::ostream &operator<<(std::ostream &os, const type_info &t) {
	if (t == typeid(int))
		os << "int";
	else if (t == typeid(int[10]))
		os << "int[10]";
	else if (t == typeid(std::string))
		os << "std::string";
	else if (t == typeid(Base))
		os << "class Base";
	else if (t == typeid(Base*))
		os << "class Base *";
	else if (t == typeid(Derived))
		os << "class Derived";
	else if (t == typeid(Sales_data))
		os << "class Sales_data";
	return os;
}
int main()
{
	using namespace std;
	int arr[10];
	Derived d;
	Base *p = &d;
	/*cout << typeid(42).name() << "\n" << typeid(arr).name() << "\n"
		<< typeid(Sales_data).name() << "\n" << typeid(string).name() << "\n"
		<< typeid(p).name() << "\n" << typeid(*p).name() << endl;*/
	cout << typeid(42) << "\n" << typeid(arr) << "\n"
		<< typeid(Sales_data) << "\n" << typeid(string) << "\n"
		<< typeid(p) << "\n" << typeid(*p) << endl;

	system("pause");
	return 0;
}

19.10
a、class A* 指针类型

b、class A* 引用类型

c、class B 引用指向的类型

19.11

普通指针用实际存在对象或变量的地址进行初始化,指向一个实际存在的对象或变量

成员指针指向类的成员(不是该类对象的成员)

19.12

//Screen.h
#pragma once
#include 
class Screen {
	typedef std::string::size_type pos;
	pos cursor = 0;
	pos height = 0, width = 0;
	std::string contents;
public:
	static const pos Screen::*data() {//19.12
		return &Screen::cursor;
	}
	Screen() = default;
	Screen(pos ht, pos wd, char c) : height(ht), width(wd), contents(ht * wd, c) {}
	char get() const { return contents[cursor]; }
	char get_cursor() const { return contents[cursor]; }
	inline char get(pos ht, pos wd) const;
	Screen &move(pos r, pos c);

};
char Screen::get(pos r, pos c) const
{
	pos row = r * width;
	return contents[row + c];
}
Screen& Screen::move(pos r, pos c)
{
	pos row = r * width;
	cursor = row + c;
	return *this;
}

//main.h
#include "Screen.h"
#include 

int main()
{
	using namespace std;
	const size_t Screen::*pc = Screen::data();
	Screen s(10,10,'-');
	s.move(5, 2);
	cout << s.*pc;
	system("pause");
	return 0;
}

19.13

//Sales_data.h
#pragma once

#include 
#include 
#include  
#include  
class Sales_data {

	friend std::ostream &operator<<(std::ostream&, const Sales_data&);

	friend std::istream &operator>>(std::istream&, Sales_data&);

	friend Sales_data operator+(const Sales_data&, const Sales_data&);

	friend bool operator==(const Sales_data&, const Sales_data&);
	friend bool operator!=(const Sales_data&, const Sales_data&);

	friend Sales_data operator+(const Sales_data&, const Sales_data&);

public:



	Sales_data() = default;
	Sales_data(const std::string &s) : bookNo(s) {}
	Sales_data(const std::string &s, unsigned n, double p) :
		bookNo(s), units_sold(n), revenue(p*n) {}
	explicit Sales_data(std::istream &is) { is >> *this; }

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

	Sales_data& operator+=(const Sales_data&);

	Sales_data& operator=(const std::string&);
	//19.13
	static const std::string Sales_data::* data()
	{
		return &Sales_data::bookNo;
	}
private:
	std::string bookNo;
	unsigned units_sold = 0;
	double revenue = 0.0;
	double avg_price() const;
};

inline
Sales_data& Sales_data::operator+=(const Sales_data& rhs)
{
	units_sold += rhs.units_sold;
	revenue += rhs.revenue;
	return *this;
}
inline
Sales_data& Sales_data::operator=(const std::string &isbn)
{
	bookNo = isbn;
	return *this;
}

inline double Sales_data::avg_price() const
{
	if (units_sold != 0)
		return revenue / units_sold;
	else
		return revenue;
}

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

inline
std::istream& operator>>(std::istream &is, Sales_data& item)
{
	double price = 0;
	is >> item.bookNo >> item.units_sold >> price;
	if (is) 
		item.revenue = item.units_sold * price;
	else
		item = Sales_data();
	return is;
}
inline
bool operator==(const Sales_data &lhs, const Sales_data &rhs)
{
	return lhs.bookNo == rhs.bookNo &&
		lhs.units_sold == rhs.units_sold &&
		lhs.revenue == rhs.revenue;
}
inline
bool operator!=(const Sales_data &lhs, const Sales_data &rhs)
{
	return !(lhs == rhs);
}
inline
Sales_data operator+(const Sales_data &lhs, const Sales_data &rhs)
{
	Sales_data sum = lhs;
	sum += rhs;
	return sum;
}

//main.cpp
#include "Sales_data.h"

int main()
{
	using namespace std;
	const string Sales_data::*pb=Sales_data::data();
	Sales_data books("c++ primer");
	cout << books.*pb;
	system("pause");
	return 0;
}

19.14

合法、

当auto pmf=&Screen::get_cursor;时,pmf是char (Screen::*pmf)();指向Screen一个返回值是char、形参为空的成员函数

而Screen::get有一个版本符合:返回值为char、形参为空,所以可以把pmf指针指向该成员函数

19.15

函数指针:函数指针的声明包括函数的形参类型、顺序、返回值,只能把返回值与形参列表都相匹配的函数地址赋给函数指针

如,指向一个int max(int i,int a);的函数指针:int (*pfun)(int,int);

赋值:pfun=max;

成员函数指针:与函数指针一样,需要指定返回值、顺序、形参列表,但需要使用 classname::*的形式声明指向那个类的成员函数

如,指向class A的void print(ostream &os)const;的成员函数指针:void (A::*pout)(ostream&)const;

赋值:pout=&A::print;需要显示的使用取地址运算符

19.16

//Sales_data
#pragma once

#include 
#include 
#include  
#include  
class Sales_data {

	friend std::ostream &operator<<(std::ostream&, const Sales_data&);

	friend std::istream &operator>>(std::istream&, Sales_data&);

	friend Sales_data operator+(const Sales_data&, const Sales_data&);

	friend bool operator==(const Sales_data&, const Sales_data&);
	friend bool operator!=(const Sales_data&, const Sales_data&);

	friend Sales_data operator+(const Sales_data&, const Sales_data&);

public:
	//19.16
	using Avg = double (Sales_data::*)() const;
	friend void text(Sales_data &s);//19.16
	Sales_data() = default;
	Sales_data(const std::string &s) : bookNo(s) {}
	Sales_data(const std::string &s, unsigned n, double p) :
		bookNo(s), units_sold(n), revenue(p*n) {}
	explicit Sales_data(std::istream &is) { is >> *this; }

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

	Sales_data& operator+=(const Sales_data&);

	Sales_data& operator=(const std::string&);
	//19.13
	static const std::string Sales_data::* data()
	{
		return &Sales_data::bookNo;
	}
private:
	std::string bookNo;
	unsigned units_sold = 0;
	double revenue = 0.0;
	double avg_price() const;
};

inline
Sales_data& Sales_data::operator+=(const Sales_data& rhs)
{
	units_sold += rhs.units_sold;
	revenue += rhs.revenue;
	return *this;
}
inline
Sales_data& Sales_data::operator=(const std::string &isbn)
{
	bookNo = isbn;
	return *this;
}

inline double Sales_data::avg_price() const
{
	if (units_sold != 0)
		return revenue / units_sold;
	else
		return revenue;
}

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

inline
std::istream& operator>>(std::istream &is, Sales_data& item)
{
	double price = 0;
	is >> item.bookNo >> item.units_sold >> price;
	if (is) 
		item.revenue = item.units_sold * price;
	else
		item = Sales_data();
	return is;
}
inline
bool operator==(const Sales_data &lhs, const Sales_data &rhs)
{
	return lhs.bookNo == rhs.bookNo &&
		lhs.units_sold == rhs.units_sold &&
		lhs.revenue == rhs.revenue;
}
inline
bool operator!=(const Sales_data &lhs, const Sales_data &rhs)
{
	return !(lhs == rhs);
}
inline
Sales_data operator+(const Sales_data &lhs, const Sales_data &rhs)
{
	Sales_data sum = lhs;
	sum += rhs;
	return sum;
}

//main.cpp
#include "Sales_data.h"
#include 
void text(Sales_data &s)
{
	Sales_data::Avg fun = &Sales_data::avg_price;
	std::cout << (s.*fun)();
}

int main()
{
	using namespace std;


	system("pause");
	return 0;
}

19.17

Screen的公有成员函数只有:

	char get() const { return contents[cursor]; }//using Action_c_v = char (Screen::*)()const;
	char get_cursor() const { return contents[cursor]; }//同上
	inline char get(pos ht, pos wd) const;//using Action_c_uu = char (Screen::*)(pos,pos)const;
	Screen &move(pos r, pos c);//using Action_Screen_uu = Screen &(Screen::*)(pos,pos);

19.18
#include 
#include 
#include 
#include 
#include 
int main()
{
	using namespace std;

	vector svec;
	svec.push_back("");
	svec.push_back("c++");
	svec.push_back("primer");
	svec.push_back("hello");
	svec.push_back("");
	svec.push_back("");
	svec.push_back("wrodl");
	/*function func = &string::empty;
	int a = count_if(svec.begin(), svec.end(), func);*/

	//int a = count_if(svec.begin(), svec.end(), mem_fn(&string::empty));

	int a = count_if(svec.begin(), svec.end(), bind(&string::empty,std::placeholders::_1));
	cout << a;
	system("pause");
	cin >> a;
	return 0;
}

19.19
#pragma once

#include 
#include 
#include  
#include  
class Sales_data {

	friend std::ostream &operator<<(std::ostream&, const Sales_data&);

	friend std::istream &operator>>(std::istream&, Sales_data&);

	friend Sales_data operator+(const Sales_data&, const Sales_data&);

	friend bool operator==(const Sales_data&, const Sales_data&);
	friend bool operator!=(const Sales_data&, const Sales_data&);

	friend Sales_data operator+(const Sales_data&, const Sales_data&);

public:
	//19.16
	using Avg = double (Sales_data::*)() const;
	friend void text(Sales_data &s);//19.16
	//19.19
	friend std::vector::const_iterator count(const std::vector &vec, double d);

	Sales_data() = default;
	Sales_data(const std::string &s) : bookNo(s) {}
	Sales_data(const std::string &s, unsigned n, double p) :
		bookNo(s), units_sold(n), revenue(p*n) {}
	explicit Sales_data(std::istream &is) { is >> *this; }

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

	Sales_data& operator+=(const Sales_data&);

	Sales_data& operator=(const std::string&);
	//19.13
	static const std::string Sales_data::* data()
	{
		return &Sales_data::bookNo;
	}
private:
	std::string bookNo;
	unsigned units_sold = 0;
	double revenue = 0.0;
	double avg_price() const;
};

inline
Sales_data& Sales_data::operator+=(const Sales_data& rhs)
{
	units_sold += rhs.units_sold;
	revenue += rhs.revenue;
	return *this;
}
inline
Sales_data& Sales_data::operator=(const std::string &isbn)
{
	bookNo = isbn;
	return *this;
}

inline double Sales_data::avg_price() const
{
	if (units_sold != 0)
		return revenue / units_sold;
	else
		return revenue;
}

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

inline
std::istream& operator>>(std::istream &is, Sales_data& item)
{
	double price = 0;
	is >> item.bookNo >> item.units_sold >> price;
	if (is) 
		item.revenue = item.units_sold * price;
	else
		item = Sales_data();
	return is;
}
inline
bool operator==(const Sales_data &lhs, const Sales_data &rhs)
{
	return lhs.bookNo == rhs.bookNo &&
		lhs.units_sold == rhs.units_sold &&
		lhs.revenue == rhs.revenue;
}
inline
bool operator!=(const Sales_data &lhs, const Sales_data &rhs)
{
	return !(lhs == rhs);
}
inline
Sales_data operator+(const Sales_data &lhs, const Sales_data &rhs)
{
	Sales_data sum = lhs;
	sum += rhs;
	return sum;
}

#include 
#include "Sales_data.h"
#include 
#include 
std::vector::const_iterator count(const std::vector &vec, double d) {
	auto fun = std::bind(&Sales_data::avg_price, std::placeholders::_1);
	return find_if(vec.cbegin(), vec.cend(), [&](const Sales_data &s) { return d < fun(s); });
}

int main()
{
	using namespace std;
	vector sv;
	sv.push_back(Sales_data("b1", 13, 36.4));
	sv.push_back(Sales_data("b2", 32, 24.2));
	sv.push_back(Sales_data("b3", 77, 82));
	sv.push_back(Sales_data("b4", 21, 15.7));
	sv.push_back(Sales_data("b5", 25, 35));
	sv.push_back(Sales_data("b6", 42, 75));
	sv.push_back(Sales_data("b7", 63, 55.5));
	sv.push_back(Sales_data("b8", 43, 25));
	sv.push_back(Sales_data("b9", 68, 34));
	sv.push_back(Sales_data("b0", 44, 43.1));
	
	cout << *count(sv, 50);

	system("pause");
	return 0;
}

19.20
#pragma once
#include   
#include   
#include   
#include     //istringstream  
//#include  //find  
#include   
#include  
#include   
#include  //shared_ptr  
#include   

class TextQuery
{
	std::vector str; //把文件每一行都保存到string中  
	std::map::size_type>> line;    //保存单词对应的行号 相当于map> line;  
	std::string isword(std::string s)
	{
		s[0] = tolower(s[0]);
		if (!isalnum(s[s.size() - 1]))
			s = std::string(s.begin(), s.end() - 1);
		return s;
	}
public:
	class QueryResult;//19.20
	TextQuery(std::ifstream &in)
	{
		if (!in)
		{
			std::cerr << "open file error in class";
			exit(1);
		}
		std::string temp;
		while (std::getline(in, temp))
		{
			str.push_back(temp);
			std::istringstream instr(temp);
			std::string t;
			while (instr >> t)
				line[isword(t)].insert(str.size() - 1);
		}
	}
	QueryResult query(const std::string &s);
};
class TextQuery::QueryResult
{
public:
	std::string word;
	std::map::size_type, std::string> mw;
	friend std::ostream &print(std::ostream &os, const QueryResult &qr);
	QueryResult() {}
};

TextQuery::QueryResult TextQuery::query(const std::string &s)
{
	QueryResult qr;
	if (line.find(s) == line.cend())
	{
		std::cout << "not word\n";
		return qr;
	}
	qr.word = s;
	for (auto &x : line[s])
		qr.mw[x] = str[x];
	return qr;
}

#include "head.h"
std::ostream &print(std::ostream &os, const TextQuery::QueryResult &qr)
{
	os << qr.word << " occurs " << qr.mw.size() << " times" << std::endl;
	for (auto &x : qr.mw)
		os << "(line " << x.first + 1 << ") " << x.second << std::endl;
	return os;
}

void runQuerues(std::ifstream &in)
{
	TextQuery tq(in);
	while (1)
	{
		std::cout << "enter word to look for,or q to quit: ";
		std::string s;
		if (!(std::cin >> s) || s == "q")
			break;
		print(std::cout, tq.query(s)) << std::endl;
	}
}
int main(int argc, char **argv)
{
	using namespace std;
	ifstream infile(argv[1]);
	runQuerues(infile);
	return 0;
}

19.21、19.22、19.23、19.25

//Sales_data.h
#pragma once
#include 
#include 
class Sales_data {
	friend std::ostream &operator<<(std::ostream&, const Sales_data&);
	friend std::istream &operator>>(std::istream&, Sales_data&);
	friend Sales_data operator+(const Sales_data&, const Sales_data&);
	friend bool operator==(const Sales_data&, const Sales_data&);
	friend bool operator!=(const Sales_data&, const Sales_data&);
	friend Sales_data operator+(const Sales_data&, const Sales_data&);
public:
	Sales_data() = default;
	Sales_data(const std::string &s) : bookNo(s) {}
	Sales_data(const std::string &s, unsigned n, double p) :
		bookNo(s), units_sold(n), revenue(p*n) {}
	explicit Sales_data(std::istream &is) { is >> *this; }
	std::string isbn() const { return bookNo; }
	Sales_data& operator+=(const Sales_data&);
	Sales_data& operator=(const std::string&);
private:
	std::string bookNo;
	unsigned units_sold = 0;
	double revenue = 0.0;
	double avg_price() const;
};

inline
Sales_data& Sales_data::operator+=(const Sales_data& rhs)
{
	units_sold += rhs.units_sold;
	revenue += rhs.revenue;
	return *this;
}
inline
Sales_data& Sales_data::operator=(const std::string &isbn)
{
	bookNo = isbn;
	return *this;
}

inline double Sales_data::avg_price() const
{
	if (units_sold != 0)
		return revenue / units_sold;
	else
		return revenue;
}

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

inline
std::istream& operator>>(std::istream &is, Sales_data& item)
{
	double price = 0;
	is >> item.bookNo >> item.units_sold >> price;
	if (is)
		item.revenue = item.units_sold * price;
	else
		item = Sales_data();
	return is;
}
inline
bool operator==(const Sales_data &lhs, const Sales_data &rhs)
{
	return lhs.bookNo == rhs.bookNo &&
		lhs.units_sold == rhs.units_sold &&
		lhs.revenue == rhs.revenue;
}
inline
bool operator!=(const Sales_data &lhs, const Sales_data &rhs)
{
	return !(lhs == rhs);
}
inline
Sales_data operator+(const Sales_data &lhs, const Sales_data &rhs)
{
	Sales_data sum = lhs;
	sum += rhs;
	return sum;
}

//Token.h
#pragma once
#include 
#include 
#include 
#include "Sales_data.h"
class Token//19.21
{
	enum { INT, CHAR, DBL, STR, SALES/*19.22*/ }tok;
	union {
		char cval;
		int ival;
		double dval;
		std::string sval;
		Sales_data sdval;//19.22
	};
	void copyUnion(const Token &t) {
		switch (t.tok) {
		case INT: ival = t.ival;
			break;
		case CHAR:cval = t.cval;
			break;
		case DBL:dval = t.dval;
			break;
		case STR:new(&sval) std::string(t.sval);
			break;
		case SALES:new(&sdval) Sales_data(t.sdval);//19.22
			break;
		}
	}
	void moveUnion(Token &&t) {//19.23
		switch (t.tok) {
		case INT:
			ival = std::move(t.ival);
			break;
		case CHAR:
			cval = std::move(t.cval);
			break;
		case DBL:
			dval = std::move(t.dval);
			break;
		case STR:
			new(&sval) std::string(std::move(t.sval));
			break;
		case SALES:
			new(&sdval) Sales_data(std::move(t.sdval));
			break;
		}
	}
	void free() {
		if (tok == STR)
			sval.std::string::~string();
		if (tok == SALES)
			sdval.~Sales_data();
	}
public:
	Token() :tok(INT), ival{ 0 } {};
	Token(const Token &t) :tok(t.tok) { copyUnion(t); }
	Token(Token &&t) :tok(std::move(t.tok)) {//19.23
		moveUnion(std::move(t));
	}
	Token &operator=(Token &&t){//19.23
		if(this != &t) {
			free();
			moveUnion(std::move(t));
			tok = std::move(t.tok);
		}
		return *this;
	}

	Token &operator=(const Token &t) {
		if (tok == STR&&t.tok != STR)sval.std::string::~string();
		if (tok == SALES&&t.tok != SALES)sdval.~Sales_data();
		if (tok == STR&&t.tok == STR)
			sval = t.sval;
		else if (tok == SALES&&t.tok == SALES)
			sdval = t.sdval;
		else
			copyUnion(t);
		tok = t.tok;
		return *this;
	}
	~Token() {
		if (tok == STR)
			sval.std::string::~string();
		if (tok == SALES)
			sdval.~Sales_data();
	}
	Token &operator=(const std::string &s) {
		free();
		new(&sval) std::string(s);
		tok = STR;
		return *this;
	}
	Token &operator=(char c) {
		free();
		cval = c;
		tok = CHAR;
		return *this;
	}
	Token &operator=(int i) {
		free();
		ival = i;
		tok = INT;
		return *this;
	}
	Token &operator=(double d) {
		free();
		dval = d;
		tok = DBL;
		return *this;
	}
	Token &operator=(Sales_data &s) {
		free();
		new(&sdval) Sales_data(s);
		tok = SALES;
		return *this;
	}
	friend std::ostream &operator<<(std::ostream &os, const Token &t) {
		switch (t.tok) {
		case Token::INT: os << t.ival; break;
		case Token::CHAR: os << t.cval; break;
		case Token::DBL: os << t.dval; break;
		case Token::STR: os << t.sval; break;
		case Token::SALES: os << t.sdval; break;
		}
		return os;
	}

};

//main.cpp
#include 
#include 
#include "Token.h"
int main()
{
	using namespace std;
	string s = "string";
	Sales_data item("c++ primer 5", 12, 128.0);
	int i = 12;
	char c = 'c';
	double d = 1.28;
	Token t;
	t = i;
	cout << t << "\t";
	t = c;
	cout << t << "\t";
	t = d;
	cout << t << "\t";
	t = s;
	cout << t << "\t";
	t = item;
	cout << t << endl;
	Token t2 = t;
	cout << t2 << "\t";
	t2 = s;
	cout << t2 << "\t";
	t2 = t;
	cout << t2 << "\t";
	t2 = c;
	cout << t2 << "\t";
	t = s;
	t2 = std::move(t);
	cout << t2 << endl;
	Token t3 = std::move(t2);
	cout << t3 << "\t";
	t3 = t3;
	cout << t3 << "\t";
	t3 = item;
	cout << t3 << endl;
	t2 = std::move(t3);
	cout << t2 << endl;
	system("pause");
	return 0;
}

19.24

没情况,因为成员都有自己的赋值构造函数,如果tok为string时,t=t将调用string的赋值构造

Sales_data同理,所以才定义了Sales_data &operator=(ostream&,const Sales_data&);

19.26

错误,c语言的方式不支持函数重载

2016年5月1日00:00:47