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