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

笔记较为零散,都是自己不熟悉的知识点。

习题答案至于一个.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 <iostream>
#include <memory>
#include <vector>
#include <string>
#include <initializer_list>
#include <algorithm>
#include <exception>
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<char*, char*> 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<char> 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<char*>(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<char*, char*> 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<string>
//
//=================================================================================

class StrBlob {
    using size_type = vector<string>::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<vector<string>>()) {}
    StrBlob(initializer_list<string> il) : data(make_shared<vector<string>>(il))    {
    }

    StrBlob(const StrBlob& sb) : data(make_shared<vector<string>>(*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<vector<string>> 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<vector<string>> check(size_t, const string&) const;
    weak_ptr<vector<string>> 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<vector<string>> 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<vector<string>> check(size_t, const string&) const;

    weak_ptr<vector<string>> 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<vector<string>>
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<vector<string>>(*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<string>);
    StrVec(const StrVec&);
    StrVec& operator=(const StrVec&);
    StrVec(StrVec&&) noexcept;
    StrVec& operator=(StrVec&&) noexcept;
    ~StrVec();

    StrVec& operator=(initializer_list<string>);         //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<string*, string*> 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<string> 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<string*, string*> 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<string> 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<string> 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<Date::Size> monthsVec_n = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

//! leap year
static const vector<Date::Size> 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<Size> 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<Size> 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<string>& words){
    sort(words.begin(), words.end());
    auto end_unique = unique(words.begin(), words.end());
    words.erase(end_unique, words.end());
}

void biggies(vector<string>& words, vector<string>::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 <fstream>
#include <iostream>
#include <vector>
#include <functional>
#include <map>
#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_div {
    int operator()(int denominator, int divisor)
    {
        return denominator / divisor;
    }
};

//! the map
map<string, function<int(int, int)>> binops = {
    {"+", add},                                //  function pointer
    {"-", minus<int>()},                  //  library functor
    {"/", wy_div()},                           //  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.重载运算符函数必须是类的成员,或者至少有一个类类型的参数."
		"重载运算符不保证操作数的求值顺序,例如对&&和||的重载版本不再具有'短路求值'的特性,两个操作数都要求值,而且不规定操作数的求值顺序。"
		"相同。重载运算符与内置运算符有一样的优先性和结合性。"<<endl;
#endif
/*14.2*/
#ifdef NUM142
	Sales_data item;
	cin >> item;
	cout << item << endl;
#endif
/*14.3*/
#ifdef NUM143
	cout <<"(a)string字符类型是const char[]类型,char*类型内置了==运算符,所以不会调用string类型的==重载. "
		"(b)string版本 (c)vector版本 (d)string版本"<<endl;
#endif
/*14.4*/
#ifdef NUM144
	cout <<"(a)对称操作符,不需要是成员.(b)改变对象的状态,必须是成员"
		"(c)改变对象状态,必须是成员(d)必须是成员(e)非成员(f)非成员(g)非成员(h)必须是成员" <<endl;
#endif
/*14.5*/
#ifdef NUM145
	Book book1(123, "C++","Lippman","2013");
	Book book2(123, "C++","Lippman","2013");
	if(book1 == book2) cout << book1 << endl;
#endif
/*14.6*/
#ifdef NUM146
	cout << "见Chapter14.h  //14.2"<<endl;
#endif
/*14.7*/
#ifdef NUM147
	String str("hello world");
	cout << str << endl;
#endif
/*14.8*/
#ifdef NUM148
	cout << "见Chapter14.h  //14.5"<<endl;
#endif
/*14.10*/
#ifdef NUM1410
	cout << "见Chapter14.h  //14.2"<<endl;
#endif
/*14.10*/
#ifdef NUM1410
	cout <<"(a)正确的形式  (b)24.95转换成unsigned类型,错误,输出10 24 22.8 0.95. "<<endl;
#endif
/*14.11*/
#ifdef NUM1411
	cout <<"只是没有添加输入检查,没有什么发生. "<<endl;
#endif
/*14.12*/
#ifdef NUM1412
	cout << "见Chapter14.h  //14.5"<<endl;
#endif
/*14.13*/
#ifdef NUM1413
	cout << "不需要"<<endl;
#endif
/*14.14*/
#ifdef NUM1414
/*
	Sales_data operator+(const Sales_data &lhs, const Sales_data &rhs){
		Sales_data sum = lhs;  // copy data members from lhs into sum
		sum = sum + rhs;             // add rhs into sum
		return sum;
	}
*/
	cout << "如上所示,直接定义opeartor+会拷贝一个不必要的临时对象。"<<endl;
#endif
/*14.15*/
#ifdef NUM1415
	cout << "见Chapter14.h  //14.5"<<endl;
#endif
/*14.16*/
#ifdef NUM1416
//StrBlob   StrBlobPtr
	StrBlob sb{"Hello", "World", "C++"};
    for (ConstStrBlobPtr iter = sb.cbegin(); iter != sb.cend(); iter.incr()) {
        cout << iter.deref() << " ";
    }
    cout << endl;
//StrVec
    StrVec vec;
    vec.reserve(6);
    cout << "capacity(reserve to 6): " << vec.capacity() << endl;

    vec.reserve(4);
    cout << "capacity(reserve to 4): " << vec.capacity() << endl;

    vec.push_back("hello");
    vec.push_back("world");

    vec.resize(4);

    for (auto i = vec.begin(); i != vec.end(); ++i)
        cout << *i << endl;
    cout << "-EOF-" << endl;

    vec.resize(1);

    for (auto i = vec.begin(); i != vec.end(); ++i)
        cout << *i << endl;
    cout << "-EOF-" << endl;

    StrVec vec_list{"hello", "world", "C++"};

    for (auto i = vec_list.begin(); i != vec_list.end(); ++i)
        cout << *i << " ";
    cout << endl;

    // Test operator==
    const StrVec const_vec_list{"hello", "world", "C++"};
    if (vec_list == const_vec_list)
        for (const auto& str : const_vec_list) cout << str << " ";
    cout << endl;
//string 见14.7
	char text[] = "world";
    String s0;
    String s1("hello");
    String s2(move(s0));
    String s3 = s1;
    String s4(text);
    s2 = s1;

    if (s2 == s1) cout << "s2 == s1" << endl;

    foo(s1);
    bar(s1);
    foo("temporary");
    bar("temporary");
    String s5 = baz();

    vector<String> svec;
    // svec.push_back(s0);
    svec.push_back(s1);
    svec.push_back(s2);
    svec.push_back(s3);
    svec.push_back(s4);
    svec.push_back(baz());
    svec.push_back("good job");

    for (const auto& s : svec) {
        cout << s << endl;
    }
    cout << "Input a string: ";
    String s6;
    cin >> s6;
    cout << s6 << endl;
#endif
/*14.17*/
#ifdef NUM1417
    cout << "需要,见Chapter14.h  //14.15"<<endl;
#endif
/*14.18*/
#ifdef NUM1418
//StrBlob
	StrBlob str1{"a","b","c"};
	StrBlob str2{"a","b","c"};
	if(str1 >= str2){
		for(ConstStrBlobPtr iter = str1.cbegin(); iter != str1.cend(); iter.incr())
			cout<< iter.deref()<< " ";
		cout << endl;
	}
//StrVec
	const StrVec const_vec_list{"hello", "world", "ok"};
	const StrVec const_vec_list_small{"hello", "world", "linux"};
	cout << (const_vec_list_small < const_vec_list) << endl;
//String
    String s1("hello");
	cout << "Input a string: ";
	String s6;
	cin >> s6;
	cout << s6 << endl;

	if (s6 > s1) cout << "s6 > s1" << endl;
#endif
/*14.19*/
#ifdef NUM1419
	cout << "需要,见Chapter14.h  //14.5"<<endl;
#endif
/*14.20*/
#ifdef NUM1420
	cout << "见Chapter14.h  //14.2"<<endl;
#endif
/*14.21*/
#ifdef NUM1421
/*
	Sales_data& Sales_data::operator+=(const Sales_data &rhs)
	{
		Sales_data old_data = *this;
		*this = old_data + rhs;
		return *this;
	}
	Sales_data operator+(const Sales_data &lhs, const Sales_data &rhs)
	{
		Sales_data sum;
		sum.units_sold = lhs.units_sold + rhs.units_sold;
		sum.revenue = lhs.revenue + rhs.revenue;
		return sum;
	}
*/
	cout << "如上所示,+和+= 的运算符操作都定义了一个不必要的Sales_data对象。"<<endl;
#endif
/*14.22*/
#ifdef NUM1422
	string strCp5("C++ Primer");
    Sales_data cp5 = strCp5;
    cout << cp5 << endl;
#endif
/*14.23*/
#ifdef NUM1423
    const StrVec const_vec_list_small = {"hello", "world", "c++"};
    for(auto &i: const_vec_list_small) cout << i << " ";
    cout <<endl;
#endif
/*14.24*/
#ifdef NUM1424
 	Date lhs(9999999), rhs(1);
    cout << (lhs -= 12000) << "\n";
#endif
/*14.25*/
#ifdef NUM1425
    cout <<"无需其他,见14.24"<<endl;
#endif
/*14.26*/
#ifdef NUM1426
//StrBlob
    StrBlob sb1{"a", "b", "c"};
    StrBlob sb2 = sb1;

    sb2[2] = "abc";

    if (sb1 > 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"<<endl;
#endif
/*14.29*/
#ifdef NUM1429
    cout <<"因为++ -- 改变了对象的状态,定义const版本是没有意义的. "<<endl;
#endif
/*14.30*/
#ifdef NUM1430
    StrBlob sb1{"a", "b", "c"};
    StrBlob sb2 = sb1;
	StrBlobPtr iter1(sb1);
 	ConstStrBlobPtr iter2(sb2);
    cout << *(iter1+2) << " "<< iter2->size() << endl;
#endif
/*14.31*/
#ifdef NUM1431
	cout<< "StrBlobPtrde类中被北邮动态内存分配,所以只需要合成的析构函数. 并且, 两个成员weak_ptr<vector<string>>和size_t类型,前者定义了自己的拷贝构造函数,后者是内置类型。所以完全可以利用合成的拷贝控制。"<<endl;
#endif
/*14.32*/
#ifdef NUM1432
    StrBlob sb1{"a", "b", "c"};
    StrBlob sb2 = sb1;
	StrBlobPtr iter1(sb1);
	StrBlobPtr_pointer it(&iter1);
	cout << it->deref() <<endl;
#endif
/*14.33*/
#ifdef NUM1433
	cout <<"一个重载操作符函数与操作符相同数量的参数。因此,最小0最大256."<<endl;
#endif
/*14.34*/
#ifdef NUM1434
    func_class fc;
    cout << fc(0, 1, 2) << endl;
#endif
/*14.35*/
#ifdef NUM1435
    PrintString getstr;
    cout << getstr() << endl;
#endif
/*14.36*/
#ifdef NUM1436
    PrintString getInput;
    vector<string> 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<int> 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"<<endl;
#endif
/*14.40*/
#ifdef NUM1440
    vector<string> vec{"fox", "jumps", "over", "quick", "red",
                       "red", "slow",  "the",  "turtle"};
    biggies(vec, 4);
#endif
/*14.41*/
#ifdef NUM1441
    cout <<"lambda是通过匿名的函数对象来实现的,因此我们可以把lambda看作是对函数对象在使用方式上进行的简化。"
        "当代码需要一个简单的函数,并且这个函数并不会在其他地方被使用时,就可以使用lambda来实现,"
        "此时它所起的作用类似于匿名函数。但如果这个函数需要多次使用,并且它需要保存某些状态的话,使用函数对象更合适一些。"<<endl;
#endif
/*14.42*/
#ifdef NUM1442
    using placeholders::_1;
    vector<int> ivec{1, 111, 1111, 11111};
    int count = count_if(ivec.cbegin(), ivec.cend(),
                              bind(greater<int>(), _1, 1024));
    cout << count << endl;

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

    transform(ivec.begin(), ivec.end(), ivec.begin(),   //all numbers multiple 2
                   bind(multiplies<int>(), _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<int> mod;
    auto predicator = [&](int i) { return 0 == mod(input, i); };
    auto is_divisible = any_of(data.begin(), data.end(), predicator);
    cout << (is_divisible ? "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<string>(cp5) << endl;    //C++ Primer 5th
    cout << static_cast<double>(cp5) << endl;	//106.5
#endif
/*14.46*/
#ifdef NUM1446
    cout <<"不应该,这种操作极具误导性,应该把它们声明成explicit的,这样可以防止sales_data"
        " 在默写情况下被默认转换成string或double类型,防止隐式的类型转换。"<<endl;
#endif
/*14.47*/
#ifdef NUM1447
struct Integral {
    operator const int();   // 转换成const int类型,编译器一般忽略,没有意义
    operator int() const;   //转换成int类型时,操作符不会改变对象的状态
};
#endif
/*14.48*/
#ifdef NUM1448
    cout <<"定义bool类型转换的运算符是有用处的,但是必须是explicit,防止自动类型转换。"
#endif
/*14.49*/
#ifdef NUM1449
    Date date(12, 4, 2015);
    if (static_cast<bool>(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.类类型转换. "<<endl;
#endif
/*14.52*/
#ifdef NUM1452
struct LongDouble {
	  LongDouble operator+(const SmallInt&); // 1
};
	LongDouble operator+(LongDouble&, double); // 2
	SmallInt si;
	LongDouble ld;
	ld = si + ld;	//不合法,无论哪个版本,+号两边值都要转换.
	ld = ld + si;	//1精确匹配
#endif
/*14.53*/
#ifdef NUM1453
    SmallInt s1;
    double d = s1 + 3.14;
    ambiguous.
Fixed:
    SmallInt s1;
    double d = s1 + SmallInt(3.14);
    cout<<"内置的operator+(int, double)是可行的,而3.14可以转换为int,然后再转换为SmallInt,所以SmallInt的成员operator+也是可行的。两者都需要进行类型转换,所以会产生二义性。改为:double d = s1 +Smallint(3.14);即可" <<endl;
#endif
	return 0;
}

参考资料:

c++ primer中文版第五版,电子工业出版社。

c++ primer第四版习题解答,人民邮电出版社。

[email protected]://github.com/pezy/CppPrimer

时间: 2024-10-27 13:27:30

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

c++ primer(第五版)学习笔记及习题答案代码版(第十一章)关联容器

笔记较为零散,都是自己不熟悉的知识点. 习题答案至于一个.cc 中,包含Chapter7.h头文件,读入文件包括./test ./rules .需要演示某一题直接修改 #define NUM****, 如运行11.23题为#define NUM1123: chapter 11 1.  关联容器不支持顺序容器的位置相关的操作,例如push_front或push_back.原因是关联容器中元素是根据关键字存储的,这些操作对 关联容器没有意义.而且关联容器也不支持构造函数或插入操作这些接收一个元素值和

c++ primer(第五版)学习笔记及习题答案代码版(第六章)函数

笔记较为零散,都是自己不熟悉的知识点. 习题答案至于一个.cc 中,编译需要包含Chapter6.h头文件. 需要演示某一题直接修改 #define NUM***, 如运行6.23题为#define NUM623: chapter 6 1. 形参初始化的机理与变量初始化一样. 当形参是引用类型时,它对应的实参被引用传递或者函数被传引用调用. 2. const和实参 void fcn(const int i){ /*fcn能够读取i,但是不能向i写值*/} void fcn(int i){ /*.

快学scala 第十一章 操作符 读书笔记及习题答案代码

chapter 11 操作符 标签:快学scala 一.笔记 scala种可以在反引号中包含几乎任何字符序列, val 'val' = 42 所有的操作符都是左结合的,除了以冒号(:)结尾的操作符,和赋值操作符.用于构造列表的::操作符是又结合的.1::2::Ni1的意思是1::(2::Ni1),先创建出包含2的列表,这个列表又被作为尾巴拼接到以1作为头部的列表中. 2. 函数调用语法:f(arg1, arg2,...)扩展到可以应用于函数之外的值,如果f不是函数或方法,那么这个表达式等于f.a

C++primer第十四章 重载操作符与转换

这些标准库的类型具有相同的操作符,使用它们就像使用内置数组和指针一样.允许程序使用表达式而不是命名函数,可以使编写和阅读程序容易得多.将 cout << "The sum of " << v1 << " and " << v2 << " is " << v1 + v2 << endl; 和以下更为冗长的代码相比较就能够看到.如果 IO 使用命名函数,类似下面的代码

C++ Primer 第五版学习笔记

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

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

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

C++ Primer(第五版)学习笔记_5_标准模板库string(2)

C++ Primer(第五版)学习笔记_5_标准模板库string(2) 10.搜索string对象的元素或子串 采用find()方法可查找字符串中的第一个字符元素(char, 用单引号界定)或者子串(用双引号界定):如果查到,则返回下标值(从0开始计数),如果查不到,则返回一个很大的数string:npos(即:4294967295). #include <iostream> #include <stdio.h> #include <string> using nam

C++ Primer(第五版)学习笔记_3_标准模板库vector(2)

C++ Primer(第五版)学习笔记_3_标准模板库vector(2) 欢迎大家阅读参考,如有错误或疑问请留言纠正,谢谢 6.元素的插入 insert()方法可以在vector对象的任意位置前插入一个新的元素,同时,vector自动扩张一个元素空间,插入位置后的所有元素依次向后挪动一个位置. 要注意的是,insert()方法要求插入的位置,是元素的迭代器位置,而不是元素的下标. #include <iostream> #include <vector> using namespa

C++ Primer(第五版)学习笔记_1_标准模板库--快速入门

C++ Primer(第五版)学习笔记_1_标准模板库--快速入门 欢迎大家阅读参考,如有错误或疑问请留言纠正,谢谢 标准模板库(STL)提供三种类型的组件:容器.迭代器和算法,他们都支持泛型程序设计标准. 容器主要有两类:顺序容器和关联容器.顺序容器(vector.list.deque和string等)是一系列元素的有序集合.关联容器(set.multiset.map和multimap)包含查找元素的键值. 迭代器的作用是遍历容器. STL算法库包含四类算法:排序算法.不可变序算法.变序性算法