程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> c++primer第五版第十九章練習

c++primer第五版第十九章練習

編輯:關於C++

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

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved