C++ primer 14章习题答案
14.1節(jié)
練習(xí)14.1
相同點(diǎn):對(duì)于優(yōu)先級(jí)和結(jié)合型以及操作數(shù)的數(shù)目都不變。
不同點(diǎn):重載操作符必須具有至少一個(gè)class或枚舉類(lèi)型的操作數(shù)。
14.2
下面所有的代碼行可能把好幾個(gè)文件放在一起了。
//sales_data.h#ifndef SALES_DATA_H #define SALES_DATA_H #include <string> #include <iostream> using namespace std; class Sales_data {friend void print(ostream &os,Sales_data rhs);friend istream& operator>>(istream &,Sales_data &rhs);friend ostream& operator<<(ostream &,const Sales_data &rhs);public:Sales_data() = default;Sales_data(const string &s):bookno(s){}Sales_data(const string &s,unsigned n,double r):bookno(s),cnt(n),revenue(r){}Sales_data(istream &is);const string & isbn()const{return bookno;} Sales_data operator+(const Sales_data &rhs);Sales_data &operator+=(const Sales_data &rhs);private:unsigned cnt = 0;double revenue = 0.0;string bookno; }; void print(ostream &os,Sales_data rhs); istream& operator>>(istream &,const Sales_data &rhs); ostream& operator<<(ostream &,const Sales_data &rhs); #endif//functions.cc #include <string> #include <iostream> #include "sales_data.h" using namespace std;Sales_data & Sales_data::operator+=(const Sales_data &rhs) { if(this->bookno != rhs.bookno)throw runtime_error("Not same type."); this->revenue += rhs.revenue; this->cnt += rhs.cnt;return *this; } Sales_data Sales_data::operator+(const Sales_data &rhs) { if(this->bookno != rhs.bookno)throw runtime_error("Not the same type."); Sales_data data; data.bookno = rhs.bookno; data.revenue = this->revenue + rhs.revenue; data.cnt = this->cnt + rhs.cnt;return data; } void print(ostream &os,Sales_data rhs) { os <<"bookno:"<<rhs.bookno << endl; os << "\trevenue:" << rhs.revenue << endl; os << "\tcnt:" << rhs.cnt << endl; }istream& operator>>(istream &is,Sales_data &rhs) { is >> rhs.bookno >> rhs.cnt >> rhs.revenue; return is; } ostream& operator<<(ostream &os,const Sales_data &rhs) { os << rhs.bookno << rhs.cnt << rhs.revenue; return os; }//main.cc #include <string> #include <iostream> #include "sales_data.h" using namespace std; int main() { Sales_data s1("book1",12,120); Sales_data s2("book1",12,130); s1 += s2; Sales_data s3 = s1 + s2; print(cout,s1); print(cout,s3); cout << "輸入s1:" << endl; cin >> s1; cout << s1 << endl;return 0; } bookno:book1revenue:250cnt:24 bookno:book1revenue:380cnt:36 輸入s1: isbnabcdefg 12 120 isbnabcdefg1212014.2
(a) 應(yīng)用了c++內(nèi)置版本的==,比較兩個(gè)指針。
(b)應(yīng)用了svec1[1] == svec2[0] 應(yīng)用了string版本的重載==。
(c)應(yīng)用了svec1 == svec2 應(yīng)用了vector版本的重載==。
(d)svec1[0] == "stone"應(yīng)用了 string版本的重載==,字符串字面知被轉(zhuǎn)換為string。
14.3
答:
(a)%通常定義飛成員
(b)%=通常定義為成員,因?yàn)闀?huì)改變對(duì)象的狀態(tài)
(c)++通常定義為類(lèi)成員,因?yàn)樗鼤?huì)改變對(duì)象的狀態(tài)。
(d)->必須定義為成員否則,否則編譯器會(huì)報(bào)錯(cuò)。
(e)<<通常定義非成員。因?yàn)樽霾僮鲾?shù)為輸出流,如果定義成成員,那就不符合<<的本來(lái)內(nèi)置習(xí)慣。
(f)&&通常是定義成非成員
(g)==通常定義為非成員(操作符具有對(duì)稱(chēng)性一般定義為非成員,這樣才可以必要時(shí)候轉(zhuǎn)換,成員不能轉(zhuǎn)換,左邊操作數(shù)是確定的)
(h)()必須定義為成員,否則編譯器會(huì)報(bào)錯(cuò)。
總結(jié):
賦值=、下標(biāo)[]、成員->、成員()這四個(gè)是必須定義成成員函數(shù)的。
復(fù)合的運(yùn)算符一般定義成成員,但是不是必須。
改變對(duì)象狀態(tài)的運(yùn)算符(++,--)或者和對(duì)象有密切關(guān)系的運(yùn)算符應(yīng)該定義成成員函數(shù),例如遞增遞減和解引用。
具有對(duì)稱(chēng)運(yùn)算的運(yùn)算符可能轉(zhuǎn)換任意一端的運(yùn)算對(duì)象,例如算數(shù)、關(guān)系、相等性和位運(yùn)算符要定義成非成員運(yùn)算符。
14.7
類(lèi)內(nèi)聲明
friend ostream & operator<<(ostream & ,const String &rhs);類(lèi)外聲明:
ostream & operator<<(ostream & ,const String &rhs);最后源文件中定義:
ostream & operator<<(ostream &os,const String &rhs) { for(auto p = rhs.elements; p != rhs.first_free; ++p){os << *p; }return os; }補(bǔ)充和理解:
這里定義==和!=一定注意,如果類(lèi)中有唯一一個(gè)動(dòng)態(tài)內(nèi)存,比如說(shuō)strblobptr,當(dāng)wptr都非空時(shí)候才比較curr,如果wptr都空時(shí)不必比較curr。也就是含有動(dòng)態(tài)內(nèi)存的類(lèi),比較的時(shí)候可能變量要分級(jí)對(duì)待(分級(jí)是我自己發(fā)明的說(shuō)話,也就是說(shuō)當(dāng)內(nèi)存都是nullptr時(shí)候,不必比較其它變量,也就是變量中間有級(jí)別的有限性,某些情況下,某個(gè)或者某些變量不必參與比較)。
14.2.2
14.3
14.3.1練習(xí)答案,這個(gè)答案產(chǎn)生一個(gè)疑問(wèn)?兩個(gè)StrBlob相等,到底是應(yīng)該是data內(nèi)的內(nèi)容相等?還是data應(yīng)該指向同一個(gè)vector?答案是比較了StrBlob的data的
bool operator==(const StrBlob & lhs,const StrBlob &rhs) {return (*(lhs.data) == *(rhs.data)); }14.3.2節(jié)練習(xí)
14.18
friend聲明和函數(shù)原型聲明就略去了。看下面的定義:
//strblob.h中的bool operator==(const StrBlob &lhs,const StrBlob & rhs) {return lhs.data == rhs.data; } bool operator<(const StrBlob &lhs,const StrBlob &rhs) {return *(lhs.data) < *(rhs.data);} bool operator>(const StrBlob &lhs,const StrBlob &rhs) {return *(lhs.data) > *(rhs.data);}bool operator<=(const StrBlob &lhs,const StrBlob &rhs) { return *(lhs.data) <= *(rhs.data);} bool operator>=(const StrBlob &lhs,const StrBlob &rhs) { return *(lhs.data) >=*(rhs.data);}說(shuō)明:就是比較兩個(gè)strblob對(duì)象是否指向同一個(gè)data,如果是則正確,如果否,那么不想等。
(1)這里是lhs.data如果和rhs.data相等的時(shí)候,那么 strblob對(duì)象相等,也就是data必須是同一個(gè)shared_ptr,也就是說(shuō)data必須是指向同一個(gè)對(duì)象的兩個(gè)對(duì)象才能相等。這里不是通常內(nèi)容代數(shù)上相等的含義,通常代數(shù)上相等的含義,比如:
(2)如果==和!=已經(jīng)定義了一個(gè),那么另一個(gè)用這個(gè)來(lái)定義。性能沒(méi)有提高,但是代碼的利用率提高了。
vector<int> v1{1,2,3,4},v2{1,2,3,4};而是,兩個(gè)data的值是否相等。
strblobptr類(lèi):
bool operator== (const StrBlobPtr &lhs,const StrBlobPtr &rhs) { if(lhs.wptr.lock() == rhs.wptr.lock()){//在某個(gè)條件成立時(shí)候返回真//在這個(gè)條件不成立時(shí),才求另一個(gè)條件的值(用 || )return !lhs.wptr.lock() || lhs.curr == rhs.curr;} else{return false; }} bool operator!= (const StrBlobPtr &lhs,const StrBlobPtr &rhs) {return !(lhs == rhs); }bool operator> (const StrBlobPtr &lhs,const StrBlobPtr &rhs) {return *(lhs.wptr.lock()) > *(rhs.wptr.lock()); } bool operator< (const StrBlobPtr &lhs,const StrBlobPtr &rhs) {return *(lhs.wptr.lock()) < *(rhs.wptr.lock()); } bool operator>= (const StrBlobPtr&,const StrBlobPtr&) {return *(lhs.wptr.lock()) >= *(rhs.wptr.lock()); } bool operator<= (const StrBlobPtr &lhs,const StrBlobPtr &rhs) {return *(lhs.wptr.lock()) <= *(rhs.wptr.lock()); }這里含有動(dòng)態(tài)內(nèi)存,動(dòng)態(tài)內(nèi)存wptr和變量,如果在動(dòng)態(tài)內(nèi)存wptr為空的時(shí)候(兩個(gè)動(dòng)態(tài)內(nèi)存相等的情況下),比較curr的大小是無(wú)意義的。所以這里wptr和curr不是同一個(gè)級(jí)別的變量。作用的大小也是不對(duì)等的。
注意:這里判斷兩個(gè)對(duì)象相等的時(shí)候,當(dāng)
(1)兩個(gè)對(duì)象的wptr指針都為空
(2)兩個(gè)對(duì)象指向的對(duì)象相同且非空,且curr相等時(shí)。
這個(gè)問(wèn)題存在這樣一個(gè)現(xiàn)象,當(dāng)兩個(gè)wptr都為空時(shí)候,不用求解curr值(對(duì)象相等或者不想等和curr沒(méi)有關(guān)系)。
那么這個(gè)時(shí)候,正好可以用關(guān)系運(yùn)算符 ||的短路求值特性去寫(xiě)代碼。(!wptr.lock() || lhs.curr == rhs.curr)。
同時(shí),strblobptr對(duì)象的==定義和strblob對(duì)象的==的定義是邏輯上等價(jià)的,都是必須指針指向同一個(gè)對(duì)象才得到兩個(gè)對(duì)象相等(而不是兩個(gè)對(duì)象的內(nèi)容完全相等)。
string.h
bool operator==(const String &lhs,const String &rhs) { if(lhs.size() != rhs.size())return false;for(auto ptr1 = lhs.begin(),ptr2 = rhs.begin();ptr1 != lhs.end() && ptr2 != rhs.end(); ++ ptr1,++ptr2){if(*ptr1 != *ptr2)return false; } return true; } bool operator!=(const String &lhs,const String &rhs) {return !(lhs == rhs); }//下面這段代碼是可以簡(jiǎn)化的,可以簡(jiǎn)化為: /******************************************************************************* bool operator>(const String &lhs,const String &rhs) {return strcmp(lhs.str,rhs.str) > 0; } ********************************************************************************/ bool operator>(const String &lhs,const String &rhs) { auto p1 = lhs.begin(),p2 = rhs.begin(); for(;p1 != lhs.end() && p2 != rhs.end(); ++ p1,++ p2){if(*p1 > *p2)return true;else if(*p1 < *p2)return false;} if(p1 == lhs.end())return false;return true; }下面這個(gè)函數(shù)也可以簡(jiǎn)化為下面的形式: /******************************************************************************* bool operator<(const String &lhs,const String &rhs) {return strcmp(lhs.str,rhs.str) < 0; } ********************************************************************************/bool operator<(const String &lhs,const String &rhs) { auto p1 = lhs.begin(),p2 = rhs.begin(); for(;p1 != lhs.end() && p2 != rhs.end();++ p1,++ p2){if(*p1 < *p2)return true;else if(*p1 > *p2)return false; } if(p2 == rhs.end())return false; return true; } bool operator>=(const String &lhs,const String &rhs) { return !(lhs < rhs);} bool operator<=(const String &lhs,const String &rhs) {return !(lhs > rhs); }上面的每個(gè)函數(shù)都可以利用strcmp() >0 或者 strcmp() < 0?? 或者 strcmp() == 0 來(lái)簡(jiǎn)化原來(lái)的函數(shù)。
strvec.h
bool operator==(const StrVec &lhs,const StrVec &rhs) { if(lhs.size() != rhs.size())return false; for(auto ptr1 = lhs.begin(),ptr2 = rhs.begin();ptr1 != lhs.end() && ptr2 != rhs.end(); ++ ptr1,++ ptr2){if(*ptr1 != *ptr2)return false;} return true; } bool operator!=(const StrVec &lhs,const StrVec &rhs) {return !(lhs == rhs); } bool operator>=(const StrVec &lhs,const StrVec &rhs) { for(auto ptr1 = lhs.begin(),ptr2 = rhs.begin(); ptr1 != lhs.end(),ptr2 != rhs.end(); ++ ptr1,++ ptr2){if(*ptr1 > *ptr2)return true;else if(*ptr1 < *ptr2)return false;} if(lhs.size() >= lhs.size()) //or can:if(ptr2 == rhs.end()) return true;return false;return true; elsereturn false; } bool operator<=(const StrVec &lhs,const StrVec &rhs) { auto p1 = lhs.begin(),p2 = rhs.begin(); for( ;p1 != lhs.end(),p2 != rhs.end(); ++ p1,++ p2){if(*p1 < *p2)return true; else if(*p1 > *p2)return false; } //到這里說(shuō)明前面所有部分相等 if(p1 == lhs.end())return true; return false; } bool operator>(const StrVec &lhs,const StrVec &rhs) {return !(lhs <= rhs); }bool operator<(const StrVec &lhs,const StrVec &rhs) { return !(lhs >= rhs); }strvec比較==邏輯規(guī)則:
首先當(dāng)size()不等的時(shí)候,馬上得到不想等。?
逐個(gè)比較兩個(gè)對(duì)象的數(shù)據(jù),如果出現(xiàn)不想等的對(duì)象,那么返回false
返回true.
這個(gè)算法其實(shí)是把比較的結(jié)果分成了3種情況。
strblob和strblobptr對(duì)象:
bool operator==(const StrBlob &lhs,const StrBlob & rhs) {return lhs.data == rhs.data; } bool operator<(const StrBlob &lhs,const StrBlob &rhs) {return *(lhs.data) < *(rhs.data);} bool operator>(const StrBlob &lhs,const StrBlob &rhs) {return *(lhs.data) > *(rhs.data); //這里兩個(gè)()不加也可以.比*要優(yōu)先 }bool operator<=(const StrBlob &lhs,const StrBlob &rhs) { return *(lhs.data) <= *(rhs.data);} bool operator>=(const StrBlob &lhs,const StrBlob &rhs) { return *(lhs.data) >=*(rhs.data);} bool operator== (const StrBlobPtr &lhs,const StrBlobPtr &rhs) { if(lhs.wptr.lock() == rhs.wptr.lock()){//在某個(gè)條件成立時(shí)候返回真//在這個(gè)條件不成立時(shí),才求另一個(gè)條件的值(用 || )return !lhs.wptr.lock() || lhs.curr == rhs.curr;} else{return false; }} bool operator!= (const StrBlobPtr &lhs,const StrBlobPtr &rhs) {return !(lhs == rhs); }bool operator> (const StrBlobPtr &lhs,const StrBlobPtr &rhs) {return *(lhs.wptr.lock()) > *(rhs.wptr.lock()); } bool operator< (const StrBlobPtr &lhs,const StrBlobPtr &rhs) {return *(lhs.wptr.lock()) < *(rhs.wptr.lock()); } bool operator>= (const StrBlobPtr&,const StrBlobPtr&) {return *(lhs.wptr.lock()) >= *(rhs.wptr.lock()); } bool operator<= (const StrBlobPtr &lhs,const StrBlobPtr &rhs) {return *(lhs.wptr.lock()) <= *(rhs.wptr.lock()); }總結(jié):
一、定義==運(yùn)算和!=運(yùn)算注意:
(1)如果有動(dòng)態(tài)指針,比較智能指針的原則是兩個(gè)指針是否指向同一個(gè)對(duì)象。shared_ptr和weak_ptr都是如此。
? (2)如果一個(gè)對(duì)象有動(dòng)態(tài)內(nèi)存和其他數(shù)據(jù),可能需要分級(jí)對(duì)待。比較時(shí)候,首先看動(dòng)態(tài)內(nèi)存是否非空。
如果動(dòng)態(tài)內(nèi)存空,則不比較另外其他數(shù)據(jù)。
如果動(dòng)態(tài)內(nèi)存為空,則才需要比較其它數(shù)據(jù)。
(3)如果是allocator對(duì)象分配的內(nèi)存,那么逐個(gè)比較每個(gè)數(shù)據(jù)即可。
二、定義>、<、>=、 <=時(shí)候得到的結(jié)論:
(1)答案中是利用strcmp(lhs.str,rhs.str),來(lái)比較的。但是自己在g++編譯器中,編譯器提示string對(duì)象沒(méi)有str成員。所以,自己改成了利用c_str()成員函數(shù):
strcmp(lhs.c_str(),rhs.c_str())來(lái)比較,==得到結(jié)果0,大于得到結(jié)果正數(shù),小于得到結(jié)果負(fù)數(shù)。
(2)兩個(gè)strblob對(duì)象比較是否相等時(shí)候,是比較兩個(gè)data是否相等(指針本身是否相等)。而>、<、>=、<=四個(gè)運(yùn)算符是指的兩個(gè)字符串的大小關(guān)系。也就是兩個(gè)vector的大小關(guān)系。
(3)比較兩個(gè)strblobptr時(shí)候,兩個(gè)對(duì)象wptr必須指向同一個(gè)vector,否則沒(méi)有比較的意義,具體看答案如下:
(3)
14.4節(jié)練習(xí)
14.20
關(guān)于這些函數(shù)的友元聲明和原型聲明就省略了。
Sales_data operator+(const Sales_data &lhs ,const Sales_data &rhs) { auto data = lhs; data += rhs; return data; } Sales_data operator-(const Sales_data &lhs,const Sales_data &rhs) { auto data = lhs; data.revenue -= rhs.revenue; data.cnt -= rhs.cnt;return data; }14.21
我自己覺(jué)得應(yīng)該如下書(shū)寫(xiě):
Sales_data operator+(const Sales_data &lhs ,const Sales_data &rhs) { auto data = lhs; data.revenue += rhs.revenue; data.cnt += rhs.cnt; return data; } Sales_data & Sales_data::operator+=(const Sales_data &rhs) {*this = *this + rhs;return *this; }由此可見(jiàn),上面的書(shū)寫(xiě)方式,性能上沒(méi)有任何優(yōu)勢(shì),但是代碼難閱讀。
我找到了這個(gè)題答案書(shū)上寫(xiě)的答案:
?在operator+=函數(shù)中,顯然返回值是Sales_data &,但是這里卻沒(méi)有用return語(yǔ)句返回一個(gè)值,顯然錯(cuò)誤。即使我們知道*this = (*this) + rhs,其實(shí)已經(jīng)可以改變左側(cè)運(yùn)算對(duì)象,但是仍然需要一個(gè)返回值的。
14.22
Sales_data& Sales_data::operator=(const Sales_data &rhs) {bookno = rhs.bookno;revenue = rhs.revenue;cnt = rhs.cnt;return *this; } Sales_data &Sales_data::operator=(const string & s) {bookno = s;revenue = 0;cnt = 0;return *this; }有第二個(gè)賦值運(yùn)算符,就可以把string對(duì)象(或者能轉(zhuǎn)化為string的字符串字面值)賦值給sales_data對(duì)象了。
14.23
類(lèi)內(nèi)聲明省去了
StrVec::StrVec(initializer_list<string> li) { auto data = allocate_n_copy(li.begin(),li.end()); elements = data.first; first_free = cap = data.second; }14.24
#include <string> #include <iostream> #include "date.h" using namespace std; int main() {return 0; } #include <string> #include <iostream> #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 <<endl;return os; }Date::Date() = default;istream & operator>>(istream &is,Date &dt) { is >> dt.year >> dt.month >> dt.day; if(!is){dt = Date();}return is;}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); } #include <string> #include <iostream> using namespace std; class Date; class Date {friend ostream &operator <<(ostream &os,const Date &dt);friend istream &operator >>(istream &is,Date &dt);friend bool operator==(const Date &lhs,const Date &rhs);friend bool operator!=(const Date &lhs,const Date &rhs);public:Date();Date(int y,int m,int d){year = y ;month = m;day = d;}private:int year;int month;int day; }; ostream &operator <<(ostream &os,const Date &dt); istream &operator >>(istream &is,Date &dt); bool operator==(const Date &lhs,const Date &rhs); bool operator!=(const Date &lhs,const Date &rhs);?14.5節(jié)
習(xí)題14.26
Date & Date::operator=(const string &date) { istringstream is(date); char ch1,ch2; is >> year >> ch1 >> month >> ch2 >> day; if(!is || ch1 != '-' || ch2 != '-' )throw invalid_argument("Bad date"); if(month < 1 || month > 12 || day < 1 || day > 21)throw invalid_argument("Bad date"); return *this; }?
string &StrBlob::operator[](size_t n) {return (*data)[n];} const string &StrBlob::operator[](size_t n)const {return (*data)[n]; }string &StrBlobPtr::operator[](size_t n) { return (*wptr.lock())[n];} const string &StrBlobPtr::operator[](size_t n)const {return (*wptr.lock())[n]; }總結(jié)
以上是生活随笔為你收集整理的C++ primer 14章习题答案的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: (学习c++primer5th的重要)c
- 下一篇: c++primer书上习题date类的部