欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

c++ primer(第五版)学习笔记及习题答案代码版(第十四章)重载运算与类型转换

程序员文章站 2022-05-09 18:26:27
笔记较为零散,都是自己不熟悉的知识点。 习题答案至于一个.h 和.cc 中,需要演示某一题直接修改 #define NUM****, 如运行14.30题为#define NUM1...
笔记较为零散,都是自己不熟悉的知识点。

习题答案至于一个.h 和.cc 中,需要演示某一题直接修改 #define NUM****, 如运行14.30题为#define NUM1430;

Alice Emma has long flowing red hair. 
Her Daddy says when the wind blows 
through her hair, it looks almost alive, 
like a fiery bird in flight. 
A beautiful fiery bird, he tells her, 
magical but untamed. 
"Daddy, shush, there is no such thing," 
she tells him, at the same time wanting 
him to tell her more.
Shyly, she asks, "I mean, Daddy, is there?"
//Chapter14.h
#ifndef CHAPTER_10_H
#define CHAPTER_10_H

#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;

//14.2
class Sales_data {
    friend istream& operator>>(istream&, Sales_data&);       // input
    friend ostream& operator<<(ostream&, const Sales_data&); // output
    friend Sales_data operator+(const Sales_data&, const Sales_data&); // addition
public:
    Sales_data(const string& s, unsigned n, double p)
        : bookNo(s), units_sold(n), revenue(n * p)  {  }
    Sales_data() : Sales_data("", 0, 0.0f) {}
    Sales_data(const string& s) : Sales_data(s, 0, 0.0f) {}
    Sales_data(istream& is);

    Sales_data& operator=(const string&);                 //14.22
    Sales_data& operator+=(const Sales_data&); // compound-assignment
    string isbn() const { return bookNo; }
 
    explicit operator string() const { return bookNo; }       //14.45
    explicit operator double() const { return avg_price(); }       //14.45
private:
    inline double avg_price() const;

    string bookNo;
    unsigned units_sold = 0;
    double revenue = 0.0;
};

istream& operator>>(istream&, Sales_data&);
ostream& operator<<(ostream&, const Sales_data&);
Sales_data operator+(const Sales_data&, const Sales_data&);

inline double Sales_data::avg_price() const{
    return units_sold ? revenue / units_sold : 0;
}

Sales_data::Sales_data(istream& is) : Sales_data(){
    is >> *this;
}

Sales_data& Sales_data::operator+=(const Sales_data& rhs){
    units_sold += rhs.units_sold;
    revenue += rhs.revenue;
    return *this;
}

istream& operator>>(istream& is, Sales_data& item){
    double price = 0.0;
    is >> item.bookNo >> item.units_sold >> price;
    if (is)
        item.revenue = price * item.units_sold;
    else
        item = Sales_data();
    return is;
}
/*
istream&operator>>(istream& in, Sales_data& s)   //14.11
{
	double price;
	in >> s.bookNo>> s.units_sold>> price;
	s.revenue = s.units_sold * price;
	return in;
}
*/
ostream& operator<<(ostream& os, const Sales_data& item){
    os << item.isbn() << " " << item.units_sold << " " << item.revenue << " "
       << item.avg_price();
    return os;
}

Sales_data operator+(const Sales_data& lhs, const Sales_data& rhs){
    Sales_data sum = lhs;
    sum += rhs;
    return sum;
}

Sales_data& Sales_data::operator=(const string& isbn){     //14.22
    *this = Sales_data(isbn);
    return *this;
}

//14.5
class Book {  
	friend istream& operator>>(istream&, Book&);       // input
    friend ostream& operator<<(ostream&, const Book&); // output
    friend bool operator==(const Book&, const Book&);
    friend bool operator!=(const Book&, const Book&);
    friend bool operator<(const Book&, const Book&);
    friend bool operator>(const Book&, const Book&);
    friend Book operator+(const Book&, const Book&);
public:  
    Book() = default;  
    Book(unsigned no, string name, string author, string pubdate):no_(no), name_(name), author_(author), pubdate_(pubdate) { }  
    Book(istream &in) { in >> no_ >> name_ >> author_ >> pubdate_; }  
	Book& operator+=(const Book&);
private:  
    unsigned no_;  
    string name_;  
    string author_;  
    string pubdate_;  
    unsigned number_;
};  

istream& operator>>(istream&, Book&);       // input
ostream& operator<<(ostream&, const Book&); // output
bool operator==(const Book&, const Book&);
bool operator!=(const Book&, const Book&);
bool operator<(const Book&, const Book&);
bool operator>(const Book&, const Book&);
Book operator+(const Book&, const Book&);


istream& operator>>(istream& in, Book& book){
    in >> book.no_ >> book.name_ >> book.author_ >> book.pubdate_ >>
        book.number_;
    if (!in) book = Book();
    return in;
}

ostream& operator<<(ostream& out, const Book& book){
    out << book.no_ << " " << book.name_ << " " << book.author_ << " "
        << book.pubdate_ << " " << book.number_ << endl;
    return out;
}

bool operator==(const Book& lhs, const Book& rhs){
    return lhs.no_ == rhs.no_;
}

bool operator!=(const Book& lhs, const Book& rhs){
    return !(lhs == rhs);
}

bool operator<(const Book& lhs, const Book& rhs){
    return lhs.no_ < rhs.no_;
}

bool operator>(const Book& lhs, const Book& rhs){
    return rhs < lhs;
}

Book& Book::operator+=(const Book& rhs){
    if (rhs == *this) this->number_ += rhs.number_;
    return *this;
}

Book operator+(const Book& lhs, const Book& rhs){
    Book book = lhs;
    book += rhs;
    return book;
}

//14.7
class String {
    friend ostream& operator<<(ostream&, const String&);
    friend istream& operator>>(istream&, String&);
    friend bool operator==(const String&, const String&);
    friend bool operator!=(const String&, const String&);
    friend bool operator<(const String&, const String&);
    friend bool operator>(const String&, const String&);
    friend bool operator<=(const String&, const String&);
    friend bool operator>=(const String&, const String&);
public:
    String() : String("") {}
    String(const char*);
    String(const String&);
    String& operator=(const String&);
    String(String&&) noexcept;
    String& operator=(String&&) noexcept;
    ~String();

    void push_back(const char);

    char* begin() const { return elements; }
    char* end() const { return last_elem; }

    char& operator[](size_t n) { return elements[n]; }               //14.26
    const char& operator[](size_t n) const { return elements[n]; }   //14.26

    const char* c_str() const { return elements; }
    size_t size() const { return last_elem - elements; }
    size_t length() const { return size(); }
    size_t capacity() const { return cap - elements; }

    void reserve(size_t);
    void resize(size_t);
    void resize(size_t, char);
private:
    pair alloc_n_copy(const char*, const char*);
    void range_initializer(const char*, const char*);
    void free();
    void reallocate();
    void alloc_n_move(size_t new_cap);
    void chk_n_alloc()    {
        if (first_free == cap) reallocate();
    }
private:
    char* elements;
    char* last_elem;
    char* first_free;
    char* cap;
    allocator alloc;
};

ostream& operator<<(ostream&, const String&);
istream& operator>>(istream&, String&);
bool operator==(const String&, const String&);
bool operator!=(const String&, const String&);
bool operator<(const String&, const String&);
bool operator>(const String&, const String&);
bool operator<=(const String&, const String&);
bool operator>=(const String&, const String&);

ostream& operator<<(ostream& os, const String& lhs){
    os << lhs.c_str();
    return os;
}

istream& operator>>(istream& is, String& rhs){
    for (char c; (c = is.get()) != '\n';) {
        rhs.push_back(c);
    }
    return is;
}

bool operator==(const String& lhs, const String& rhs){
    return (lhs.size() == rhs.size() &&
            equal(lhs.begin(), lhs.end(), rhs.begin()));
}

bool operator!=(const String& lhs, const String& rhs){
    return !(lhs == rhs);
}

bool operator<(const String& lhs, const String& rhs){
    return lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(),
                                        rhs.end());
}

bool operator>(const String& lhs, const String& rhs){
    return rhs < lhs;
}

bool operator<=(const String& lhs, const String& rhs){
    return !(rhs < lhs);
}

bool operator>=(const String& lhs, const String& rhs){
    return !(lhs < rhs);
}

String::String(const char* s){
    char* sl = const_cast(s);
    while (*sl) ++sl;
    range_initializer(s, ++sl);
}

String::String(const String& rhs){
    range_initializer(rhs.elements, rhs.first_free);
}

String& String::operator=(const String& rhs){
    auto newstr = alloc_n_copy(rhs.elements, rhs.first_free);
    free();
    elements = newstr.first;
    first_free = cap = newstr.second;
    last_elem = first_free - 1;
    return *this;
}

String::String(String&& s) noexcept : elements(s.elements), last_elem(s.last_elem), first_free(s.first_free),
                                      cap(s.cap){
    s.elements = s.last_elem = s.first_free = s.cap = nullptr;
}

String& String::operator=(String&& rhs) noexcept{
    if (this != &rhs) {
        free();
        elements = rhs.elements;
        last_elem = rhs.last_elem;
        first_free = rhs.first_free;
        cap = rhs.cap;
        rhs.elements = rhs.last_elem = rhs.first_free = rhs.cap = nullptr;
    }
    return *this;
}

String::~String(){
    free();
}

//===========================================================================
//
//      members
//
//===========================================================================

void String::push_back(const char c){
    chk_n_alloc();
    *last_elem = c;
    last_elem = first_free;
    alloc.construct(first_free++, '\0');
}

void String::reallocate(){
    auto newcapacity = size() ? 2 * (size() + 1) : 2;
    alloc_n_move(newcapacity);
}

void String::alloc_n_move(size_t new_cap){
    auto newdata = alloc.allocate(new_cap);
    auto dest = newdata;
    auto elem = elements;
    for (size_t i = 0; i != size() + 1; ++i)
        alloc.construct(dest++, move(*elem++));
    free();
    elements = newdata;
    last_elem = dest - 1;
    first_free = dest;
    cap = elements + new_cap;
}

void String::free(){
    if (elements) {
        for_each(elements, first_free,
                      [this](char& c) { alloc.destroy(&c); });
        alloc.deallocate(elements, cap - elements);
    }
}

pair String::alloc_n_copy(const char* b, const char* e){
    auto str = alloc.allocate(e - b);
    return {str, uninitialized_copy(b, e, str)};
}

void String::range_initializer(const char* first, const char* last){
    auto newstr = alloc_n_copy(first, last);
    elements = newstr.first;
    first_free = cap = newstr.second;
    last_elem = first_free - 1;
}

void String::reserve(size_t new_cap){
    if (new_cap <= capacity()) return;
    alloc_n_move(new_cap);
}

void String::resize(size_t count, char c){
    if (count > size()) {
        if (count > capacity()) reserve(count * 2);
        for (size_t i = size(); i != count; ++i) {
            *last_elem++ = c;
            alloc.construct(first_free++, '\0');
        }
    }
    else if (count < size()) {
        while (last_elem != elements + count) {
            --last_elem;
            alloc.destroy(--first_free);
        }
        *last_elem = '\0';
    }
}

void String::resize(size_t count){
    resize(count, ' ');
}

//14.16
class StrBlobPtr;
class ConstStrBlobPtr;

//=================================================================================
//
//      StrBlob - custom vector
//
//=================================================================================

class StrBlob {
    using size_type = vector::size_type;
    friend class ConstStrBlobPtr;
    friend class StrBlobPtr;
    friend bool operator==(const StrBlob&, const StrBlob&);
	friend bool operator!=(const StrBlob&, const StrBlob&);
	friend bool operator<(const StrBlob&, const StrBlob&);
	friend bool operator>(const StrBlob&, const StrBlob&);
	friend bool operator<=(const StrBlob&, const StrBlob&);
	friend bool operator>=(const StrBlob&, const StrBlob&);

public:
    StrBlob() : data(make_shared>()) {}
    StrBlob(initializer_list il) : data(make_shared>(il))    {
    }

    StrBlob(const StrBlob& sb) : data(make_shared>(*sb.data)) {}
    StrBlob& operator=(const StrBlob&);

    StrBlob(StrBlob&& rhs) noexcept : data(move(rhs.data)) {}
    StrBlob& operator=(StrBlob&&) noexcept;

    StrBlobPtr begin();
    StrBlobPtr end();

    ConstStrBlobPtr cbegin() const;
    ConstStrBlobPtr cend() const;

    string& operator[](size_t n);
    const string& operator[](size_t n) const;

    size_type size() const { return data->size(); }
    bool empty() const { return data->empty(); }

    void push_back(const string& t) { data->push_back(t); }
    void push_back(string&& s) { data->push_back(move(s)); }

    void pop_back();
    string& front();
    string& back();
    const string& front() const;
    const string& back() const;
private:
    void check(size_type, const string&) const;
    shared_ptr> data;
};

bool operator==(const StrBlob&, const StrBlob&);
bool operator!=(const StrBlob&, const StrBlob&);
bool operator<(const StrBlob&, const StrBlob&);
bool operator>(const StrBlob&, const StrBlob&);
bool operator<=(const StrBlob&, const StrBlob&);
bool operator>=(const StrBlob&, const StrBlob&);


inline void StrBlob::pop_back(){
    check(0, "pop_back on empty StrBlob");
    data->pop_back();
}

inline string& StrBlob::front(){
    check(0, "front on empty StrBlob");
    return data->front();
}

inline string& StrBlob::back(){
    check(0, "back on empty StrBlob");
    return data->back();
}

inline const string& StrBlob::front() const{
    check(0, "front on empty StrBlob");
    return data->front();
}

inline const string& StrBlob::back() const{
    check(0, "back on empty StrBlob");
    return data->back();
}

inline void StrBlob::check(size_type i, const string& msg) const{
    if (i >= data->size()) throw out_of_range(msg);
}
inline string& StrBlob::operator[](size_t n){
    check(n, "out of range");
    return data->at(n);
}
inline const string& StrBlob::operator[](size_t n) const{
    check(n, "out_of_range");
    return data->at(n);
}
//=================================================================================
//
//      StrBlobPtr - custom iterator of StrBlob
//
//=================================================================================

class StrBlobPtr {
    friend bool operator==(const StrBlobPtr&, const StrBlobPtr&);
	friend bool operator!=(const StrBlobPtr&, const StrBlobPtr&);
	friend bool operator<(const StrBlobPtr&, const StrBlobPtr&);
	friend bool operator>(const StrBlobPtr&, const StrBlobPtr&);
	friend bool operator<=(const StrBlobPtr&, const StrBlobPtr&);
	friend bool operator>=(const StrBlobPtr&, const StrBlobPtr&);

public:
    StrBlobPtr() : curr(0) {}
    StrBlobPtr(StrBlob& s, size_t sz = 0) : wptr(s.data), curr(sz) {}

    const string &operator*() const;       //14.30
    const string *operator->() const;
    StrBlobPtr &operator++();             //14.27
    StrBlobPtr &operator--();
    StrBlobPtr operator++(int);
    StrBlobPtr operator--(int);
    StrBlobPtr &operator+=(size_t);
    StrBlobPtr &operator-=(size_t); 
    StrBlobPtr operator+(size_t) const;     //14.28
    StrBlobPtr operator-(size_t) const;

    string& deref() const;
    StrBlobPtr& incr();
    string& operator[](size_t n);                      //14.26
    const string& operator[](size_t n) const;
private:
    shared_ptr> check(size_t, const string&) const;
    weak_ptr> wptr;
    size_t curr;
};

bool operator==(const StrBlobPtr&, const StrBlobPtr&);
bool operator!=(const StrBlobPtr&, const StrBlobPtr&);
bool operator<(const StrBlobPtr&, const StrBlobPtr&);
bool operator>(const StrBlobPtr&, const StrBlobPtr&);
bool operator<=(const StrBlobPtr&, const StrBlobPtr&);
bool operator>=(const StrBlobPtr&, const StrBlobPtr&);

inline string& StrBlobPtr::deref() const{
    auto p = check(curr, "dereference past end");
    return (*p)[curr];
}

inline StrBlobPtr& StrBlobPtr::incr(){
    check(curr, "increment past end of StrBlobPtr");
    ++curr;
    return *this;
}

const string &StrBlobPtr::operator*() const{       //14.30
	auto p = check(curr, "dereference past end");
	return (*p)[curr];
}
const string *StrBlobPtr::operator->() const{
	return &this->operator*();
}
inline StrBlobPtr &StrBlobPtr::operator++() {
  check(curr, "increment past end of StrBlobPtr");
  ++curr;
  return *this;
}

inline StrBlobPtr &StrBlobPtr::operator--() {
  --curr;
  check(curr, "decrement past begin of StrBlobPtr");
  return *this;
}

inline StrBlobPtr StrBlobPtr::operator++(int) {
  StrBlobPtr ret = *this;
  ++*this;
  return ret;
}

inline StrBlobPtr StrBlobPtr::operator--(int) {
  StrBlobPtr ret = *this;
  --*this;
  return ret;
}

inline StrBlobPtr &StrBlobPtr::operator+=(size_t n) {
  curr += n;
  check(curr, "increment past end of StrBlobPtr");
  return *this;
}

inline StrBlobPtr &StrBlobPtr::operator-=(size_t n) {
  curr -= n;
  check(curr, "increment past end of StrBlobPtr");
  return *this;
}

inline StrBlobPtr StrBlobPtr::operator+(size_t n) const {
  StrBlobPtr ret = *this;
  ret += n;
  return ret;
}

inline StrBlobPtr StrBlobPtr::operator-(size_t n) const {
  StrBlobPtr ret = *this;
  ret -= n;
  return ret;
}

inline shared_ptr> StrBlobPtr::check(size_t i, const string& msg) const{
    auto ret = wptr.lock();
    if (!ret) throw runtime_error("unbound StrBlobPtr");
    if (i >= ret->size()) throw out_of_range(msg);
    return ret;
}

inline string& StrBlobPtr::operator[](size_t n){
    auto p = check(n, "dereference out of range.");
    return (*p)[n];
}

inline const string& StrBlobPtr::operator[](size_t n) const{
    auto p = check(n, "dereference out of range.");
    return (*p)[n];
}
//=================================================================================
//
//      ConstStrBlobPtr - custom const_iterator of StrBlob
//
//=================================================================================
class ConstStrBlobPtr {
    friend bool operator==(const ConstStrBlobPtr&, const ConstStrBlobPtr&);
    friend bool operator!=(const ConstStrBlobPtr&, const ConstStrBlobPtr&);
	friend bool operator<(const ConstStrBlobPtr&, const ConstStrBlobPtr&);
	friend bool operator>(const ConstStrBlobPtr&, const ConstStrBlobPtr&);
	friend bool operator<=(const ConstStrBlobPtr&, const ConstStrBlobPtr&);
	friend bool operator>=(const ConstStrBlobPtr&, const ConstStrBlobPtr&);

public:
    ConstStrBlobPtr() : curr(0) {}
    ConstStrBlobPtr(const StrBlob& s, size_t sz = 0) : wptr(s.data), curr(sz) {}

    const string& deref() const;
    ConstStrBlobPtr& incr();

    ConstStrBlobPtr &operator++();                  //14.27
    ConstStrBlobPtr &operator--();
    ConstStrBlobPtr operator++(int);
    ConstStrBlobPtr operator--(int);
    ConstStrBlobPtr &operator+=(size_t);
    ConstStrBlobPtr &operator-=(size_t);
    ConstStrBlobPtr operator+(size_t) const;        //14.28
    ConstStrBlobPtr operator-(size_t) const;
    const string& operator[](size_t n) const;       //14.26
	const string& operator*() const;
	const string* operator->() const;  //14.30

private:
    shared_ptr> check(size_t, const string&) const;

    weak_ptr> wptr;
    size_t curr;
};

inline const string& ConstStrBlobPtr::deref() const{
    auto p = check(curr, "dereference past end");
    return (*p)[curr];
}

inline ConstStrBlobPtr& ConstStrBlobPtr::incr(){
    check(curr, "increment past end of StrBlobPtr");
    ++curr;
    return *this;
}

inline const string& ConstStrBlobPtr::operator*() const {
  auto p = check(curr, "dereference past end");
  return (*p)[curr];
}

inline const string *ConstStrBlobPtr::operator->() const {  //14.30
  return &this->operator*();
}

inline ConstStrBlobPtr &ConstStrBlobPtr::operator++() {
  check(curr, "increment past end of ConstStrBlobPtr");
  ++curr;
  return *this;
}

inline ConstStrBlobPtr &ConstStrBlobPtr::operator--() {
  --curr;
  check(-1, "decrement past begin of ConstStrBlobPtr");
  return *this;
}

inline ConstStrBlobPtr ConstStrBlobPtr::operator++(int) {
  ConstStrBlobPtr ret = *this;
  ++*this;
  return ret;
}

inline ConstStrBlobPtr ConstStrBlobPtr::operator--(int) {
  ConstStrBlobPtr ret = *this;
  --*this;
  return ret;
}

inline ConstStrBlobPtr &ConstStrBlobPtr::operator+=(size_t n) {
  curr += n;
  check(curr, "increment past end of ConstStrBlobPtr");
  return *this;
}

inline ConstStrBlobPtr &ConstStrBlobPtr::operator-=(size_t n) {
  curr -= n;
  check(curr, "increment past end of ConstStrBlobPtr");
  return *this;
}

inline ConstStrBlobPtr ConstStrBlobPtr::operator+(size_t n) const {
  ConstStrBlobPtr ret = *this;
  ret += n;
  return ret;
}

inline ConstStrBlobPtr ConstStrBlobPtr::operator-(size_t n) const {
  ConstStrBlobPtr ret = *this;
  ret -= n;
  return ret;
}

inline shared_ptr>
ConstStrBlobPtr::check(size_t i, const string& msg) const{
    auto ret = wptr.lock();
    if (!ret) throw runtime_error("unbound StrBlobPtr");
    if (i >= ret->size()) throw out_of_range(msg);
    return ret;
}

inline const string& ConstStrBlobPtr::operator[](size_t n) const{
    auto p = check(n, "dereference out of range.");
    return (*p)[n];
}

bool operator==(const ConstStrBlobPtr&, const ConstStrBlobPtr&);
bool operator!=(const ConstStrBlobPtr&, const ConstStrBlobPtr&);
bool operator<(const ConstStrBlobPtr&, const ConstStrBlobPtr&);
bool operator>(const ConstStrBlobPtr&, const ConstStrBlobPtr&);
bool operator<=(const ConstStrBlobPtr&, const ConstStrBlobPtr&);
bool operator>=(const ConstStrBlobPtr&, const ConstStrBlobPtr&);
//==================================================================
//
//      operators
//
//==================================================================

bool operator==(const StrBlob& lhs, const StrBlob& rhs){
    return *lhs.data == *rhs.data;
}

bool operator!=(const StrBlob& lhs, const StrBlob& rhs){
    return !(lhs == rhs);
}

bool operator<(const StrBlob& lhs, const StrBlob& rhs){
	return lexicographical_compare(lhs.data->begin(), lhs.data->end(), rhs.data->begin(), rhs.data->end());
}

bool operator>(const StrBlob& lhs, const StrBlob& rhs){
	return rhs < lhs;
}
bool operator<=(const StrBlob& lhs, const StrBlob& rhs){
	return !(lhs > rhs);
}
bool operator>=(const StrBlob& lhs, const StrBlob& rhs){
	return  !(lhs < rhs);
}

bool operator==(const StrBlobPtr& lhs, const StrBlobPtr& rhs){
    return lhs.curr == rhs.curr;
}

bool operator!=(const StrBlobPtr& lhs, const StrBlobPtr& rhs){
    return !(lhs == rhs);
}

bool operator<(const StrBlobPtr& x, const StrBlobPtr& y){
	    return x.curr < y.curr;
}

bool operator>(const StrBlobPtr& x, const StrBlobPtr& y){
	    return x.curr > y.curr;
}

bool operator<=(const StrBlobPtr& x, const StrBlobPtr& y){
	    return x.curr <= y.curr;
}

bool operator>=(const StrBlobPtr& x, const StrBlobPtr& y){
	    return x.curr >= y.curr;
}

bool operator==(const ConstStrBlobPtr& lhs, const ConstStrBlobPtr& rhs){
    return lhs.curr == rhs.curr;
}

bool operator!=(const ConstStrBlobPtr& lhs, const ConstStrBlobPtr& rhs){
    return !(lhs == rhs);
}

bool operator<(const ConstStrBlobPtr& lhs, const ConstStrBlobPtr& rhs){
	    return lhs.curr < rhs.curr;
}

bool operator>(const ConstStrBlobPtr& lhs, const ConstStrBlobPtr& rhs){
	    return lhs.curr > rhs.curr;
}

bool operator<=(const ConstStrBlobPtr& lhs, const ConstStrBlobPtr& rhs){
	    return lhs.curr <= rhs.curr;
}

bool operator>=(const ConstStrBlobPtr& lhs, const ConstStrBlobPtr& rhs){
	    return lhs.curr >= rhs.curr;
}

//==================================================================
//
//      copy assignment operator and move assignment operator.
//
//==================================================================
StrBlob& StrBlob::operator=(const StrBlob& lhs){
    data = make_shared>(*lhs.data);
    return *this;
}

StrBlob& StrBlob::operator=(StrBlob&& rhs) noexcept{
    if (this != &rhs) {
        data = move(rhs.data);
        rhs.data = nullptr;
    }

    return *this;
}

//==================================================================
//
//      members
//
//==================================================================
StrBlobPtr StrBlob::begin(){
    return StrBlobPtr(*this);
}

StrBlobPtr StrBlob::end(){
    return StrBlobPtr(*this, data->size());
}

ConstStrBlobPtr StrBlob::cbegin() const{
    return ConstStrBlobPtr(*this);
}

ConstStrBlobPtr StrBlob::cend() const{
    return ConstStrBlobPtr(*this, data->size());
}

//StrVec
class StrVec {
    friend bool operator==(const StrVec&, const StrVec&);
	friend bool operator!=(const StrVec&, const StrVec&);
	friend bool operator<(const StrVec&, const StrVec&);
	friend bool operator>(const StrVec&, const StrVec&);
	friend bool operator<=(const StrVec&, const StrVec&);
	friend bool operator>=(const StrVec&, const StrVec&);
public:
    StrVec() : elements(nullptr), first_free(nullptr), cap(nullptr) {}
    StrVec(initializer_list);
    StrVec(const StrVec&);
    StrVec& operator=(const StrVec&);
    StrVec(StrVec&&) noexcept;
    StrVec& operator=(StrVec&&) noexcept;
    ~StrVec();

    StrVec& operator=(initializer_list);         //14.23
    void push_back(const string&);
    size_t size() const { return first_free - elements; }
    size_t capacity() const { return cap - elements; }
    string* begin() const { return elements; }
    string* end() const { return first_free; }

    string& at(size_t pos) { return *(elements + pos); }
    const string& at(size_t pos) const { return *(elements + pos); }

    string& operator[](size_t n) { return elements[n]; }           //14.26
    const string& operator[](size_t n) const { return elements[n]; }  //14.26

    void reserve(size_t new_cap);
    void resize(size_t count);
    void resize(size_t count, const string&);

private:
    pair alloc_n_copy(const string*, const string*);
    void free();
    void chk_n_alloc()    {
        if (size() == capacity()) reallocate();
    }
    void reallocate();
    void alloc_n_move(size_t new_cap);
    void range_initialize(const string*, const string*);
private:
    string* elements;
    string* first_free;
    string* cap;
    allocator alloc;
};

bool operator==(const StrVec&, const StrVec&);
bool operator!=(const StrVec&, const StrVec&);
bool operator<(const StrVec&, const StrVec&);
bool operator>(const StrVec&, const StrVec&);
bool operator<=(const StrVec&, const StrVec&);
bool operator>=(const StrVec&, const StrVec&);

void StrVec::push_back(const string& s){
    chk_n_alloc();
    alloc.construct(first_free++, s);
}

pair StrVec::alloc_n_copy(const string* b, const string* e){
    auto data = alloc.allocate(e - b);
    return {data, uninitialized_copy(b, e, data)};
}

void StrVec::free(){
    if (elements) {
        for_each(elements, first_free,
                 [this](string& rhs) { alloc.destroy(&rhs); });
        alloc.deallocate(elements, cap - elements);
    }
}

void StrVec::range_initialize(const string* first, const string* last){
    auto newdata = alloc_n_copy(first, last);
    elements = newdata.first;
    first_free = cap = newdata.second;
}

StrVec::StrVec(const StrVec& rhs){
    range_initialize(rhs.begin(), rhs.end());
}

StrVec::StrVec(initializer_list il){
    range_initialize(il.begin(), il.end());
}

StrVec::~StrVec(){
    free();
}

StrVec& StrVec::operator=(const StrVec& rhs){
    auto data = alloc_n_copy(rhs.begin(), rhs.end());
    free();
    elements = data.first;
    first_free = cap = data.second;
    return *this;
}

void StrVec::alloc_n_move(size_t new_cap){
    auto newdata = alloc.allocate(new_cap);
    auto dest = newdata;
    auto elem = elements;
    for (size_t i = 0; i != size(); ++i)
        alloc.construct(dest++, move(*elem++));
    free();
    elements = newdata;
    first_free = dest;
    cap = elements + new_cap;
}

void StrVec::reallocate(){
    auto newcapacity = size() ? 2 * size() : 1;
    alloc_n_move(newcapacity);
}

void StrVec::reserve(size_t new_cap){
    if (new_cap <= capacity()) return;
    alloc_n_move(new_cap);
}

void StrVec::resize(size_t count){
    resize(count, string());
}

void StrVec::resize(size_t count, const string& s){
    if (count > size()) {
        if (count > capacity()) reserve(count * 2);
        for (size_t i = size(); i != count; ++i)
            alloc.construct(first_free++, s);
    }
    else if (count < size()) {
        while (first_free != elements + count) alloc.destroy(--first_free);
    }
}

StrVec::StrVec(StrVec&& s) noexcept : elements(s.elements), first_free(s.first_free), cap(s.cap){
    // leave s in a state in which it is safe to run the destructor.
    s.elements = s.first_free = s.cap = nullptr;
}

StrVec& StrVec::operator=(StrVec&& rhs) noexcept{
    if (this != &rhs) {
        free();
        elements = rhs.elements;
        first_free = rhs.first_free;
        cap = rhs.cap;
        rhs.elements = rhs.first_free = rhs.cap = nullptr;
    }
    return *this;
}

bool operator==(const StrVec& lhs, const StrVec& rhs){
    return (lhs.size() == rhs.size() &&
            equal(lhs.begin(), lhs.end(), rhs.begin()));
}

bool operator!=(const StrVec& lhs, const StrVec& rhs){
    return !(lhs == rhs);
}

bool operator<(const StrVec& lhs, const StrVec& rhs){
	    return lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
}

bool operator>(const StrVec& lhs, const StrVec& rhs){
	    return rhs < lhs;
}

bool operator<=(const StrVec& lhs, const StrVec& rhs){
	    return !(rhs < lhs);
}

bool operator>=(const StrVec& lhs, const StrVec& rhs){
	    return !(lhs < rhs);
}

StrVec& StrVec::operator=(initializer_list li){         //14.23
    auto data = alloc_n_copy(li.begin(), li.end());
    free();
    elements = data.first;
    first_free = cap = data.second;
    return *this;
}

//14.24
class Date {
    friend bool operator==(const Date& lhs, const Date& rhs);
    friend bool operator<(const Date& lhs, const Date& rhs);
    friend bool check(const Date& d);
    friend ostream& operator<<(ostream& os, const Date& d);
public:
    typedef size_t Size;

    //! default constructor
    Date() = default;
    //! constructor taking Size as days
    explicit Date(Size days);
    //! constructor taking three Size
    Date(Size d, Size m, Size y) : day(d), month(m), year(y) {}
    //! constructor taking iostream
    Date(istream& is, ostream& os);

    //! copy constructor
    Date(const Date& d);
    //! move constructor
    Date(Date&& d) noexcept;

    //! copy operator=
    Date& operator=(const Date& d);
    //! move operator=
    Date& operator=(Date&& rhs) noexcept;

    //! destructor  --  in this case, user-defined destructor is not nessary.
    ~Date() { cout << "destroying\n"; }

    //! members
    Size toDays() const; // not implemented yet.
    Date& operator+=(Size offset);
    Date& operator-=(Size offset);
    explicit operator bool() { return (year < 4000) ? true : false; }     //14.49
private:
    Size day = 1;
    Size month = 1;
    Size year = 0;
};

static const Date::Size YtoD_400 = 146097; // 365*400 + 400/4 -3 == 146097
static const Date::Size YtoD_100 = 36524; // 365*100 + 100/4 -1 ==  36524
static const Date::Size YtoD_4 = 1461; // 365*4 + 1          ==   1461
static const Date::Size YtoD_1 = 365; // 365

//! normal year
static const vector monthsVec_n = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

//! leap year
static const vector monthsVec_l = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

//! non-member operators:  <<  >>  -   ==  !=  <   <=  >   >=
//!
ostream& operator<<(ostream& os, const Date& d);
istream& operator>>(istream& is, Date& d);
int operator-(const Date& lhs, const Date& rhs);
bool operator==(const Date& lhs, const Date& rhs);
bool operator!=(const Date& lhs, const Date& rhs);
bool operator<(const Date& lhs, const Date& rhs);
bool operator<=(const Date& lhs, const Date& rhs);
bool operator>(const Date& lhs, const Date& rhs);
bool operator>=(const Date& lhs, const Date& rhs);
Date operator-(const Date& lhs, Date::Size rhs);
Date operator+(const Date& lhs, Date::Size rhs);

//!  utillities:
bool check(const Date& d);
inline bool isLeapYear(Date::Size y);

//! check if the date object passed in is valid
inline bool check(const Date& d){
    if (d.month == 0 || d.month > 12)
        return false;
    else {
        //!    month == 1 3 5 7 8 10 12
        if (d.month == 1 || d.month == 3 || d.month == 5 || d.month == 7 ||
            d.month == 8 || d.month == 10 || d.month == 12) {
            if (d.day == 0 || d.day > 31)
                return false;
            else
                return true;
        }
        else {
            //!    month == 4 6 9 11
            if (d.month == 4 || d.month == 6 || d.month == 9 || d.month == 11) {
                if (d.day == 0 || d.day > 30)
                    return false;
                else
                    return true;
            }
            else {
                //!    month == 2
                if (isLeapYear(d.year)) {
                    if (d.day == 0 || d.day > 29)
                        return false;
                    else
                        return true;
                }
                else {
                    if (d.day == 0 || d.day > 28)
                        return false;
                    else
                        return true;
                }
            }
        }
    }
}

inline bool isLeapYear(Date::Size y){
    if (!(y % 400)) {
        return true;
    }
    else {
        if (!(y % 100)) {
            return false;
        }
        else
            return !(y % 4);
    }
}

//! constructor taking Size as days
//! the argument must be within (0, 2^32)
Date::Date(Size days){
    //! calculate the year
    Size y400 = days / YtoD_400;
    Size y100 = (days - y400 * YtoD_400) / YtoD_100;
    Size y4 = (days - y400 * YtoD_400 - y100 * YtoD_100) / YtoD_4;
    Size y = (days - y400 * YtoD_400 - y100 * YtoD_100 - y4 * YtoD_4) / 365;
    Size d = days - y400 * YtoD_400 - y100 * YtoD_100 - y4 * YtoD_4 - y * 365;
    this->year = y400 * 400 + y100 * 100 + y4 * 4 + y;

    //! check if leap and choose the months vector accordingly
    vector currYear =
        isLeapYear(this->year) ? monthsVec_l : monthsVec_n;

    //! calculate day and month using find_if + lambda
    Size D_accumu = 0, M_accumu = 0;
    //! @bug    fixed:  the variabbles above hade been declared inside the
    //! find_if as static
    //!                 which caused the bug. It works fine now after being move
    //!                 outside.

    find_if(currYear.cbegin(), currYear.cend(), [&](Size m) {

        D_accumu += m;
        M_accumu++;

        if (d < D_accumu) {
            this->month = M_accumu;
            this->day = d + m - D_accumu;

            return true;
        }
        else
            return false;
    });
}

//! construcotr taking iostream
Date::Date(istream& is, ostream& os){
    is >> day >> month >> year;

    if (is) {
        if (check(*this))
            return;
        else {
            os << "Invalid input! Object is default initialized.";
            *this = Date();
        }
    }
    else {
        os << "Invalid input! Object is default initialized.";
        *this = Date();
    }
}

//! copy constructor
Date::Date(const Date& d) : day(d.day), month(d.month), year(d.year){
}

//! move constructor
Date::Date(Date&& d) noexcept : day(d.day), month(d.month), year(d.year){
    cout << "copy moving";
}

//! copy operator=
Date& Date::operator=(const Date& d){
    this->day = d.day;
    this->month = d.month;
    this->year = d.year;

    return *this;
}

//! move operator=
Date& Date::operator=(Date&& rhs) noexcept{
    if (this != &rhs) {
        this->day = rhs.day;
        this->month = rhs.month;
        this->year = rhs.year;
    }
    cout << "moving =";

    return *this;
}

//! conver to days
Date::Size Date::toDays() const{
    Size result = this->day;

    //! check if leap and choose the months vector accordingly
    vector currYear =
        isLeapYear(this->year) ? monthsVec_l : monthsVec_n;

    //! calculate result + days by months
    for (auto it = currYear.cbegin(); it != currYear.cbegin() + this->month - 1;
         ++it)
        result += *it;

    //! calculate result + days by years
    result += (this->year / 400) * YtoD_400;
    result += (this->year % 400 / 100) * YtoD_100;
    result += (this->year % 100 / 4) * YtoD_4;
    result += (this->year % 4) * YtoD_1;

    return result;
}

//! member operators:   +=  -=

Date& Date::operator+=(Date::Size offset){
    *this = Date(this->toDays() + offset);
    return *this;
}

Date& Date::operator-=(Date::Size offset)
{
    if (this->toDays() > offset)
        *this = Date(this->toDays() - offset);
    else
        *this = Date();

    return *this;
}

//! non-member operators:  <<  >>  -   ==  !=  <   <=  >   >=

ostream& operator<<(ostream& os, const Date& d){
    os << d.day << " " << d.month << " " << d.year;
    return os;
}

istream& operator>>(istream& is, Date& d){
    if (is) {
        Date input = Date(is, cout);
        if (check(input)) d = input;
    }
    return is;
}

int operator-(const Date& lhs, const Date& rhs){
    return lhs.toDays() - rhs.toDays();
}

bool operator==(const Date& lhs, const Date& rhs){
    return (lhs.day == rhs.day) && (lhs.month == rhs.month) &&
           (lhs.year == rhs.year);
}

bool operator!=(const Date& lhs, const Date& rhs){
    return !(lhs == rhs);
}

bool operator<(const Date& lhs, const Date& rhs){
    return lhs.toDays() < rhs.toDays();
}

bool operator<=(const Date& lhs, const Date& rhs){
    return (lhs < rhs) || (lhs == rhs);
}

bool operator>(const Date& lhs, const Date& rhs){
    return !(lhs <= rhs);
}

bool operator>=(const Date& lhs, const Date& rhs){
    return !(lhs < rhs);
}

Date operator-(const Date& lhs, Date::Size rhs){ //!  ^^^ rhs must not be larger than 2^32-1
    //! copy lhs
    Date result(lhs);
    result -= rhs;

    return result;
}

Date operator+(const Date& lhs, Date::Size rhs){ //!  ^^^ rhs must not be larger than 2^32-1
    //! copy lhs
    Date result(lhs);
    result += rhs;

    return result;
}

//14.32
class StrBlobPtr_pointer {
public:
	StrBlobPtr_pointer() = default;
	StrBlobPtr_pointer(StrBlobPtr* p) : pointer(p) {}

	StrBlobPtr& operator*();
	StrBlobPtr* operator->();
private:
	StrBlobPtr* pointer = nullptr;
};

StrBlobPtr& StrBlobPtr_pointer::operator*(){
	return *(this->pointer);
}

StrBlobPtr*	StrBlobPtr_pointer::operator->(){
	return &this -> operator*();
}

//14.34
struct  func_class{
    int operator()(bool a, int b, int c){
        return a ? b : c;
    }
};

//14.35
class PrintString{
public:
	PrintString(istream& i = cin) : is(i){}
    string operator()(){
        string str;
		getline(is, str);
		return is ? str : string();
    }
private:
    istream& is;
};

//14.37
class IsEqual {
    int value;
public:
    IsEqual(int v) : value(v) {}
    bool operator()(int elem) { return elem == value; }
};

//14.38
class BoundTest {
public:
    BoundTest(size_t l = 0, size_t u = 0) : lower(l), upper(u) {}
    bool operator()(const string& s)
    {
        return lower <= s.length() && s.length() <= upper;
    }

private:
    size_t lower;
    size_t upper;
};

//14.40
class ShorterString {
public:
    bool operator()(string const& s1, string const& s2) const
    {
        return s1.size() < s2.size();
    }
};

class BiggerEqual {
    size_t sz_;

public:
    BiggerEqual(size_t sz) : sz_(sz) {}
    bool operator()(string const& s) { return s.size() >= sz_; }
};

class Print {
public:
    void operator()(string const& s) { cout << s << " "; }
};

string make_plural(size_t ctr, string const& word, string const& ending){
    return (ctr > 1) ? word + ending : word;
}

void elimDups(vector& words){
    sort(words.begin(), words.end());
    auto end_unique = unique(words.begin(), words.end());
    words.erase(end_unique, words.end());
}

void biggies(vector& words, vector::size_type sz){
    elimDups(words);
    stable_sort(words.begin(), words.end(), ShorterString());
    auto wc = find_if(words.begin(), words.end(), BiggerEqual(sz));
    auto count = words.end() - wc;
    cout << count << " " << make_plural(count, "word", "s") << " of length "
         << sz << " or longer" << endl;
    for_each(wc, words.end(), Print());
    cout << endl;
}
#endif
//main.cc
#include 
#include 
#include 
#include 
#include
#include "Chapter14.h"
using namespace std;
#define NUM1452

/*14.16*/
void foo(String x){
    cout << x << endl;
}

void bar(const String& x){
    cout << x.c_str() << endl;
}

String baz(){
    String ret("world");
    return ret;
}

//14.44
//! normal function
int add(int i, int j)
{
    return i + j;
}

//! named lambda
auto mod = [](int i, int j) { return i % j; };

//! functor
struct wy_p {
    int operator()(int denominator, int pisor)
    {
        return denominator / pisor;
    }
};

//! the map
map> binops = {
    {"+", add},                                //  function pointer
    {"-", minus()},                  //  library functor
    {"/", wy_p()},                           //  user-defined functor
    {"*", [](int i, int j) { return i * j; }}, //  unnamed lambda
    {"%", mod}                                 //  named lambda object
};



int main(){
/*14.1*/
#ifdef NUM141
	cout <<"不同,1. 我们可以直接调用重载运算符函数。2.重载运算符函数必须是类的成员,或者至少有一个类类型的参数."
		"重载运算符不保证操作数的求值顺序,例如对&&和||的重载版本不再具有'短路求值'的特性,两个操作数都要求值,而且不规定操作数的求值顺序。"
		"相同。重载运算符与内置运算符有一样的优先性和结合性。"<> item;
	cout << item << endl;
#endif
/*14.3*/
#ifdef NUM143
	cout <<"(a)string字符类型是const char[]类型,char*类型内置了==运算符,所以不会调用string类型的==重载. "
		"(b)string版本 (c)vector版本 (d)string版本"< sb2) {
        for (ConstStrBlobPtr iter = sb1.cbegin(); iter < sb1.cend();
             iter.incr())
            cout << iter.deref() << " ";
        cout << endl;
    }

    StrBlobPtr iter(sb2);
    cout << iter[2] << endl;
//StrVec
    const StrVec const_vec_list_small{"hello", "world", "ok"};
    cout << const_vec_list_small[1] << endl;
//String
     String s1("hello");
     cout << s1[2] << endl;
#endif
/*14.27*/
#ifdef NUM1427
    StrBlob sb1{"a", "b", "c"};
    StrBlob sb2 = sb1;
    sb2[2] = "abc";
    if (sb1 > sb2) {
    	for (StrBlobPtr iter = sb1.begin(); iter < sb1.end(); ++iter)
    		cout << iter.deref() << " ";
        cout << endl;
    }
    ConstStrBlobPtr iter(sb2);
    cout << (iter + 2).deref() << endl;
#endif
/*14.28*/
#ifdef NUM1428
    cout << "见Chapter14.h  //14.27"<size() << endl;
#endif
/*14.31*/
#ifdef NUM1431
	cout<< "StrBlobPtrde类中被北邮动态内存分配,所以只需要合成的析构函数. 并且, 两个成员weak_ptr>和size_t类型,前者定义了自己的拷贝构造函数,后者是内置类型。所以完全可以利用合成的拷贝控制。"<deref() < vec;
    for (string tmp; !(tmp = getInput()).empty();) 
        vec.push_back(tmp);
    for (const auto& str : vec) 
        cout << str << " ";
    cout << endl;
#endif
/*14.37*/
#ifdef NUM1437
    vector vec = {3, 2, 1, 4, 3, 7, 8, 6};
    replace_if(vec.begin(), vec.end(), IsEqual(3), 5);
    for (int i : vec) cout << i << " ";
    cout << endl;
#endif
/*14.38*/
#ifdef NUM1438
    ifstream fin("./storyDataFile");

    size_t quantity9 = 0, quantity10 = 0;
    BoundTest test9(1, 9);
    BoundTest test10(1, 10);

    for (string word; fin >> word;) {
        if (test9(word)) ++quantity9;
        if (test10(word)) ++quantity10;
    }
    cout << quantity9 << ", " << quantity10 << endl;
#endif
/*14.39*/
#ifdef NUM1439
	cout<<"见14.38"< vec{"fox", "jumps", "over", "quick", "red",
                       "red", "slow",  "the",  "turtle"};
    biggies(vec, 4);
#endif
/*14.41*/
#ifdef NUM1441
    cout <<"lambda是通过匿名的函数对象来实现的,因此我们可以把lambda看作是对函数对象在使用方式上进行的简化。"
        "当代码需要一个简单的函数,并且这个函数并不会在其他地方被使用时,就可以使用lambda来实现,"
        "此时它所起的作用类似于匿名函数。但如果这个函数需要多次使用,并且它需要保存某些状态的话,使用函数对象更合适一些。"< ivec{1, 111, 1111, 11111};
    int count = count_if(ivec.cbegin(), ivec.cend(),
                              bind(greater(), _1, 1024));
    cout << count << endl;

    vector svec{"pooh", "pooh", "linux", "pooh"};
    auto found =
        find_if(svec.cbegin(), svec.cend(),
                     bind(not_equal_to(), _1, "pooh"));
    cout << *found << endl;

    transform(ivec.begin(), ivec.end(), ivec.begin(),   //all numbers multiple 2
                   bind(multiplies(), _1, 2));
    for (int i : ivec) cout << i << " ";
    cout << endl;
#endif
/*14.43*/
#ifdef NUM1443
    auto data = {2, 3, 4, 5};
    int input;
    cin >> input;
    modulus mod;
    auto predicator = [&](int i) { return 0 == mod(input, i); };
    auto is_pisible = any_of(data.begin(), data.end(), predicator);
    cout << (is_pisible ? "Yes!" : "No!") << endl;
#endif
/*14.44*/
#ifdef NUM1444
 while (true) {
        cout << "\npleasr enter: num operator num :\n";
        int n1, n2;
        string s;
        cin >> n1 >> s >> n2;

        cout << binops[s](n1, n2);
    }
#endif
/*14.45*/
#ifdef NUM1445
    Sales_data cp5("C++ Primer 5th", 4, 106.5);
    cout << cp5 << endl;
    cout << static_cast(cp5) << endl;    //C++ Primer 5th
    cout << static_cast(cp5) << endl;	//106.5
#endif
/*14.46*/
#ifdef NUM1446
    cout <<"不应该,这种操作极具误导性,应该把它们声明成explicit的,这样可以防止sales_data"
        " 在默写情况下被默认转换成string或double类型,防止隐式的类型转换。"<(date)) cout << date << endl;
#endif
/*14.50*/
#ifdef NUM1450
struct LongDouble {
    LongDouble(double = 0.0);
    operatordouble();
    operatorfloat();
};
    LongDouble ldObj;
    int ex1 = ldObj;    // error ambiguous: double or float?
    float ex2 = ldObj;  // legal
#endif
/*14.51*/
#ifdef NUM1451
    void calc(int);
    void calc(LongDouble);
    double dval;
    calc(dval); // which calc?
	cout<< "最佳可行函数: void calc(int).因为类类型转换时最低级别. "
	"顺序是1. 完全匹配. 2. const转换. 3. 类型提升 4.算数和指针转换 5.类类型转换. "<