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

时间: 2024-11-03 05:43:00

c++primer第五版第十九章练习的相关文章

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

16.1 根据模板参数的类型实例化出一个该类型的函数 16.2 #include <iostream> #include <string> #include <functional> //less //#include "../../7.21/7.21/标头.h" template<typename T> int compare(const T &a, const T &b) { if (std::less<T>

C++Primer第五版习题解答---第一章

C++Primer第五版习题解答---第一章 ps:答案是个人在学习过程中书写,可能存在错漏之处,仅作参考. 作者:cosefy Date: 2022/1/7 第一章:开始 练习1.3 #include<iostream> int main() { std::cout << "hello, world" << std::endl; return 0; } 练习1.4: #include<iostream> int main() { int

C++ Primer 第五版:第1 章

*****C++ Primer 第五版第1章学习笔记***** *****实验代码在Red Hat 6.6或VS 2013中调试***** *****文章内容依据当前知识撰写,存在认识的局限性***** 1.1 编写一个简单的C++程序 函数:依据我个人理解,C/C++的函数是一个能够完成一个功能的模块. 完整函数的组成: ①返回类型:不一定有返回值,故不一定有返回类型 ②函数名:根据名字标识完成特定功能的模块,必须存在 ③形参列表:可能没有参数传入,不一定存在 ④函数体:一个完整的函数应该是有

C++ Primer 第五版:第2章

*****C++ Primer 第五版第2章学习笔记***** *****实验代码在Red Hat 6.6或VS 2013中调试***** *****文章内容依据当前知识撰写,存在认识的局限性***** 今天学习C++ Primer 的第2章,还没有看完,先写一点看书的心得和笔记. 对象类型决定对象包含的数据和能参与的运算操作,同时还决定了存储空间大小.算术表达式中不要使用char,因为不同机器实现不一样,导致结果不同.单精度计算不一定比双精度快. C++类型不匹配时,是自动进行类型的转换. C

C#高级编程第11版 - 第十九章

导航 C# 全版本特性一览 全书目录 第十九章 Libraries, Assemblies, Packages and NuGet 19.1 库的地狱 423 19.2 程序集 425 19.3 创建库 426 19.3.1 .NET 标准 427 19.3.2 创建.NET 标准库 428 19.3.3 解决方案文件 428 19.3.4 引用项目 429 19.3.5 引用NuGet 包 429 19.3.6 NuGet 的来源 430 19.3.7 使用.NET Framework 库 4

c++ Primer 第五版习题答案第二章

练习2.1 Q: 类型int.long.long long和short的区别是什么,无符号和带符号类型的区别是什么?float和double的区别是什么? A:int. long. long long和short尺寸不同,表示的数据范围不同.无符号只能表示0和正数,无符号还可以表示负数.float为单精度浮点数,double为双精度,一般来说,float占4字节,double占8字节. 练习2.2 Q: 计算按揭贷款时,对于利率.本金和付款分别应选择何种数据类型?说明你的理由. A: 利率应该用

C++ Primer 第五版学习笔记

<C++ Primer>第五版中文版学习笔记 ? C++ Primer 第五版学习笔记

《C++ Primer 第五版》练习9.51参考答案

//Date.h #include <map> #include <string> #include <vector> using namespace std; struct Date {         explicit Date(const string & info){//检测输入格式,尝试初始化,若失败则进行errorInit             if(mymap.empty()){               initMap();         

C++ Primer(第五版)学习笔记_9_标准模板库_multimap多重映照容器

C++ Primer(第五版)学习笔记_9_标准模板库_multimap多重映照容器 多重映照容器multimap与map结构基本相同,但由于重复键值存在,所以multimap的元素插入.删除.查找都与map的方法不相同. 1.multimap对象创建.元素插入 插入元素时,需要使用insert()方法和类似pair<string,double>("Jack", 300.5)的元素结构.可以看到,重复的元素是按照插入的先后顺序排序的. #include <iostre