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