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

19.1

#include <iostream>
#include <cstdlib>

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 <iostream>
#include <string>
#include <memory>	//allocator
#include <utility>	//move
#include <initializer_list>
#include <algorithm>	//for_each
class StrVec
{
	std::allocator<std::string> alloc;//为所有StrVec对象分配内存用
	void chk_n_alloc()		//如果剩余空间为0就分配新空间
	{
		if (size() == capacity())
			reallocate();
	}
	std::pair<std::string *, std::string *> 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<std::string> 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<std::string *, std::string *> 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<string *,string *>
}
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<std::string> 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 <cstdlib>

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 <iostream>
#include <typeinfo>
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<B*>(pa))//a)   T
		cout << "a)	T" << endl;
	else
		cout << "a)	F" << endl;
	B *pbb = new B;
	if (C *pc = dynamic_cast<C*>(pbb))//b)   F:pbb指向的对象不包含C对象,返回0
		cout << "b)	T" << endl;
	else
		cout << "b)	F" << endl;
	A *paa = new D;
	if (B *pbbb = dynamic_cast<B*>(paa))//c)   T
		cout << "c)	T" << endl;
	else
		cout << "c)	F" << endl;


	try {
		C &cp = dynamic_cast<C&>(*pa);//正确,*pa的类型是C
		cout << "cp" << endl;
		C &ccp = dynamic_cast<C&>(*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<B*>(a);
  b.print();
}
...
int main(){
  B b;
  A *a=&b;
  f(a);
  

}

19.6、19.7、19.8

//TextQuery.h
#pragma once
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <memory>
std::string make_plural(size_t, const std::string&, const std::string&);
class QueryResult;
class TextQuery {
public:
	using line_no = std::vector<std::string>::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<line_no>);
				lines->insert(n);
			}
		}
	}
	QueryResult query(const std::string &sought) const;
private:
	std::shared_ptr<std::vector<std::string>> file;
	std::map<std::string, std::shared_ptr<std::set<line_no>>> 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<std::set<TextQuery::line_no>> p, std::shared_ptr<std::vector<std::string>> f) :sought(s), lines(p), file(f) {}
	std::set<TextQuery::line_no>::iterator begin() const { return lines->begin(); }
	std::set<TextQuery::line_no>::iterator end() const { return lines->end(); }
	std::shared_ptr<std::vector<std::string>> get_file() const { return file; }
private:
	std::string sought;
	std::shared_ptr<std::set<TextQuery::line_no>> lines;
	std::shared_ptr<std::vector<std::string>> file;
};

QueryResult TextQuery::query(const std::string &sought) const
{
	static std::shared_ptr<std::set<line_no>> nodata(new std::set<line_no>);
	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 <cstddef>
#include <string>
#include <utility>
#include <algorithm>
#include <iterator>
#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<std::set<line_no>>(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<line_no>>();
		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<std::set<line_no>>();
		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 <iostream>
#include <typeinfo>
#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<AndQuery*>(pb1)) {
		cout << "成功" << endl;
	}
	else {
		cout << "失败" << endl;
	}
	if (AndQuery *pa2 = dynamic_cast<AndQuery*>(pb2)) {
		cout << "成功" << endl;
	}
	else {
		cout << "失败" << endl;
	}
	//19.7
	try {
		AndQuery &ra1 = dynamic_cast<AndQuery&>(*pb1);
		cout << "成功" << endl;
	}
	catch (bad_cast e) {
		cout << e.what() << endl;
	}
	try {
		AndQuery &ra2 = dynamic_cast<AndQuery&>(*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 <iostream>
#include <string>
#include <typeinfo>
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 <string>
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 <iostream>

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 <iostream>
#include <string>
#include <cstddef> 
#include <vector> 
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 <iostream>
#include <string>
#include <cstddef> 
#include <vector> 
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 <iostream>
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 <iostream>
#include <string>
#include <functional>
#include <vector>
#include <algorithm>
int main()
{
	using namespace std;

	vector<string> 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<bool(const string &)> 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 <iostream>
#include <string>
#include <cstddef> 
#include <vector> 
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<Sales_data>::const_iterator count(const std::vector<Sales_data> &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 <iostream>
#include "Sales_data.h"
#include <functional>
#include <algorithm>
std::vector<Sales_data>::const_iterator count(const std::vector<Sales_data> &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<Sales_data> 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 <iostream>  
#include <string>  
#include <fstream>  
#include <sstream>    //istringstream  
//#include <iterator> //find  
#include <vector>  
#include <map>  
#include <set>  
#include <memory> //shared_ptr  
#include <cctype>  

class TextQuery
{
	std::vector<std::string> str; //把文件每一行都保存到string中  
	std::map<std::string, std::set<std::vector<std::string>::size_type>> line;    //保存单词对应的行号 相当于map<string,set<unsigned>> 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<std::vector<std::string>::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 <iostream>
#include <string>
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 <iostream>
#include <string>
#include <utility>
#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 <iostream>
#include <string>
#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





































































































评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值