c++ primer 第14章 习题解答
14.1節
14.1答
不同點:
重載操作符必須具有至少一個class或枚舉類型的操作數。
重載操作符不保證操作數的求值順序,例如對&&和| | 的重載版本不再具有“短路求值”的特征,兩個操作數,兩個操作數都要進行求值,而且不規定操作數的求值順序。
相同點:?
? ? ? ? 對于優先級和結合性及操作數的數目都不變。
14.2 答:
文件sales_data.cc
#include <iostream> #include <string> #include "Sales_data.h" using namespace std; Sales_data operator+(const Sales_data &lhs,const Sales_data &rhs) { Sales_data data = lhs; data += rhs; return data; }Sales_data& Sales_data::operator+=(const Sales_data &s) {this->units_sold += s.units_sold;this->revenue += s.revenue;return *this; }istream & operator>>(istream &is,Sales_data &s) { is >> s.bookNo >> s.units_sold >> s.revenue;return is; } ostream & operator<<(ostream &os,const Sales_data &s) { os << s.bookNo << s.units_sold << s.revenue;return os; }文件? Sales_data.h?
class Sales_data {friend Sales_data operator+(const Sales_data &,const Sales_data &);friend istream & operator>>(istream &is,Sales_data &);friend ostream & operator<<(ostream &os,const Sales_data &);public:Sales_data &operator+=(const Sales_data &);std::string bookNo;unsigned units_sold = 0;double revenue = 0.0; };注意:切記不可在友元函數的前面加Sales_data::,否則編譯器回提示,C++:‘std::ostream& String::operator<<(std::ostream&, const Sales_data &)’ must take exactly one argument
14.3
答:
(a)使用了c++內置版本的const char *版本的 ‘==’運算符。
字符串字面量是 const char* 類型
(b)string類型的"=="運算符
(c)vector類型的"=="運算符
(d)首先const char *類型的"stone"轉換為 string,然后使用string類型的“=="
14.4
答:
(a)%通常定義為非成員,因為可以左右調換
(b)%=會改變自身狀態,成員
(c)++成員
(d)->必須為成員
(e)&&非成員,一般不建議重載(&&和| |重載后,短路求值屬性會失效)
(f)<<非成員,因為左操作數必須是 ostream類型。
(g)==? 一般定義為非成員
(h)()必須為成員,否則編譯器會報錯。
賦值運算符,下標運算符,調用運算符,成員運算符必須是成員運算符,其余沒有強制要求。
14.5
答:
我們以Date類為例,為其定義重載的輸出運算符,輸入運算符可參照實現,顯然,為Date定義輸入輸出運算符,可以讓我們像輸入輸出內置類型對象那樣輸入輸出Date,在易用性和代碼的可讀性上有明顯的好處。因此,定義這兩個重載運算符是合理的。
文件date.h
#ifndef DATE_H #define DATE_H#include <iostream> #include <string> using namespace std; class Date {public:Date(){}Date(int y,int m,int d){year = y;month = m;day = d;}friend ostream & operator<< (ostream &os,const Date &dt);private:int year,month,day; };#endif #include <iostream> #include <string> #include "date.h" using namespace std; ostream & operator<<(ostream & os,const Date &dt) {const char sep = '\t';os << "year:"<< dt.year << sep << "month:"<< dt.month<<sep << "day:"<<dt.day; return os; }int main() {Date d(2021,11,14);cout << d << endl;return 0; }14.2節
14.2.1習題
習題14.6
14.7
/** This file contains code from "C++ Primer, Fifth Edition", by Stanley B.* Lippman, Josee Lajoie, and Barbara E. Moo, and is covered under the* copyright and warranty notices given in that book:* * "Copyright (c) 2013 by Objectwrite, Inc., Josee Lajoie, and Barbara E. Moo."* * * "The authors and publisher have taken care in the preparation of this book,* but make no expressed or implied warranty of any kind and assume no* responsibility for errors or omissions. No liability is assumed for* incidental or consequential damages in connection with or arising out of the* use of the information or programs contained herein."* * Permission is granted for this code to be used for educational purposes in* association with the book, given proper citation if and when posted or* reproduced.Any commercial use of this code requires the explicit written* permission of the publisher, Addison-Wesley Professional, a division of* Pearson Education, Inc. Send your request for permission, stating clearly* what code you would like to use, and in what specific way, to the following* address: * * Pearson Education, Inc.* Rights and Permissions Department* One Lake Street* Upper Saddle River, NJ 07458* Fax: (201) 236-3290 */ #ifndef STRING_H #define STRING_H#include <cstring> #include <algorithm> #include <cstddef> #include <iostream> #include <initializer_list> #include <iostream> #include <memory>class String { friend String operator+(const String&, const String&); friend String add(const String&, const String&); friend std::ostream &print(std::ostream&, const String&); friend std::ostream &operator<<(ostream &os,const String &); public:String() = default;// cp points to a null terminated array, // allocate new memory & copy the arrayString(const char *cp) : sz(std::strlen(cp)), p(a.allocate(sz)){ std::uninitialized_copy(cp, cp + sz, p); }// copy constructor: allocate a new copy of the characters in sString(const String &s):sz(s.sz), p(a.allocate(s.sz)){ std::uninitialized_copy(s.p, s.p + sz , p); }// move constructor: copy the pointer, not the characters, // no memory allocation or deallocationString(String &&s) noexcept : sz(s.size()), p(s.p) { s.p = 0; s.sz = 0; }String(size_t n, char c) : sz(n), p(a.allocate(n)){ std::uninitialized_fill_n(p, sz, c); }// allocates a new copy of the data in the right-hand operand; // deletes the memory used by the left-hand operandString &operator=(const String &);// moves pointers from right- to left-hand operandString &operator=(String &&) noexcept;// unconditionally delete the memory because each String has its own memory~String() noexcept { if (p) a.deallocate(p, sz); }// additional assignment operatorsString &operator=(const char*); // car = "Studebaker"String &operator=(char); // model = 'T'String &operator=(std::initializer_list<char>); // car = {'a', '4'}const char *begin() { return p; }const char *begin() const { return p; }const char *end() { return p + sz; }const char *end() const { return p + sz; }size_t size() const { return sz; }void swap(String &s){ auto tmp = p; p = s.p; s.p = tmp; auto cnt = sz; sz = s.sz; s.sz = cnt; } private:std::size_t sz = 0;char *p = nullptr;static std::allocator<char> a; }; String make_plural(size_t ctr, const String &, const String &); inline void swap(String &s1, String &s2) {s1.swap(s2); }#endif /** This file contains code from "C++ Primer, Fifth Edition", by Stanley B.* Lippman, Josee Lajoie, and Barbara E. Moo, and is covered under the* copyright and warranty notices given in that book:* * "Copyright (c) 2013 by Objectwrite, Inc., Josee Lajoie, and Barbara E. Moo."* * * "The authors and publisher have taken care in the preparation of this book,* but make no expressed or implied warranty of any kind and assume no* responsibility for errors or omissions. No liability is assumed for* incidental or consequential damages in connection with or arising out of the* use of the information or programs contained herein."* * Permission is granted for this code to be used for educational purposes in* association with the book, given proper citation if and when posted or* reproduced.Any commercial use of this code requires the explicit written* permission of the publisher, Addison-Wesley Professional, a division of* Pearson Education, Inc. Send your request for permission, stating clearly* what code you would like to use, and in what specific way, to the following* address: * * Pearson Education, Inc.* Rights and Permissions Department* One Lake Street* Upper Saddle River, NJ 07458* Fax: (201) 236-3290 */ #include <cstring> using std::strlen;#include <algorithm> using std::copy; #include <cstddef> using std::size_t; #include <iostream> using std::ostream; #include <utility> using std::swap;#include <initializer_list> using std::initializer_list;#include <memory> using std::uninitialized_copy;#include "string.h"// define the static allocator member std::allocator<char> String::a;// copy-assignment operator String & String::operator=(const String &rhs) {// copying the right-hand operand before deleting the left handles self-assignmentauto newp = a.allocate(rhs.sz); // copy the underlying string from rhsuninitialized_copy(rhs.p, rhs.p + rhs.sz, newp);if (p)a.deallocate(p, sz); // free the memory used by the left-hand operandp = newp; // p now points to the newly allocated stringsz = rhs.sz; // update the sizereturn *this; }// move assignment operator String & String::operator=(String &&rhs) noexcept {// explicit check for self-assignmentif (this != &rhs) {if (p)a.deallocate(p, sz); // do the work of the destructorp = rhs.p; // take over the old memorysz = rhs.sz;rhs.p = 0; // deleting rhs.p is saferhs.sz = 0;}return *this; }String& String::operator=(const char *cp) {if (p) a.deallocate(p, sz);p = a.allocate(sz = strlen(cp));uninitialized_copy(cp, cp + sz, p);return *this; }String& String::operator=(char c) {if(p) a.deallocate(p, sz);p = a.allocate(sz = 1);*p = c;return *this; }String& String::operator=(initializer_list<char> il) {// no need to check for self-assignmentif (p)a.deallocate(p, sz); // do the work of the destructorp = a.allocate(sz = il.size()); // do the work of the copy constructoruninitialized_copy(il.begin(), il.end(), p);return *this; } // named functions for operators ostream &print(ostream &os, const String &s) {auto p = s.begin();while (p != s.end())os << *p++ ;return os; }String add(const String &lhs, const String &rhs) {String ret;ret.sz = rhs.size() + lhs.size(); // size of the combined Stringret.p = String::a.allocate(ret.sz); // allocate new spaceuninitialized_copy(lhs.begin(), lhs.end(), ret.p); // copy the operandsuninitialized_copy(rhs.begin(), rhs.end(), ret.p + lhs.sz);return ret; // return a copy of the newly created String }// return plural version of word if ctr isn't 1 String make_plural(size_t ctr, const String &word,const String &ending) {return (ctr != 1) ? add(word, ending) : word; }// chapter 14 will explain overloaded operators ostream & operator<<(ostream &os,const String &s) { for(auto ptr = s.begin(); ptr != s.end(); ++ptr)os << *ptr << std::endl; //or can be written: print(os,s)return os; }String operator+(const String &lhs, const String &rhs) {return add(lhs, rhs); }int main() {return 0; }14.8 同練習14.5
14.2.2重載輸入運算符
istream & operator>>(istream &is,Sales_data &s) { double price; is >> s.bookNo >> s.units_sold >> price; if(is)s.revenue = price * s.units_sold; elses = Sales_data(); //input failure,object is set to the default statereturn is; }輸入運算符定義注意事項如下:
1.輸入后要判斷流是否正確,如果正確繼續執行往后的操作
2.如果錯誤,那么把被輸入的對象置為默認狀態。
?
?
?
?習題14.2.2
習題14.9
istream & operator>>(istream &is,Sales_data &s) { double price; is >> s.bookNo >> s.units_sold >> price; if(is)s.revenue = price * s.units_sold; elses = Sales_data(); //input failure,object is set to the default statereturn is; } ostream & operator<<(ostream &os,const Sales_data &s) { os << s.bookNo << s.units_sold << s.revenue;return os; }提示:輸入運算符必須在輸入后立刻判斷流的狀態,如果流失敗(說明讀取數據發生錯誤),那么立刻把被輸入的對象置于默認的狀態。
14.10
(a)參數中傳入的Sales_data 對象將會得到輸入的值,其中BookNo、units_sold、price的值分別是:0-201-99999-9、10、24.95,同時,revenue的值是249.5。
(b)輸入錯誤,參數中傳入的Sales_data對象會得到默認值。
練習14.11
對于上題中的(a)程序將會正常執行,對于(b)程序將會發生錯誤,bookNo得到值10,units_sold得到值24,price得到值0.95,最后revenue得到值revenue = 24 * 0.95。
練習14.12
#include "date.h" #include <string> #include <iostream> using namespace std; istream & operator>>(istream &,Date &); ostream & operator<<(ostream &,const Date &); int main() { Date d; cin >> d; cout << d << endl;return 0; } #ifndef DATE_H_INCLUDE #define DATE_H_INCLUDE #include <string> #include <iostream> using namespace std;class Date {public:Date(){}Date(int y,int m,int d){year = y; month = m; day = d;}friend istream & operator>>(istream &is,Date &dt){is >> dt.year >> dt.month >> dt.day;if(!is){dt = Date(0,0,0); } return is;}friend ostream & operator<<(ostream &os,const Date& dt){os << dt.year << dt.month << dt.day;return os;}private:int year,month,day;};#endif習題14.16
strvec類:
bool operator==(const StrVec &lhs,const StrVec &rhs){ if(lhs.size() == rhs.size()){return false;}for(auto iter1 = lhs.begin(),iter2 = rhs.begin(); iter1 != lhs.end() && iter2 != rhs.end();++ iter1,++iter2){if(*iter1 != *iter2){return false;}return true; } }strblob類:
friend bool operator==(const StrBlob &,const StrBlob &); friend bool operator!=(const StrBlob &,const StrBlob &);bool operator==(const StrBlob & lhs,const StrBlob &rhs) {return lhs.data == rhs.data; } bool operator!=(const StrBlob &lhs,const StrBlob &rhs) {return !(lhs == rhs); }strblobptr類:
bool operator==(const StrBlobPtr &lhs,const StrBlobPtr &rhs) { auto l = lhs.wptr.lock(),r = rhs.wptr.lock(); if(l == r){return (!r || lhs.curr == rhs.curr); }else return false; }? ? ? ?如果一個條件為真時不求另一個表達式的值,一個條件為假時才去求另一個表達式的值,那么用||符號。
習題14.17
bool operator==(const Date &lhs,const Date &rhs) {return lhs.year == rhs.year && lhs.month == rhs.month && lhs.day == rhs.day; }bool operator!=(const Date &lhs,const Date &rhs) {return !(lhs == rhs); }判斷幾個條件是否同時成立,可以使用 && 把這幾個條件連起來。秒。
14.3.2節
練習14.18
? ? ? ?對于Sales_data的==運算符來說,如果兩筆交易的revenue和units_sold成員不同,那么即時他們的ISBN相同也無濟于事,他們仍然是不相同的。如果我們定義的<運算符僅僅比較ISBN成員,那么將發生這樣的情況:兩個ISBN相同但是revenue和units_sold不同的對象經比較是不想等的,但是其中的任何一個都不小于另一個。然而實際情況是,如果我們有兩個對象并且一個都不比另一個小,則從道理上來說這兩個對象應該是相等的。
String比較兩個字符串的字典順序的先后。
這個鏈接有關于String類的實現的一個版本,個人覺得很好
C++ Primer 第三章補充String類的實現
bool operator<(const String &lhs,const String &rhs) {return strcmp(s1.str,s2.str) < 0; } bool operator<=(const String &s1,const String &s2) {return strcmp(s1,s2) <= 0; } bool operator>(const String &s1,const String &s2) {return strcmp(s1,s2)>0; }bool operator>=(const String &s1,const String &s2) {return strcmp(s1,s2)>=0; }比較兩個strblob的大小:
bool operator<(const StrBlob &s1,const StrBlob &s2) {return *s1.data < *s2.data; } bool operator<=(const StrBlob &s1,const StrBlob &s2) {return *s1.data <= *s2.data; } bool operator>(const StrBlob &s1,const StrBlob &s2) {return *s1.data > *s2.data; } bool operator>=(const StrBlob &s1,const StrBlob &s2) {return *s1.data >= *s2.data; }比較兩個strblobptr:
bool operator<(const StrBlobPtr &s1,const StrBlobPtr &s2) { auto l = s1.wptr.lock(), r = s2.wptr.lock(); if(l == r){if(!l)return false; //兩個指針都為空,認為是相等的return s1.curr < s2.curr;} elsereturn false; } bool operator<=(const StrBlobPtr &s1,const StrBlobPtr &s2) { auto l = s1.wptr.lock(), r = s2.wptr.lock(); if(l == r){if(!l) return true;return s1.curr <= s2.curr;} else return false; } bool operator>(const StrBlobPtr &s1,const StrBlobPtr &s2) { auto l = s1.wptr.lock(), r = s2.wptr.lock(); if(l == r){//兩個指針都為空,認為是相等的。if(!r)return false;return (s1.curr > s2.curr);} elsereturn false; } bool operator>=(const StrBlobPtr &s1,const StrBlobPtr &s2) { auto l = s1.wptr.lock(),r = s2.wptr.lock(); if(l == r){return (!r || s1.curr >= s2.curr); //當!r為假時才求解后面的表達式的值} else return false;}要比較兩個strvec,需要手工編寫代碼,逐個比較string。
????????別忘記了,有長短之分。
14.19
在7.40中,我們編寫了類Date,對于日期,可以比較其大小,因此需要為此重載關系運算符。 class Date { ... }; bool operator<(const Date & d1,const Date &d2) { return (d1.year < d2.yera) ||(d1.year == d2.year && d1.month < d2.month) || (d1.year == d2.year && d1.month == d2.month && d1.day < d2.day); } bool operator<=(const Date &d1,const Date &d2) {return d1 == d2 || d1 < d2; } bool operator>(const Date &d1,const Date &d2) {return !(d1 <= d2); } bool operator>=(const Date &d1,const Date &d2) {return !(d1 < d2); }14.4節練習
14.20
+運算符不是成員函數,+=是成員函數:
Sales_data operator+(const Sales_data &rhs,const Sales_data &rhs) {Sales_data sum = lhs;sum += rhs;return sum; } Sales_data & Sales_data::operator+=(const Sales_data &s) {units_sold += s.units_sold;revenue += s.revenue;return *this; }14.21
Sales_data opeartor+(const Sales_data s1,const Sales_data &s2) { Sales_data sum = s1; sum.units_sold += s2.units_sold; sum.revenue += s2.revenue;return sum; } Sales_data & operator+=(const Sales_data s) { *this = *this + s; return *this; }14.22
Sales_data & operator=(const string &s) {bookNo = s;return *this; }14.23
StrVec & operator=(initializer_list<string> li) { auto data = alloc_n_copy(li.begin(),li.end()); free(); elements = data.first; cap = first_free = data.second;return *this; }14.24
例子7.40中曾經選擇并且編寫了一個類,它有3個int類型的數據成員,利用淺拷貝就可以,不需要另外定義拷貝賦值和移動賦值運算符。
14.25
這完全取決于實際的需求,例如,如果你希望能用string形式的日期來初始化Date,就需要定義一個接受string的賦值運算符。
class Date{ public:Date & operate=(const string &date); }; Date & Sales_data::operator=(const string &date){//接受 1971-12-5 類型的日期istringstream in(date);char ch1,ch2;in >> year >> ch1 >> month >> ch2 >> day;if(!in || ch1 != '-' || ch2 != '-')throw invalid_argument("Bad date");if(month < 1 || month > 12 || day < 1 || day > 31)throw invalid_argument(“Bad date”);return *this;}顯然,日期的合法性并不完美,讀者可以自己嘗試改進。
練習14.26:為你的StrBlob類、StrBlobPtr類、StrVec類和String類定義下標運算符。
解:
class StrBlob{public:string &operator[](size_t n){return data[n];}const string & operator[](size_t n)const{return (*data)[n];} }; class StrBlobPtr{ public:string &operator[](size_t n){return (*wptr.lock())[n];}const string &operator[](size_t n)const{return (*wptr.lock()[n]]);}private://..其他成員}; class StrVec{string& operator[](size_t n){return elements[n];}}?以下這個題目自己很不理解。
class String {public:char& operator[](size_t n){return (char)str[n];}private:char *str;}St練習14.27.為了你的StrBlobPtr類添加遞增和遞減運算符。
class StrBlobPtr {public:StrBlobPtr& operator++();StrBlobPtr& operator--();StrBlobPtr operator--(int);StrBlobPtr operator++(int); }; StrBlobPtr& StrBlobPtr::operator++(){check(curr,"increment past end of StrBlobPtr");++ curr;return *this;} StrBlobPtr& StrBlobPtr::operator--(){--curr;check(curr,"increment past end of StrBlobPtr");retutn *this; } StrBlobPtr operator++(int) //后置運算符有個參數int,這是區別后置和前置的一個偽參數,不會用 {StrBlobPtr ret = *this;++ *this;return ret; } //后置的--運算符也有一個int類型運算符 StrBlobPtr operator--(int) {StrBlobPtr ret = *this;-- *this; //這個是調用前置類型的--運算符,檢查也叫給了那個函數。return ret; }? ? ? ? 這個問題要注意,當++時候,先執行check(),因為一個StrBlobPtr對象的curr變量的取值范圍是[0,data.size()],如果先執行++,那么就會出現越界的可能性。所以此時必須要檢查curr是否大于等于data.size(),如果大于等于data.size(),那么應該立刻拋出異常。
? ? ? ? 但是--時候情況不一樣,執行--運算前,curr可能的值范圍是[0,data.size()],做--運算是安全的(除了curr是0的情況)。所以先執行--運算,但是如果curr原來是0,那么執行后curr會是一個超級大的數(curr是size_t也就是unsigned long類型,所以如果原來是0,那么執行減法后會得到超級大的數,肯定會大于data.size(),肯定會check中拋出異常),所以執行++運算時,先check,后執行++,執行--運算時,先執行--運算,然后再check(),這樣是絕對安全的。
?14.28? 為你的StrBlobPtr類添加加法和減法運算符,使其可以實現指針的算數運算。
class StrBlobPtr {StrBlobPtr operator+(int n);StrBlobPtr operator-(int n);//其它成員 }StrBlobPtr StrBlobPtr::operator+(int n){auto ret = *this;ret.curr += n;return ret;}StrBlobPtr StrBlobPtr::operator-(int n){auto ret = *this;ret.curr += n;return ret;}有了上述的兩個函數,就可以執行指針的算數運算了。
練習14.29
? ? ? ? 對于++和--運算符,無論是 hi前綴版本還是后綴版本,都會改變對象本身的值,因此不能定義為const的。
練習14.30
class StrBlobPtr { public:string & operator*(){auto p = check(curr,"deferenced past the end.");return (*p)[curr];}string & operator->()const{return &(this->operator*()); //成員運算符返回解引用運算符的地址。} }; class ConstStrBlobPtr { public:const string & operator*()const{auto p = check(curr,"deference past the end.");return (*p)[curr];}const string*operator->()const{return &(this->operator*());} };到底什么能夠決定返回的引用是加const還是不用加const?
根據這個例子,如果是一個容器類型,那么返回元素的引用到底是否加const,那么取決于這個容器的類型是不是const的。
14.31
對于StrBlobPtr類型,那么它的數據成員有2個:分別是weak_ptr<vector<string>>和size_t類型的,前者定義了自己的拷貝構造函數、賦值運算符和析構函數,后者是內置類型的,因此默認的拷貝語義即可,無須為了StrBlobPtr定義拷貝構造函數、賦值運算符和析構函數。
14.32
定義一個類令其含有指向StrBlobPtr對象的指針,為這個類定義重載的箭頭運算符。
class MyClass {public:string* operator*()const{return ptr->operaotr->();}private:StrBlobPtr *ptr; };14.8節基礎知識
#include <string> #include <iostream> #include <vector> using namespace std; class PrintString {public:PrintString(ostream &o = cout,char c = ' '):os(o),sep(c){}void operator()(const string &s){os << s << sep; }private:ostream &os;char sep;}; int main() { string s = "this is string s..."; PrintString p; p("this is string s..."); PrintString errors(cerr,'\n'); errors(s);return 0; }運行結果:
this is string s... this is string s...14.32
class MyClass {public:string * operator->()const{return ptr->operator->();}private:StrBlobPtr *ptr; }:14.33
0個或者多個。
這里for_each里面放著一個臨時構造的類對象(重載了調用運算符的類又叫函數對象),這個函數對象可以被調用。可以直接放在for_each算法的最后面。
14.33
答:0個或者多個。
14.34
答:
#include <string> #include <iostream> #include <memory> using namespace std; struct Select{public:Select() = default;int operator()(int a,int b,int c){return a ? b : c; }private:};int main() { Select s1; cout << s1(1,2,3) << endl; return 0; }14.35
#include <string> #include <iostream> #include <memory> using namespace std;struct Read{ Read() = default; string operator()(istream &is,string &s){getline(is,s);if(!is)return "";return s; } }; int main() { Read r; string s; string str = r(cin,s); cout << str << endl;return 0; }或者可以這樣寫:
?
總之,類的重載調用運算符函數可以自己帶參數進行相關操作,也可以依靠其它數據成員來進行相關的操作。函數對象類的其它數據成員就是輔助進行相關的調用運算符的操作的。
練習14.36
#include <string> #include <iostream> #include <memory> #include <vector> using namespace std; struct Select{ Select(istream &in = cin):is(in){} vector<string> operator()(){string str;vector<string> v;while(getline(is,str)){v.push_back(str); }return v; } private:istream &is; };int main() {Select s;auto p =s();for(auto &i : p)cout << i << endl; }14.37
#include <string> #include <iostream> #include <memory> #include <algorithm> #include <vector> using namespace std;struct IsEqual{IsEqual() = default;IsEqual(int a):val(a){}bool operator()(int a){return a == val; }int val = 1; };int main() { vector<int> v{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};replace_if(v.begin(),v.end(),IsEqual(),100); for(auto i : v)cout << i << endl;return 0; }調用運算符的例子:
#include <string> #include <iostream> #include <vector> #include <algorithm> using namespace std; class IntComp{public:IntComp(int v):val(v){}bool operator()(int n){return val == n;}private:int val; };int main() {const int old_value = 2; const int new_value = 200; IntComp icmp(old_value); vector<int> v{1,2,3,4,5,67,7,8,9,19}; replace_if(v.begin(),v.end(),IntComp(3),new_value); for(auto i : v)cout << i << endl;return 0; }14.8.1節練習
14.38
自己編寫答案:
#include <string> #include <iostream> #include <algorithm> #include <vector> #include <fstream> #include <sstream> using namespace std; class Stati_word_len{public:Stati_word_len(const string & s):val(s){}//判斷這個對象的長度是否和n相等bool operator()(int n){return n == val.size();}private:string val; };//對于文件流f,統計輸入的單詞中有多少個長度是1,2,3,4,5...10 void stati_words(fstream &f) { string line; size_t lengthes[10] = {0}; int len = 0; while(getline(f,line)){string word;stringstream in(line);while(in >> word){Stati_word_len w(word);for(int i = 1; i != 11; ++i){if(w(i))lengthes[i-1] ++;} } } f.close(); for(auto i = 0; i != sizeof(lengthes) / sizeof(lengthes[0]); ++ i){cout << lengthes[i] << endl; } } int main() {fstream in("data.txt"); stati_words(in);return 0; }參考書的答案:
#include <string> #include <iostream> #include <algorithm> #include <vector> using namespace std; /*比較單詞的長度是否與一個闊值相等*/ class StrLenIs{public:StrLenIs(int len):len(len){}bool operator()(string word){return word.size() == len;}private:int len; };void readStr(istream &is,vector<string> &vs) { string word; while(cin >> word){vs.push_back(word);} }int main() { vector<string> v1; readStr(cin,v1); for(auto i = 1;i != 11; ++ i){cout<< "len "<<i<<":" <<count_if(v1.begin(),v1.end(),StrLenIs(i)) << endl;}return 0; }14.39
#include <string> #include <iostream> #include <memory> #include <fstream> #include <sstream> using namespace std; class StatiWord{public:StatiWord(const string &w):word(w){}size_t operator()(){return word.size();}private:string word; };int main() { fstream in("data.txt"); string line; size_t lengths[10] = {0}; while(getline(in,line)){stringstream s(line);string word;while(s >> word){StatiWord st_1(word);size_t len = st_1();if(len >=1 && len <= 9)lengths[len - 1]++;else lengths[9]++;}} for(auto i : lengths){cout << i <<endl;}return 0; }14.39參考書答案
#include <string> #include <iostream> #include <algorithm> #include <vector> using namespace std; class StrLenBetween{public:StrLenBetween(int min,int max):minLen(min),maxLen(max){}bool operator()(const string &w){return w.size() >= minLen && w.size() <= maxLen; }private:size_t minLen;size_t maxLen; }; class StrNotShorterThan{public:StrNotShorterThan(int s):len(s){}bool operator()(const string &s){return s.size() >= len;}private:size_t len;};int main() { vector<string> v{"str1","str2","str3","str4","str5","str6","str7","str8","12"}; StrLenBetween b1(1,9); StrNotShorterThan b2(10); cout << "length between 1 and 9:" << count_if(v.begin(),v.end(),b1) << endl; cout << "length notshorter than:" << count_if(v.begin(),v.end(),b2) << endl;return 0; } length between 1 and 9:9 length notshorter than:014.40
#include <string> #include <iostream> #include <algorithm> #include <vector> using namespace std;string make_plural(size_t n,const string &s,const string & s1 = "s");class compLen{public:bool operator()(const string &s1,const string &s2){//這里必須<,不能<=,否則stable_sort不起作用//還可能給按照降序排列。return s1.size() < s1.size(); } };class IsLonggerThan{public:IsLonggerThan(int l):sz(l){}bool operator()(const string &s){ return s.size() >= sz;}private:int sz; };class PrintString{public:void operator()(const string &s){cout << s << " ";}};void elimDups(vector<string> &words) { //按字典順序排列words,以便查找重復單詞 sort(words.begin(),words.end()); //unique()重排輸入范圍,是的每個單詞都只出現一次 auto end_unique = unique(words.begin(),words.end()); //使用向量操作erase刪除重復單詞 words.erase(end_unique,words.end()); }void biggies(vector<string> &words,vector<string>::size_type sz) { elimDups(words);//no problems #ifdef DEBUG for(auto i : words)cout << i << endl; #endif//按照長度排序,長度相同的單詞維持字典順序 stable_sort(words.begin(),words.end(),compLen());#ifdef DEBUG2 for(auto i = 0; i != words.size() ; ++i)cout << words[i] << endl; #endif//獲取一個迭代器,指向第一個滿足 size() >=sz的元素 auto wc = find_if(words.begin(),words.end(),IsLonggerThan(sz)); //計算滿足size() >= sz的元素的數目 auto count = words.end() - wc; cout << count << " " << make_plural(count,"word","s") <<" of length " << sz<< " or longer" << endl; //打印長度大于或等于給定值的單詞,每個單詞后面接一個空格 for_each(wc,words.end(),PrintString()); cout << endl;} string make_plural(size_t n,const string &s,const string & s1) {return (n > 1) ? (s + s1) : (s); }int main() { vector<string> v = {"asdafasdf","gr","lmjhjk","hjoi","adff","bnmijdf","bnmtsdf","kklsd","xaf","ywlaijsdf","xafd"}; biggies(v,5);return 0; j}14.41
在c++11中,lambda是通過匿名的函數對象來實現的,因此我們可以把lambda看作是對函數對象在使用方式上的簡化。
? ? ? ? 當代碼需要一個簡單的函數,并;且這個函數并不會在其它地方使用的時候,我們就可以使用lambda來實現,此時它所起的作用類似匿名函數。
? ? ? ? 但如果這個函數需要多次使用,并且他需要存放某些狀態的話,使用函數對象則更合適一些。
14.8.2節基礎知識
14.42(a)
#include <string> #include <iostream> #include <algorithm> #include <functional> #include <vector> using namespace std; using namespace std::placeholders; int main() { vector<int> v{12,3,12345,12,15433,123,123111}; auto sum = count_if(v.begin(),v.end(),bind(greater<int>(),_1,1024)); cout << sum << endl;return 0; }提示:bind定義在頭文件functional中
占位符,_1定義在頭文件functional中,定義在命名空間std::spaceholders中,spaceholders中。
因此要使用bind和_1,必須程序中加:
?
?14.42(b)
#include <string> #include <iostream> #include <vector> #include <algorithm> #include <functional> using namespace std; using namespace std::placeholders; int main() { vector<string> v{"pooth","pooth","abd","abdf","abg","abasdfasdfk","asdfjkasd"}; auto ojb_find = bind(not_equal_to<string>(),_1,"pooth"); auto pos = find_if(v.begin(),v.end(),ojb_find); cout << *pos << endl;return 0; }14.42(c)
#include <string> #include <functional> #include <iostream> #include <vector> #include <algorithm> using namespace std; using namespace std::placeholders;int main() { vector<int> v{1,2,3,4,5,6,7,8,9,10}; transform(v.begin(),v.end(),v.begin(),bind(multiplies<int>(),_1,2)); for(auto i : v)cout << i << endl;return 0; }能不能用for_each?for_each能否改變原來的元素?
14.8.3
#include <string> #include <iostream> #include <memory> #include <functional> #include <map> using namespace std; using namespace std::placeholders; int add(int i,int j){ return i + j;} struct Mod{ int operator()(int i,int j){return i % j;} };struct divide{ double operator()(int i,int j){return (double)i / j;} };int main() { function<int(int,int)> f = add; function<int(int,int)> f1 = Mod(); function<int(int,int)> f2 = [](int i,int j){ return i % j;}; cout << f(4,2) << endl; cout << f1(4,2) << endl; cout << f2(4,2) << endl;map<string,function<int(int,int)>> binops { {"+",add}, {"-",std::minus<int>()}, {"*",[](int i ,int j){return i * j;}}, {"/",divide()}, {"%",Mod()} };binops["+"](1,2); //call add(1,2) binops["-"](2,1); //call minus(2,1) binops["*"](2,1); //call multiplies(2,1) binops["/"](2,1); //call divide(2,1) binops["%"](2,1); //call Mod(2,1)return 0; }?練習14.44
#include <string> #include <iostream> #include <algorithm> #include <functional> #include <map> using namespace std; using namespace std::placeholders;int main() { map<string,function<int(int,int)>> binOps = {{"+",std::plus<int>()},{"-",std::minus<int>()},{"*",std::multiplies<int>()},{"/",std::divides<int>()},{"%",std::modulus<int>()} };int i,j; string ops; cin >> i >> ops >> j; cout << binOps[ops](i,j) <<endl;return 0; }14.45
轉換成string返回值應該是bookNO;
如果要轉換成double,返回值是revenue;
14.46
答:
不該;因為Sales_data有三個數據成員,分別是bookNo,revenue和units_sold。三個運算符在一起才有意義。
? ? ? ? 但是如果確實需要定義這兩個運算符的話,那么應該把他們申明稱為explicit的,這樣可以防止Sales_data在某些情況下被默認轉換成string或者double類型的,這樣可能導致我們意料之外的運算結果。
14.47
答:
第一個轉換成const int類型,第二個轉換成int類型。
14.48
答:
我們應該為Date類型定義一個類型轉換運算符,用來檢查3個數據成員是否都是有效值(比如month是否是1~12之間,day是否超出了當月的天數)。
? ? ? ? bool類型轉換運算符應該聲明為explicit的,因為哦我們有意要在條件表達式中使用他們。
14.48
答:
class Date{ //其它成員函數... explicit operator bool(){return month >= 1 && month <=12 && }};14.49
class Date{ public: explicit operator bool(){ vector<vector<int>> days_per_month = {{31,28,31,30,31,30,31,31,30,31,30,31},{31,29,31,30,31,30,31,31,30,31,30,31}}; } operator bool(){ return (month >=1 && month <= 12 && ( day >= 1 && day <= days_per_month[isLeapYear() ? 1:0][month-1] )) }bool isLeapYear() {return (year % 4 == 0 && year % 400 !=0 || year % 400 ==0) } };14.9.2
總結
以上是生活随笔為你收集整理的c++ primer 第14章 习题解答的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: win环境下安装python之matpl
- 下一篇: s3c2440移植MQTT