日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > c/c++ >内容正文

c/c++

c++primer 5th第15章基础、课后习题自己解析、心得体会等

發(fā)布時(shí)間:2024/4/18 c/c++ 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 c++primer 5th第15章基础、课后习题自己解析、心得体会等 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

先看一個(gè)例子:

#include <string> #include <memory> #include <iostream> using namespace std; class A{private:int * d;size_t * use_count;public:A(int n):d(new int(n)),use_count(new size_t(1)){}A(const A & a):d(a.d),use_count(a.use_count){++ * use_count;}A& operator=(const A& a){++ *(a.use_count);if(-- *use_count == 0){delete use_count;delete d; }use_count = a.use_count;d = a.d; return *this;}~A(){if(--*use_count == 0){delete use_count;delete d;}use_count = nullptr;d = nullptr;}void ret_use(){cout << *use_count << endl;}};int main() { A a(1234); a.ret_use(); A b(a); a.ret_use(); b.ret_use(); A *c = new A(a); c->ret_use(); a.ret_use(); b.ret_use();return 0; }

運(yùn)行結(jié)果:?

1 2 2 3 3 3

結(jié)論:new 動(dòng)態(tài)分配對(duì)象和普通對(duì)象調(diào)用的拷貝構(gòu)造函數(shù)成員或者構(gòu)造函數(shù)完全一致。不過(guò)就是存儲(chǔ)的方式不同罷了。創(chuàng)建對(duì)象所調(diào)用的那些函數(shù)(構(gòu)造函數(shù)是一樣樣的)。?

delete 一個(gè)指類類型的動(dòng)態(tài)類型指針會(huì)發(fā)生什么??

class Quote{ public:std::string isbn() const;virtual double new_price(size_t n) const; }; class Bulk_quote : public Quote { public:double net_price(size_t )const override; };

虛函數(shù):對(duì)于基類的某些函數(shù),基類希望它的派生類能各自定義適合自己的版本,此時(shí)基類就將這些函數(shù)聲明成虛函數(shù)(virtual function)。

訪問(wèn)說(shuō)明符:比如private,public,protected;

override:c++11允許派生類顯式地注明它使用哪個(gè)成員函數(shù)改寫基類的虛函數(shù),具體措施是在該類的形參列表之后增加一個(gè)override關(guān)鍵字。override位于&,const,等之后。

動(dòng)態(tài)綁定:當(dāng)通過(guò)一個(gè)基類的指針或者引用調(diào)用一個(gè)虛函數(shù)時(shí)候,這個(gè)虛函數(shù)會(huì)根據(jù)調(diào)用的實(shí)際對(duì)象類型選擇使用對(duì)應(yīng)的版本,這個(gè)過(guò)程叫做動(dòng)態(tài)綁定。因?yàn)槭窃谶\(yùn)行時(shí)選擇函數(shù)的版本,所以動(dòng)態(tài)綁定又叫做運(yùn)行時(shí)綁定

訪問(wèn)控制與繼承:繼承類的成員函數(shù)可以直接訪問(wèn)基類的public成員和protected成員,但是不能直接訪問(wèn)基類的private成員。

習(xí)題15.2.1練習(xí)

練習(xí)15.1

答:類中被聲明為virtual的成員,基類希望這種成員在派生類中重新定義。除了構(gòu)造函數(shù)外,任意非static成員都可以定義為虛成員。

練習(xí)15.2

答:protected是受保護(hù)的成員,可以被該類的成員、友元和派生類成員(非友元)訪問(wèn),而不可以被該類的普通用戶訪問(wèn)。而private成員只能被基類的友元和成員訪問(wèn),不能被派生類訪問(wèn)。

練習(xí)15.3

答:

定義你自己的quote類和print_total成員函數(shù)。

15.4

b對(duì),a,c錯(cuò)誤。

15.5
答:

15.6

class Bulk_quote : public Quote //Bulk_quote derived from Quote { public:Bulk_quote() = default;Bulk_quote(const string &,double,size_t ,double);//覆蓋基類的版本以實(shí)現(xiàn)大量購(gòu)買的折扣和政策double net_price(size_t n)const override; //override:顯式地用這個(gè)成員函數(shù)改寫基類的虛函數(shù)} private:size_t min_qty;double discount = 0.0;};

15.7

class Limitted_quote: public Quote {public:double net_price(size_t cnt)const override{if(cnt <= min_qty){return cnt * (1 - discount) * price; }elsereturn min_qty * (1-discount)*price + (cnt - min_qty) * price; }private:size_t min_qty;double discount;};

15.8

靜態(tài)類型:變量聲明的類型或者表達(dá)式生成的類型,靜態(tài)類型在編譯期就已經(jīng)決定了。動(dòng)態(tài)類型:變量或者表達(dá)式表示的內(nèi)存中的對(duì)象的類型,動(dòng)態(tài)類型直到運(yùn)行時(shí)才能知道。如 Quote * pQuote =

new Bulk_quote;指針pQuote的靜態(tài)類型是Quote,而動(dòng)態(tài)類型是Bulk_quote,直到運(yùn)行時(shí)才能知道它指向的類型是基類還是派生類。如果一個(gè)變量非指針也非引用,則它的靜態(tài)類型和動(dòng)態(tài)類型永遠(yuǎn)一致,但基類的指針或者引用的動(dòng)態(tài)類型可能與其靜態(tài)類型不一致。
?

15.9

當(dāng)一個(gè)對(duì)象是非指針也非引用,靜態(tài)類型和動(dòng)態(tài)類型永遠(yuǎn)一致。當(dāng)給基類對(duì)象的指針或者引用賦值或者初始化時(shí),靜態(tài)類型和動(dòng)態(tài)類型可能不一致。

Bulk_quote bulk; Quote * pQuote = & bulk; Quote & rQuote = bulk; 傳遞給item的如果是派生類對(duì)象,即是靜態(tài)類型和動(dòng)態(tài)類型不同的情況。 double print_total(ostream &os,const Quote &item,size_t n);

15.10

可能傳遞給iostream對(duì)象,也可以傳遞派生類對(duì)象,比如fstream對(duì)象。

15.3虛函數(shù)

習(xí)題15.11

void Quote::debug_1()const { cout << "bookNo:" << bookNo << endl; cout << "price:" << price << endl; }void Bulk_quote::debug_1()const { cout << "min_qty:" << min_qty << endl; cout << "discount:" << discount << endl; }

15.12

有必要

override:c++11新標(biāo)準(zhǔn)中我們可以使用override關(guān)鍵字來(lái)說(shuō)明派生類中的虛函數(shù),這么做的好處是使得我們的意圖更加清洗即明確地告訴編譯器我們想要覆蓋已存在的虛函數(shù)。如果定義個(gè)了函數(shù)與基類中的名字相同但是形參列表不同,在不使用override關(guān)鍵字的時(shí)候這種函數(shù)定義是合法的,在使用了override關(guān)鍵字之后這種行為是非法的,編譯器會(huì)提示出錯(cuò)。

? ? ? ? final:如果我們將某個(gè)函數(shù)定義成final,則不允許后續(xù)的派生類來(lái)覆蓋這個(gè)函數(shù),否則會(huì)報(bào)錯(cuò)。

? ? ? ? 因此,將一個(gè)成員函數(shù)聲明稱為override和final能夠使得我們的意圖更加清晰。

15.13

該派生類的虛函數(shù)想要調(diào)用它覆蓋的基類的虛函數(shù)版本,但是沒(méi)有使用使用作用域運(yùn)算符,會(huì)導(dǎo)致無(wú)限遞歸。

fixed: void print(ostream &os) {base::print(os); os << "? " << i;}

15.15

#include <string> #include <iostream> using namespace std;class Bulk_quote; class Quote{ public:Quote() = default;Quote(const string &book,double sales_price):bookNo(book),price(sales_price){}string isbn()const;virtual double net_price(size_t n)const;double print_total(ostream &os,const Quote &item,size_t n);virtual ~Quote();virtual void debug_1()const; private:string bookNo; protected:double price = 0.0; };class Limitted_quote: public Quote {public:double net_price(size_t cnt)const override{if(cnt <= min_qty){return cnt * (1 - discount) * price; }elsereturn min_qty * (1-discount)*price + (cnt - min_qty) * price; }private:size_t min_qty;double discount;};class Disc_quote: public Quote{public:Disc_quote() = default;Disc_quote(const string &book,double price,size_t qty,double disc):Quote(book,price),quantity(qty),discount(disc){}double net_price(size_t)const = 0;private: size_t quantity = 0; double discount = 0;}; class Bulk_quote : public Disc_quote //Bulk_quote derived from Quote { public:Bulk_quote() = default;Bulk_quote(const string &,double,size_t ,double);//覆蓋基類的版本以實(shí)現(xiàn)大量購(gòu)買的折扣和政策double net_price(size_t n)const override; //override:顯式地用這個(gè)成員函數(shù)改寫基類的虛函數(shù)void debug_1()const override;private:size_t min_qty = 0;double discount = 0.0;};

15.17

編譯器會(huì)給出錯(cuò)誤信息:Disc_quote is an abstract type......意思是Disc_quote是一個(gè)抽象基類。不能定義抽象基類的對(duì)象。

15.18

只有d1和dd1可以。因?yàn)橹挥信缮惞灿械乩^承基類時(shí),用戶代碼才能使用派生類到基類的轉(zhuǎn)換。只有d1和dd1是共有地繼承,所以只有這2個(gè)是可以的。

或者可以這樣理解,只有當(dāng)基類的共有成員是可訪問(wèn)的,才能使用派生類到基類的轉(zhuǎn)換。目前對(duì)于用戶來(lái)說(shuō),共有成員只對(duì)d1和dd1是可見(jiàn)的。

15.19

如果派生類繼承基類是共有的,那么所有用戶都可以使用從派生類到基類的轉(zhuǎn)換。

如果派生類繼承基類是共有的或者是受保護(hù)的,那么派生類的成員函數(shù)和友元可以使用從派生類到基類的轉(zhuǎn)換,普通用戶不可以。

如果D繼承B是共有的或者受保護(hù)的,那么D的派生類或的成員或友元可以使用從D到B的轉(zhuǎn)換,如果D到B的繼承是私有的,那么D的派生類的成員或者友元將不能使用D到B的轉(zhuǎn)換。

一戶話:如果基類的共有成員對(duì)某個(gè)用戶(對(duì)象用戶或者代碼實(shí)現(xiàn)用戶)是可見(jiàn)的,那么從派生類到基類是可以轉(zhuǎn)換的,反之則不可以。

Derived_from_private: private Priv_Derv這個(gè)類的函數(shù)不合法。

15.20

#include <string> #include <iostream> using namespace std; class Base{public:void pub_mem();protected:int prot_mem = -1234;private:char priv_mem;};struct Pub_Derv: public Base { int f(){return prot_mem;}void memfcn(Base &b){b = *this;cout << "Pub_Derv" << endl;} };struct Priv_Derv: private Base { int f1() const{return prot_mem;} void memfcn(Base &b) {b = *this;cout << "Priv_Derv" << endl; } };struct Prot_Derv:protected Base { int f2(){return prot_mem;} void memfcn(Base &b) { b = *this; cout << "Prot_Derv" << endl; } };struct Derived_from_Public:public Pub_Derv { int use_base(){return prot_mem;} void memfcn(Base &b){b= *this;cout << "Derived_from_Public" << endl; } };struct Derived_from_Protected:protected Prot_Derv { int use_base() {return prot_mem; } void memfcn(Base &b) {b = *this;cout << "Derived_from_Protected" << endl; } };int main() { Pub_Derv d1; Priv_Derv d2; Prot_Derv d3; Derived_from_Public dd1; //Derived_from_Private dd2; Derived_from_Protected dd3; Base base; Base *p = new Base; p = &d1; //p = &d2; //p = &d3; p = &dd1; //p = &dd2; //p = &dd3; d1.memfcn(base); d2.memfcn(base); d3.memfcn(base);dd1.memfcn(base); //dd2.memfcn(base); dd3.memfcn(base); return 0;return 0; }

15.24

作為基類使用的類應(yīng)該具有虛析構(gòu)函數(shù),以保證在刪除指向動(dòng)態(tài)分配對(duì)象的基類指針時(shí),根據(jù)基類的實(shí)際指向的對(duì)象所屬的類型運(yùn)行時(shí)當(dāng)?shù)奈鰳?gòu)函數(shù)。

? ? ? ? 虛析構(gòu)函數(shù)可以為空,即不執(zhí)行任何操作。一般而言,析構(gòu)函數(shù)的主要作用是清除本類中定義的數(shù)據(jù)成員。如果該類沒(méi)有定義指針類的成員,則使用合成版本即可;如果該類定義了指針成員,則一般需要自定義析構(gòu)函數(shù)以保證對(duì)指針成員進(jìn)行適當(dāng)?shù)那宄R虼?#xff0c;如果有虛析構(gòu)函數(shù)必須執(zhí)行的操作,則就是清除本類中定義的數(shù)據(jù)成員的操作。

15.26

自己編寫版本(后面有書上的答案部分)

#include <string> #include <iostream> using namespace std; class Quote{public:Quote(){cout << "Quote()"<< endl;};Quote(const Quote & rhs){cout << "Quote(const Quote &rhs)" << endl;}Quote(Quote &&rhs){ cout << "Quote(Quote &&rhs)" << endl;}Quote &operator=(const Quote &rhs) {cout << "Quote& operator=(const Quote&)" << endl;bookNo = rhs.bookNo;price = rhs.price;return *this;}Quote &operator=(Quote &&rhs){bookNo = std::move(rhs.bookNo);price = std::move(rhs.price);cout <<"Quote& operator(Quote &&)" << endl;return *this;}virtual ~Quote() {cout << "~Quote()" << endl;}private:string bookNo; double price = 0.0; }; class Disc_quote : public Quote {public:Disc_quote(){ cout << "Disc_quote()" << endl;}Disc_quote(const Disc_quote &rhs):Quote(rhs),quantity(),discount(){cout << "Disc_quote(const Disc_quote&)" <<endl; }Disc_quote(Disc_quote && rhs):Quote(std::move(rhs)),quantity(rhs.quantity),discount(rhs.discount){cout << "Disc_quote(Disc_quote(Disc_quote &&rhs))" << endl;}Disc_quote& operator=(const Disc_quote & rhs){quantity = rhs.quantity;discount = rhs.discount;cout << "Disc_count&operator=(const Disc_quote &rhs) " << endl;return *this; }~Disc_quote()override {cout <<"~Disk_quote()"<< endl;}protected:size_t quantity = 0;double discount = 0;};class Bulk_quote : public Disc_quote {public:Bulk_quote(){cout << "Bulk_quote()" <<endl;}Bulk_quote(const Bulk_quote & rhs):Disc_quote(rhs){}Bulk_quote(Bulk_quote && rhs):Disc_quote(rhs){}Bulk_quote& operator=(const Bulk_quote &rhs){Disc_quote::operator=(rhs);cout << "operator=(const Bulk_quote) " << endl;return *this; }Bulk_quote& operator=(Bulk_quote && rhs){Disc_quote::operator=(std::move(rhs));cout << "Bulk_quote(Bulk_quote && rhs)" << endl; return *this;}~Bulk_quote() override {cout << "~Bulk_quote()" << endl; }};int main() {Bulk_quote b1;return 0; } Quote() Disc_quote() Bulk_quote() ~Bulk_quote() ~Disk_quote() ~Quote()

書上的答案(15.26)Quote部分:

class Quote{public:Quote(const string &book = "",double sales_price = 0):bookNo(book),price(sales_price){cout << "call Quote(const string &book,double sales_price = 0)" << endl;}Quote(const Quote & rhs){cout << "Quote(const Quote &rhs)" << endl;}Quote(Quote &&rhs){ cout << "Quote(Quote &&rhs)" << endl;}Quote &operator=(const Quote &rhs) {cout << "Quote& operator=(const Quote&)" << endl;bookNo = rhs.bookNo;price = rhs.price;return *this;}Quote &operator=(Quote &&rhs){bookNo = std::move(rhs.bookNo);price = std::move(rhs.price);cout <<"Quote& operator(Quote &&)" << endl;return *this;}virtual double net_price(size_t n)const{return n * price; }virtual ~Quote() {cout << "~Quote()" << endl;}friend ostream & operator<<(ostream &os,const Quote & rhs){os << "bookNo:"<<rhs.bookNo << "price:" << rhs.price;return os;}private:string bookNo; double price = 0.0; };

習(xí)題15.27?

#include <string> #include <iostream> using namespace std; class Quote{public:Quote(){cout << "Quote()"<< endl;};Quote(const Quote & rhs){cout << "Quote(const Quote &rhs)" << endl;}Quote(const string &book,double sales_price):bookNo(book),price(sales_price){}Quote(Quote &&rhs){ cout << "Quote(Quote &&rhs)" << endl;}Quote &operator=(const Quote &rhs) {cout << "Quote& operator=(const Quote&)" << endl;bookNo = rhs.bookNo;price = rhs.price;return *this;}Quote &operator=(Quote &&rhs){bookNo = std::move(rhs.bookNo);price = std::move(rhs.price);cout <<"Quote& operator(Quote &&)" << endl;return *this;}virtual ~Quote() {cout << "~Quote()" << endl;}protected:string bookNo; double price = 0.0; }; class Disc_quote : public Quote {public:using Quote::Quote;Disc_quote(){ cout << "Disc_quote()" << endl;}Disc_quote(const Disc_quote &rhs):Quote(rhs),quantity(),discount(){cout << "Disc_quote(const Disc_quote&)" <<endl; }Disc_quote(Disc_quote && rhs):Quote(std::move(rhs)),quantity(rhs.quantity),discount(rhs.discount){cout << "Disc_quote(Disc_quote(Disc_quote &&rhs))" << endl;}Disc_quote& operator=(const Disc_quote & rhs){quantity = rhs.quantity;discount = rhs.discount;cout << "Disc_count&operator=(const Disc_quote &rhs) " << endl;return *this; }~Disc_quote()override {cout <<"~Disk_quote()"<< endl;}friend ostream &operator<<(ostream &os,const Disc_quote & q){os << "bookNo:" << q.bookNo << " " << "price:" << q.price << " quantity:" << q.quantity << " discount:" << q.discount << endl;return os;}protected:size_t quantity = 0;double discount = 0;};class Bulk_quote : public Disc_quote {public:Bulk_quote(){cout << "Bulk_quote()" <<endl;}Bulk_quote(const Bulk_quote & rhs):Disc_quote(rhs){}Bulk_quote(Bulk_quote && rhs):Disc_quote(rhs){}Bulk_quote& operator=(const Bulk_quote &rhs){Disc_quote::operator=(rhs);cout << "operator=(const Bulk_quote) " << endl;return *this; }Bulk_quote& operator=(Bulk_quote && rhs){Disc_quote::operator=(std::move(rhs));cout << "Bulk_quote(Bulk_quote && rhs)" << endl; return *this;}~Bulk_quote() override {cout << "~Bulk_quote()" << endl; }};int main() {Bulk_quote b1; Disc_quote d("isbn-123-345-456",12.12); cout << d << endl;return 0; }

?15.28

#include <string> #include <iostream> #include <vector> #include <memory> using namespace std; class Quote{public:Quote(){cout << "Quote()"<< endl;};Quote(const Quote & rhs){cout << "Quote(const Quote &rhs)" << endl;}Quote(const string &book,double sales_price):bookNo(book),price(sales_price){}Quote(Quote &&rhs){ cout << "Quote(Quote &&rhs)" << endl;}Quote &operator=(const Quote &rhs) {cout << "Quote& operator=(const Quote&)" << endl;bookNo = rhs.bookNo;price = rhs.price;return *this;}Quote &operator=(Quote &&rhs){bookNo = std::move(rhs.bookNo);price = std::move(rhs.price);cout <<"Quote& operator(Quote &&)" << endl;return *this;}virtual double net_price(size_t n)const{cout << "Quote::net_price(size_t)" << endl;return n * price;}virtual ~Quote() {cout << "~Quote()" << endl;}protected:string bookNo; double price = 0.0; }; class Disc_quote : public Quote {public:using Quote::Quote;Disc_quote(){ cout << "Disc_quote()" << endl;}Disc_quote(const Disc_quote &rhs):Quote(rhs),quantity(),discount(){cout << "Disc_quote(const Disc_quote&)" <<endl; }Disc_quote(const string &book,double sales_price,size_t qty,double disc):Quote(book,sales_price),quantity(qty),discount(disc){cout << "Disc_quote(const string&,double,size_t ,double)" << endl;}Disc_quote(Disc_quote && rhs):Quote(std::move(rhs)),quantity(rhs.quantity),discount(rhs.discount){cout << "Disc_quote(Disc_quote(Disc_quote &&rhs))" << endl;}Disc_quote& operator=(const Disc_quote & rhs){quantity = rhs.quantity;discount = rhs.discount;cout << "Disc_count&operator=(const Disc_quote &rhs) " << endl;return *this; }~Disc_quote()override {cout <<"~Disk_quote()"<< endl;}double net_price(size_t n)const override{cout << "Disc_quote::net_price(size_t)" << endl;return n * price;}friend ostream &operator<<(ostream &os,const Disc_quote & q){os << "bookNo:" << q.bookNo << " " << "price:" << q.price << " quantity:" << q.quantity << " discount:" << q.discount << endl;return os;}protected:size_t quantity = 0;double discount = 0;};class Bulk_quote : public Disc_quote {public:Bulk_quote(){cout << "Bulk_quote()" <<endl;}Bulk_quote(const Bulk_quote & rhs):Disc_quote(rhs){}Bulk_quote(Bulk_quote && rhs):Disc_quote(rhs){}Bulk_quote& operator=(const Bulk_quote &rhs){Disc_quote::operator=(rhs);cout << "operator=(const Bulk_quote) " << endl;return *this; }Bulk_quote& operator=(Bulk_quote && rhs){Disc_quote::operator=(std::move(rhs));cout << "Bulk_quote(Bulk_quote && rhs)" << endl; return *this;}~Bulk_quote() override {cout << "~Bulk_quote()" << endl; }};int main() { /* //根據(jù)打印結(jié)果,如果vector類型為vector<Quote>,那么存儲(chǔ)的類型都是Quote類型,即使賦值時(shí)候的類型是 //Disc_quote類型,賦值的過(guò)程中也會(huì)把繼承部分切掉。//自己編寫的例子 vector<Quote> v1; v1.push_back(Quote("isbn-001-v1",12.4)); v1.push_back(Disc_quote("isbn-002-v1",12.6,100,14.2)); cout << v1[0].net_price(10) << endl; cout << v1[1].net_price(20) << endl;//自己編寫的例子:v2是Quote*類型 vector<shared_ptr<Quote>> v2; v2.push_back(make_shared<Quote>(Quote("isbn1-net1-0001",12.5))); v2.push_back(make_shared<Disc_quote>(Disc_quote("isbn2-net2-0002",12.5,100,14))); cout << v2[0]->net_price(10) << endl; cout << v2[1]->net_price(10) << endl; *///結(jié)果發(fā)現(xiàn),定義時(shí)候的類型是Quote,即使插入的元素類型是Disc_quote類型,那么 //調(diào)用的全部都是Quote::net_price(size_t ) vector<Quote> itemVec; for(size_t i = 0;i != 10; ++i){Disc_quote item("isbn-001-v1",12.5,100,12);itemVec.push_back(item); } double sum = 0; for(vector<Quote>::iterator it = itemVec.begin(); it != itemVec.end(); ++ it){sum += it->net_price(10); } cout << sum << endl;return 0; }

15.29

int main() { //結(jié)果發(fā)現(xiàn),定義時(shí)候的類型是Quote,即使插入的元素類型是Disc_quote類型,那么 //調(diào)用的全部都是Quote::net_price(size_t ) vector<shared_ptr<Quote>> itemVec; for(size_t i = 0;i != 10; ++i){Disc_quote item("isbn-001-v1",12.5,100,12);itemVec.push_back(make_shared<Disc_quote>(item)); } double sum = 0; for(vector<shared_ptr<Quote>>::iterator it = itemVec.begin(); it != itemVec.end(); ++ it){sum += (*it)->net_price(10); } cout << sum << endl;return 0; }

15.8.1節(jié)基礎(chǔ)內(nèi)容?

#include <string> #include <vector> #include <iostream> #include <memory> #include <set> using namespace std; class Quote{ public:Quote() = default;Quote(const string &book,double sales_price):bookNo(book),b(sales_price){}const string & isbn()const{return bookNo; } private://static可以用戶不完全類型,如果不定義為static類型會(huì)報(bào)錯(cuò)//猜測(cè),名字解析先編譯申明部分,但是此時(shí)compareIsbn是不完全類型//不完全類型有時(shí)候不能當(dāng)做一個(gè)類型使用static bool compareIsbn(const Quote &lhs,const Quote &rhs){return lhs.isbn() < rhs.isbn();}string bookNo;int b;multiset<shared_ptr<Quote>,decltype(compareIsbn)*> item{compareIsbn}; //上面不用用圓括號(hào)()}; int main() {return 0; }

上面的代碼有2個(gè)問(wèn)題需要思考:

(1)為何compareIsbn一定定義成static的,如果去掉static會(huì)報(bào)錯(cuò)。如下錯(cuò)誤:

2.cc:23:50: error: invalid use of non-static member function ‘bool Quote::compareIsbn(const Quote&, const Quote&)’23 | multiset<shared_ptr<Quote>,decltype(compareIsbn)*> item{compareIsbn};| ^ 2.cc:17:9: note: declared here17 | bool compareIsbn(const Quote &lhs,const Quote &rhs)| ^~~~~~~~~~~ 2.cc:23:52: error: template argument 2 is invalid23 | multiset<shared_ptr<Quote>,decltype(compareIsbn)*> item{compareIsbn};| ^ 2.cc:23:70: error: cannot convert ‘<brace-enclosed initializer list>’ to ‘int’ in initialization23 | multiset<shared_ptr<Quote>,decltype(compareIsbn)*> item{compareIsbn};

猜測(cè),可能是解析multiset<shared_ptr<Quote>,decltype(compareIsbn)*>時(shí)候,compare是不完全類型。

(2) .......item{compareIsbn},這里不能用圓括號(hào)。如果換成(),會(huì)按照如下方式報(bào)錯(cuò):

2.cc:26:59: error: ‘compareIsbn’ is not a type26 | multiset<shared_ptr<Quote>,decltype(compareIsbn)*> item(compareIsbn);

練習(xí)15.23?

// 15.7.cpp : 定義控制臺(tái)應(yīng)用程序的入口點(diǎn)。 // #include "stdafx.h" #include <string> #include <iostream> #include <memory> using namespace std; class Base{ public:virtual int fcn(){cout << "Base::fcn()" << endl;return 0;}private:};class D1 : public Base{ public:int fcn()override{cout << "D1::fcn()" << endl;return 0;}private:};class D2 : public D1{ public:int fun(int){ cout << "D2::fcn(int)" << endl; }virtual int fcn()override{cout << "D2:fcn()" << endl;return 0;}private:};int _tmain(int argc, _TCHAR* argv[]) {Base bobj; D1 d1obj; D2 d2obj;Base *bp1 = &bobj, *bp2 = &d1obj, *bp3 = &d2obj;bp1->fcn();bp2->fcn();bp3->fcn();D1 *d1p = &d1obj; D2 *d2p = &d2obj;cout << "can you see it?" << endl;system("pause");return 0; }

15.24哪種類需要虛析構(gòu)函數(shù)?虛析構(gòu)函數(shù)需要執(zhí)行什么樣的操作?

解:

作為基類使用的類應(yīng)該具有虛析構(gòu)函數(shù),以保證在刪除指向動(dòng)態(tài)分配的對(duì)象的基礎(chǔ)類指針時(shí),根據(jù)指針實(shí)際指向的對(duì)象所屬的類型運(yùn)行適當(dāng)?shù)奈鰳?gòu)函數(shù)。

? ? ? ? 虛析構(gòu)函數(shù)可以為空,即不執(zhí)行任何操作。一般而言,析構(gòu)函數(shù)的主要作用是清楚本類中定義的數(shù)據(jù)成員。如果該類沒(méi)有定義指針類成員,則使用合成的版本即可;如果該類定義了指針成員,則一般需要自定義析構(gòu)函數(shù)以對(duì)指針成員進(jìn)行適當(dāng)?shù)那宄R虼?#xff0c;如果有虛析構(gòu)函數(shù)必須執(zhí)行的操作,則就是清楚本類中定義的數(shù)據(jù)成員的操作。

練習(xí)15.26答案

//文件 main.cc #include <string> #include <iostream> #include "quote.h" using namespace std;int main() { Quote q1; Bulk_quote d1;return 0; } //文件functions.cc #include <string> #include <iostream> #include <memory> #include "quote.h" using namespace std;string Quote::isbn()const{return bookNo; }double Quote::net_price(size_t n)const {return n * price; }double print_total(ostream &os,const Quote &item,size_t n) //override:顯式地用這個(gè)成員函數(shù)改寫基類的虛函數(shù) { //根據(jù)傳入的item的形參的對(duì)象類型調(diào)用Quote::net_price 或者 Bulk_quote::net_price //共有成員訪問(wèn)的時(shí)候必須用對(duì)象去訪問(wèn)。 double ret = item.net_price(n); os << "ISBN: " << item.isbn() << "# sold: " << n << " total due: " << ret << endl;return ret; }//destructor Quote::~Quote(){cout << "Quote::~Quote()" << endl;}Bulk_quote::Bulk_quote(const string &book,double p,size_t qty,double disk):Disc_quote(book,p,qty,disk) {cout << "Bulk_quote(const string &,double ,size_t ,double)" << endl; }double Bulk_quote::net_price(size_t n)const {return 1.1; }//test void call_fun(Quote q) {cout << q.net_price(12) << endl;} //文件quote.h #ifndef QUOTE_INCLUDE_H #define QUOTE_INCLUDE_H#include <string> #include <iostream> using namespace std;class Bulk_quote; class Quote{ public:Quote(){cout << "Quote()" << endl;};Quote(const string &book,double sales_price):bookNo(book),price(sales_price){cout << "Quote(const string &,double )" << endl;}Quote(const Quote & q):bookNo(q.bookNo),price(q.price){cout << "Quote(const Quote &)" << endl;}Quote(Quote &&q):bookNo(std::move(q.bookNo)),price(q.price){cout << "Quote(Quote &&)" << endl;}Quote& operator=(const Quote &q){bookNo = q.bookNo;price = q.price;cout << "Quote::operator=" << endl;return *this; }Quote& operator=(Quote &&q){bookNo = std::move(q.bookNo);price = q.price;cout << "Quote::operator=(Quote&&)" << endl;return *this; }string isbn()const;virtual double net_price(size_t n)const;friend double print_total(ostream &os,const Quote &item,size_t n);virtual ~Quote(); private:string bookNo; protected:double price = 0.0; };//abstract class class Disc_quote: public Quote{public:Disc_quote(){cout << "Disc_quote()" << endl;}Disc_quote(const string &book,double price,size_t qty,double disc):Quote(book,price),quantity(qty),discount(disc){cout << "Disc_quote(const string&,double ,size_t ,double) " <<endl;}Disc_quote(const Disc_quote &q):Quote(q),quantity(q.quantity),discount(q.discount){cout << "Disc_quote(const Disc_quote &)" << endl; }Disc_quote(Disc_quote &&q):Quote(std::move(q)),quantity(q.quantity),discount(q.discount){}Disc_quote & operator=(const Disc_quote &d){Quote::operator=(d);quantity = d.quantity;discount = d.discount; cout << "Disc_quote::operator=" << endl;return *this;}Disc_quote& operator=(Disc_quote &&d){Quote(std::move(d));quantity = d.quantity;discount = d.discount;return *this;}//pure virtual functiondouble net_price(size_t)const = 0;~Disc_quote()override{cout << "~Disc_quote()" << endl; }private: size_t quantity = 0; double discount = 0;}; class Bulk_quote : public Disc_quote //Bulk_quote derived from Quote { public:Bulk_quote(){cout << "Bulk_quote()" << endl; }Bulk_quote(const string &,double,size_t ,double);//拷貝控制成員Bulk_quote(const Bulk_quote &b):Disc_quote(b){cout << "Bulk_quote(const Bulk_quote &)" << endl;}Bulk_quote(Bulk_quote && b):Disc_quote(std::move(b)){cout << "Bulk_quote(Bulk_quote&&)" << endl;}Bulk_quote& operator=(const Bulk_quote &b){Disc_quote::operator=(b); cout <<"Bulk_quote(const Bulk_quote &)" << endl;return *this;}Bulk_quote& operator=(Bulk_quote &&q){Disc_quote::operator=(std::move(q));return *this; }~Bulk_quote()override{cout << "~Bulk_quote()" << endl;}//覆蓋基類的版本以實(shí)現(xiàn)大量購(gòu)買的折扣和政策double net_price(size_t n)const override; //override:顯式地用這個(gè)成員函數(shù)改寫基類的虛函數(shù)};double print_total(ostream &,const Quote &,size_t ); void call_fun(Quote ); #endif

15.30

//main.cc #include <string> #include <iostream> #include "quote.h" #include <vector> #include <memory>using namespace std; int main() {return 0; } //functions.cc #include <string> #include <iostream> #include <memory> #include "quote.h" using namespace std;string Quote::isbn()const{return bookNo; }double Quote::net_price(size_t n)const {cout << "Quote::net_price(size_t)" << endl;return n * price; }double print_total(ostream &os,const Quote &item,size_t n) //override:顯式地用這個(gè)成員函數(shù)改寫基類的虛函數(shù) { //根據(jù)傳入的item的形參的對(duì)象類型調(diào)用Quote::net_price 或者 Bulk_quote::net_price //共有成員訪問(wèn)的時(shí)候必須用對(duì)象去訪問(wèn)。 double ret = item.net_price(n); os << "ISBN: " << item.isbn() << "# sold: " << n << " total due: " << ret << endl;return ret; }//destructor Quote::~Quote(){cout << "Quote::~Quote()" << endl;}/* Bulk_quote::Bulk_quote(const string &book,double p,size_t qty,double disk):Disc_quote(book,p,qty,disk) {cout << "Bulk_quote(const string &,double ,size_t ,double)" << endl; } */double Bulk_quote::net_price(size_t n)const {cout << "Bulk_quote::net_price(size_t)" << endl; return 1.1; }//test void call_fun(Quote q) {cout << q.net_price(12) << endl;}//Basket類成員函數(shù) double Basket::total_receipt(ostream &os)const { double sum = 0.0; for(auto iter = items.cbegin();iter != items.end();iter = items.upper_bound(*iter)){sum += print_total(os,**iter,items.count(*iter));} os << "Total sale: " <<sum <<endl;return sum; } //quote.h #ifndef QUOTE_INCLUDE_H #define QUOTE_INCLUDE_H#include <string> #include <iostream> #include <vector> #include <memory> #include <set> using namespace std;class Bulk_quote; class Quote{ public:Quote(){cout << "Quote()" << endl;};Quote(const string &book,double sales_price):bookNo(book),price(sales_price){cout << "Quote(const string &,double )" << endl;}Quote(const Quote & q):bookNo(q.bookNo),price(q.price){cout << "Quote(const Quote &)" << endl;}Quote(Quote &&q):bookNo(std::move(q.bookNo)),price(q.price){cout << "Quote(Quote &&)" << endl;}Quote& operator=(const Quote &q){bookNo = q.bookNo;price = q.price;cout << "Quote::operator=" << endl;return *this; }Quote& operator=(Quote &&q){bookNo = std::move(q.bookNo);price = q.price;cout << "Quote::operator=(Quote&&)" << endl;return *this; }string isbn()const;virtual double net_price(size_t n)const;friend double print_total(ostream &os,const Quote &item,size_t n);virtual ~Quote();virtual Quote* clone() const &{return new Quote(*this); }virtual Quote* clone()&&{return new Quote(std::move(*this));}private:string bookNo; protected:double price = 0.0; };//abstract class class Disc_quote: public Quote{public:Disc_quote(){cout << "Disc_quote()" << endl;}Disc_quote(const string &book,double price,size_t qty,double disc):Quote(book,price),quantity(qty),discount(disc){cout << "Disc_quote(const string&,double ,size_t ,double) " <<endl;}Disc_quote(const Disc_quote &q):Quote(q),quantity(q.quantity),discount(q.discount){cout << "Disc_quote(const Disc_quote &)" << endl; }Disc_quote(Disc_quote &&q):Quote(std::move(q)),quantity(q.quantity),discount(q.discount){}Disc_quote & operator=(const Disc_quote &d){Quote::operator=(d);quantity = d.quantity;discount = d.discount; cout << "Disc_quote::operator=" << endl;return *this;}Disc_quote& operator=(Disc_quote &&d){Quote(std::move(d));quantity = d.quantity;discount = d.discount;return *this;}//pure virtual functiondouble net_price(size_t)const = 0;~Disc_quote()override{cout << "~Disc_quote()" << endl; }private: size_t quantity = 0; double discount = 0;}; class Bulk_quote : public Disc_quote //Bulk_quote derived from Quote { public:Bulk_quote* clone()const & override{return new Bulk_quote(*this); }Bulk_quote* clone()&& override{return new Bulk_quote(std::move(*this));}using Disc_quote::Disc_quote;Bulk_quote(){cout << "Bulk_quote()" << endl; }//Bulk_quote(const string &,double,size_t ,double);//拷貝控制成員Bulk_quote(const Bulk_quote &b):Disc_quote(b){cout << "Bulk_quote(const Bulk_quote &)" << endl;}Bulk_quote(Bulk_quote && b):Disc_quote(std::move(b)){cout << "Bulk_quote(Bulk_quote&&)" << endl;}Bulk_quote& operator=(const Bulk_quote &b){Disc_quote::operator=(b); cout <<"Bulk_quote(const Bulk_quote &)" << endl;return *this;}Bulk_quote& operator=(Bulk_quote &&q){Disc_quote::operator=(std::move(q));return *this; }~Bulk_quote()override{cout << "~Bulk_quote()" << endl;}//覆蓋基類的版本以實(shí)現(xiàn)大量購(gòu)買的折扣和政策double net_price(size_t n)const override; //override:顯式地用這個(gè)成員函數(shù)改寫基類的虛函數(shù)};class Basket {public:void add_item(const Quote & sale){items.insert(shared_ptr<Quote>(sale.clone())); }void add_item(Quote && sale){items.insert(shared_ptr<Quote>((std::move(sale)).clone()));}//打印每本書的總價(jià)格和籃中所有書的總價(jià)double total_receipt(ostream &)const;private:static bool compare(const shared_ptr<Quote> &lhs,const shared_ptr<Quote> &rhs){return lhs->isbn() < rhs->isbn();} // items定義成一個(gè)multiset,可以將同一本書的多條交易信息保存到一個(gè)multiset中, // 這里不能用圓括號(hào),因?yàn)閐efault member initializer來(lái)初始化成員有2 // 個(gè)方法,list initialization,即一對(duì)花括號(hào).第二種是copy initializa//tion,即 等號(hào).如果嘗試用圓括號(hào),編譯器會(huì)誤以為是函數(shù)聲明,所以/報(bào)告compare is not a type..multiset<shared_ptr<Quote>,decltype(compare)*> items{compare}; };double print_total(ostream &,const Quote &,size_t ); void call_fun(Quote );#endif

練習(xí)15.32

Query未定義自己的拷貝、移動(dòng)、賦值和銷毀成員,當(dāng)進(jìn)行這些操作時(shí),執(zhí)行默認(rèn)的語(yǔ)義。而其唯一的數(shù)據(jù)成員是Query_base的shared_ptr,因此,當(dāng)拷貝、移動(dòng)、賦值、或者銷毀一個(gè)Query對(duì)象時(shí),會(huì)調(diào)用shared_ptr的對(duì)應(yīng)控制成員,從而實(shí)現(xiàn)多個(gè)Query對(duì)象正確共享一個(gè)Query_base。而shared_ptr的控制成員調(diào)用Query_base的控制成員時(shí),由于指向的可能是Query_base的派生類對(duì)象,因此可能是類層次中進(jìn)行相應(yīng)的拷貝、移動(dòng)操作,調(diào)用Query_base的派生類的相應(yīng)控制成員。

練習(xí)15.34

? (a)Query(const string &),WordQuery(const string &),NotQuery(const Query &),AndQuery(const Query &,const Query &),OrQuery(const Query &,const Query &)。

? (b)OrQuerry::rep()

(c)OrQuery::eval(const TextQuery &)

15.35

15.9節(jié)

先看一些代碼的基礎(chǔ),下面是查詢類的完整代碼
?

//文件query.h#ifndef CLASS_H #define CLASS_H#include <string> #include <iostream> #include <vector> #include <set> #include <memory> #include <fstream> #include <map> #include <algorithm>using namespace std;class QueryResult; class Query_base; class BinaryQuery; class AndQuery; class OrQuery; class NotQuery; class Query; class WordQuery;Query operator~(const Query &q); Query operator&(const Query &,const Query &); Query operator|(const Query &,const Query &);class TextQuery {friend class Query;public:using line_no = vector<string>::size_type;TextQuery() = default;TextQuery(ifstream &is);QueryResult query(const string &s)const;size_t size()const{return file->size();}vector<string>::iterator begin()const{return file->begin();}vector<string>::iterator end()const{return file->end();}private:shared_ptr<vector<string>> file;shared_ptr<set<line_no>> lines;map<string,shared_ptr<set<line_no>>> wm;}; class QueryResult{friend void print(ostream &,const QueryResult &);public:using line_no = TextQuery::line_no;QueryResult(shared_ptr<vector<string>> f,shared_ptr<set<line_no>> l,const string &s):file(f),lines(l),query_word(s){}set<line_no>::iterator begin()const{return lines->begin();}set<line_no>::iterator end()const{return lines->end();}shared_ptr<vector<string>> get_file()const{return file;}private:shared_ptr<vector<string>> file;shared_ptr<set<line_no>> lines;string query_word;};class Query_base{friend class Query;protected:using line_no = TextQuery::line_no;virtual ~Query_base() = default;private:virtual QueryResult eval(const TextQuery &)const= 0;virtual string rep()const = 0;};class WordQuery:public Query_base{ friend class Query;WordQuery(const string &s):query_word(s){}QueryResult eval(const TextQuery &)const; string rep()const;string query_word; };inline QueryResult WordQuery::eval(const TextQuery &t)const {return t.query(query_word); }inline string WordQuery::rep()const {return query_word; }class Query{ friend Query operator~(const Query &q); friend Query operator&(const Query &,const Query &); friend Query operator|(const Query &,const Query &);public:QueryResult eval(const TextQuery &t)const{return query->eval(t);}string rep()const{return query->rep();}Query(const string &w):query(new WordQuery(w)){}private:Query(shared_ptr<Query_base> p):query(p){}shared_ptr<Query_base> query;};class BinaryQuery: public Query_base { protected: BinaryQuery(const Query &l,const Query &r,const string &s):lhs(l),rhs(r),opSym(s){}Query lhs,rhs; string opSym;string rep()const; };inline string BinaryQuery::rep()const{ return "(" + lhs.rep() + opSym + rhs.rep()+")"; }class AndQuery: public BinaryQuery { friend Query operator&(const Query &,const Query &); AndQuery(const Query &l,const Query &r):BinaryQuery(l,r,"&"){} QueryResult eval(const TextQuery &)const;};inline QueryResult AndQuery::eval(const TextQuery &t)const { //先利用Query的成員函數(shù)eval查詢AndQuery的兩個(gè)操作數(shù)的 //查詢結(jié)果 QueryResult left = lhs.eval(t),right = rhs.eval(t); shared_ptr<set<line_no>> ret = make_shared<set<line_no>>(); set_intersection(left.begin(),left.end(),right.begin(),right.end(),inserter(*ret,ret->begin()));return QueryResult(left.get_file(),ret,rep());}class OrQuery:public BinaryQuery {friend Query operator|(const Query &,const Query &);OrQuery(const Query &l,const Query &r):BinaryQuery(l,r,"|"){}QueryResult eval(const TextQuery &)const; }; inline QueryResult OrQuery::eval(const TextQuery &t)const { auto left = lhs.eval(t),right = rhs.eval(t); auto ret = make_shared<set<line_no>>(left.begin(),left.end()); ret->insert(right.begin(),right.end());return QueryResult(left.get_file(),ret,rep());} inline Query operator&(const Query &l,const Query &r) { return shared_ptr<Query_base>(new AndQuery(l,r)); }inline Query operator|(const Query &l,const Query &r) { return shared_ptr<Query_base>(new OrQuery(l,r));}class NotQuery:public Query_base{ friend class Query; friend Query operator~(const Query &);NotQuery(const Query &s):query(s){}QueryResult eval(const TextQuery &t)const; string rep()const; private: Query query; }; inline QueryResult NotQuery::eval(const TextQuery &t)const { auto r = query.eval(t); auto ret = make_shared<set<line_no>>(r.begin(),r.end()); auto beg = ret->begin(); auto end = ret->end(); auto result = make_shared<set<line_no>>(); for(int i = 0; i != r.get_file()->size();++ i){if(*beg != i && beg != end){result->insert(i);}elseif(beg != end){++ beg; }} return QueryResult(r.get_file(),result,rep()); }inline string NotQuery::rep()const {return "~(" + query.rep() + ")"; }inline Query operator~(const Query &q) {return shared_ptr<Query_base>(new NotQuery(q)); }#endif

//functions.cc#include <string> #include "class.h" #include <iostream> #include <fstream> #include <set> #include <vector> #include <memory> #include <sstream> #include <map> #include "query.h" using namespace std; /* class TextQuery's member functions */ TextQuery::TextQuery(ifstream &is):file(new vector<string>()),lines(new set<line_no>()) { string line; string word; size_t num = 0; while(getline(is,line)){file->push_back(line);istringstream in(line);while(in >> word){auto &loc = wm[word];if(!loc){loc.reset(new set<line_no>()); }loc->insert(num);}++ num;} }/* QueryResult 's member functions */QueryResult TextQuery::query(const string &s)const { //map的find成員,查找成功返回一個(gè)找到元素的迭代器,找不到返回尾后迭代器. auto pos = wm.find(s); if(pos == wm.end()){shared_ptr<set<line_no>> nodata(new set<line_no>());return QueryResult(file,nodata,s);}else{//慎重用map的下標(biāo)操作,因?yàn)樵厝绻淮嬖跁?huì)添加元素return QueryResult(file,pos->second,s);}}void print(ostream &os,const QueryResult &q) { cout << q.query_word << " occurs " << q.lines->size() << " times:" << endl; for(auto i : *(q.lines)){cout << "\t(line " << i+1 << "):" << (*q.file)[i] << endl; }} #include <string> #include <iostream> #include "class.h" #include <fstream> #include <map> #include <set> #include "query.h"using namespace std;int main() {//假設(shè)數(shù)據(jù)文件放在data.txt中 ifstream in("data.txt"); TextQuery t(in); Query q = Query("good") | Query("you"); q.eval(t); print(cout,q.eval(t));return 0; }

練習(xí)15.34答案:

(a)執(zhí)行的構(gòu)造函數(shù)如下:

WordQuery(const string &)Query(const string &)WordQuery(const string &)Query(const string &)WordQuery(const string &)Query(const string &)AndQuery(const Query &,const Query &,const string &)BinaryQuery(const Query &,const Query &,const string? &)#下面這個(gè)構(gòu)造函數(shù)形式參數(shù)類型不可以是const的Query(shard_ptr<Query_base> )OrQuery(const Query &,const Quyer &)BinaryQuery(const Query &,const Query &,const string &)

(b)

首先執(zhí)行Query::rep() 然后直行OrQuery::rep() ...Query::rep() ...Query::rep() ...AndQuery::rep() ...Query::rep() ...WordQuery::rep() ...WordQuery::rep() ...WordQuery::rep()

(c)

Query::eval() OrQuery::eval() Query::eval() Query::eval() AndQuery::eval() Query::eval() Query::eval() Query::eval() WordQuery::eval() WordQuery::eval() WordQuery::eval()

15.37(這個(gè)題答案是自己想的,做了一下午,從下午1點(diǎn)做到5點(diǎn)30)

自己隨便弄了個(gè)測(cè)試的讀取單詞的數(shù)據(jù)文件:

文件data.txt

you are my good friend , and you are so good too . i am glad to see you , if you do not mind i will take some time to study from you .wahaha . sometimes i was so moody .

//main.cc #include <string> #include <iostream> #include "textquery.h" #include "query.h" #include <fstream> using namespace std; int main() {ifstream in("data.txt"); TextQuery t(in);shared_ptr<Query_base> p = ~shared_ptr<Query_base>(new WordQuery("you"))|shared_ptr<Query_base>(new WordQuery("are"));print(cout,p->eval(t));print(cout,p) << endl; return 0; } //textquery.cc#include <string> #include <iostream> #include <fstream> #include <vector> #include <map> #include <set> #include "textquery.h" #include <memory> #include <sstream> using namespace std; TextQuery::TextQuery(ifstream &in):file(new vector<string>()) { string line; //cnt 表示讀入文件的行號(hào) int cnt = 0; while(getline(in,line)){//首先把行插入到文件file中file->push_back(line);istringstream in_s(line);string word;while(in_s >> word){//在wm中插入單詞的行號(hào)//注意這里ret是引用類型auto &ret = wm[word];if(!ret){//為ret分配內(nèi)存空間,這里無(wú)論有沒(méi)有圓括號(hào)都是空集合初始化ret所指向的空間ret.reset(new set<line_no>()); }ret->insert(cnt);} ++ cnt; //行號(hào)遞增 } }QueryResult TextQuery::query(const string &s)const { //不能用下標(biāo)操作查詢單詞s是否存在,因?yàn)橄聵?biāo)操作在單詞不存在的 //情況下會(huì)往map中添加單詞,正確的做法用find auto ret = wm.find(s); //find返回的是迭代器 if(ret == wm.end()){//這里必須新建一個(gè)set<line_no>對(duì)象,內(nèi)容為空,不然當(dāng)單詞查不到時(shí),對(duì)返回的QueryResult對(duì)象中的有關(guān)wm對(duì)象的一切操作均會(huì)報(bào)錯(cuò),因?yàn)闆](méi)有分配內(nèi)存,是不能使用的,包括調(diào)用size()成員函數(shù)。//智能指針使用前必須要里面有內(nèi)容,也就是分配了內(nèi)存auto nodata = make_shared<set<line_no>>();return QueryResult(file,nodata,s);}//注意迭代器其實(shí)就是一個(gè)指針,用->訪問(wèn)迭代器所指的pair else//ret->second 不能改成下標(biāo)操作,也就是wm[s],原因我也不知道,大概是下標(biāo)式子使用受限r(nóng)eturn QueryResult(file,ret->second,s); } //textquery.h#ifndef TEXTQUERY_H #define TEXTQUERY_H #include <string> #include <iostream> #include <fstream> #include <vector> #include <map> #include <set> #include <memory> using namespace std; class QueryResult; class TextQuery{public: using line_no = vector<string>::size_type; TextQuery() = default; TextQuery(ifstream &in); QueryResult query(const string &s)const;private: map<string,shared_ptr<set<line_no>>> wm; shared_ptr<vector<string>> file; };class QueryResult { friend ostream& print(ostream &,const QueryResult &);public: using line_no = TextQuery::line_no; QueryResult() = default; QueryResult(shared_ptr<vector<string>> f,shared_ptr<set<line_no>> l,const string &w):file(f),lines(l),query_word(w){} shared_ptr<vector<string>> get_file()const{return file;} set<line_no>::iterator begin()const{return lines->begin();} set<line_no>::iteratorend()const{return lines->end();} size_t size()const{return lines->size();}private: //編譯器對(duì)于智能指針只管擇機(jī)釋放,不管分配,所以使用前務(wù)必自己分配。 shared_ptr<set<line_no>> lines; //lines使用前必須手動(dòng)分配空間 shared_ptr<vector<string>> file;//file 使用前必須手動(dòng)分配空間 string query_word;}; inline ostream& print(ostream & os,const QueryResult &q) { os << q.query_word << " occurs "<<q.lines->size() << " times:" << endl; auto file = q.get_file(); for(auto i : *(q.lines)){os << "(line " << i+1 << ") " << (*file)[i] << endl;}return os; } #endif //query.h#ifndef QUERY_H #define QUERH_H#include <string> #include <iostream> #include <memory>#include <set> #include <algorithm> #include "textquery.h" using namespace std;class Query_base{public:Query_base() = default;virtual QueryResult eval(const TextQuery &t)const=0;virtual string rep()const=0;virtual ~Query_base(){}protected:using line_no = TextQuery::line_no; }; //沒(méi)有覆蓋eval,所以BinaryQuery還是一個(gè)抽象基類 class BinaryQuery : public Query_base { public:BinaryQuery(shared_ptr<Query_base> l,shared_ptr<Query_base> r,const string & ope):lhs(l),rhs(r),opSym(ope){}string rep()const override;protected: shared_ptr<Query_base> lhs; //使用前必須分配空間,或者是用另一個(gè)指針賦值 shared_ptr<Query_base> rhs; //同上 private: string opSym; }; inline string BinaryQuery::rep()const {return "(" + lhs->rep() +" " +opSym + " "+rhs->rep() + ")"; }class WordQuery:public Query_base {public:WordQuery(const string &s):query_word(s){}QueryResult eval(const TextQuery &t)const override{ return t.query(query_word);}string rep()const override{return query_word;} private:string query_word;};class AndQuery:public BinaryQuery {public: //BinaryQuery()的各個(gè)實(shí)參必須都正確,如果寫成lhs和rhs,那么使用時(shí)候就會(huì)失去實(shí)參, //結(jié)果就是lhs和rhs沒(méi)有得到空間然后就是用了,就會(huì)出現(xiàn) segmentation fault,core dumped之類的錯(cuò)誤。 AndQuery(shared_ptr<Query_base> l,shared_ptr<Query_base> r):BinaryQuery(l,r,"&"){} QueryResult eval(const TextQuery &)const override;};inline QueryResult AndQuery::eval(const TextQuery &t)const { auto l = lhs->eval(t); auto r = rhs->eval(t); auto file = l.get_file(); auto new_set = make_shared<set<line_no>>(); //set_intersection算法:intersection意思是 交集 ,所以set_intersection是求交集 set_intersection(l.begin(),l.end(),r.begin(),r.end(),inserter(*new_set,new_set->begin()));return QueryResult(file,new_set,rep()); }class OrQuery:public BinaryQuery {public:OrQuery(shared_ptr<Query_base> l,shared_ptr<Query_base> r):BinaryQuery(l,r,"|"){}QueryResult eval(const TextQuery &)const;string rep()const; }; inline QueryResult OrQuery::eval(const TextQuery &t)const { auto r1 = lhs->eval(t); auto r2 = rhs->eval(t); auto file = r1.get_file(); auto new_set = make_shared<set<line_no>>(r1.begin(),r1.end()); new_set->insert(r2.begin(),r2.end()); return QueryResult(file,new_set,rep()); }string OrQuery::rep()const {return "(" + lhs->rep() +" | "+ rhs->rep() + ")"; }class NotQuery:public Query_base {public: NotQuery(shared_ptr<Query_base> s):query(s){} QueryResult eval(const TextQuery &)const; string rep()const;private: shared_ptr<Query_base> query; };inline string NotQuery::rep()const {return "~(" + query->rep() + ")"; }inline QueryResult NotQuery::eval(const TextQuery &t)const { auto result = query->eval(t); auto file = result.get_file(); auto old_set = make_shared<set<line_no>>(result.begin(),result.end()); auto beg = old_set->begin(); auto end = old_set->end(); auto new_set = make_shared<set<line_no>>(); //下面是求一個(gè)子集的補(bǔ)集,并且全集和補(bǔ)集是按照同樣的方式排序時(shí)候的一個(gè)算法,我自己稱它為: //“求補(bǔ)集算法”,很好用的一個(gè)算法 for(int i = 0;i != file->size(); ++i){if(beg != end && i != *beg){new_set->insert(i);}else{if(beg != end)++ beg; }} return QueryResult(file,new_set,rep()); }inline shared_ptr<Query_base>operator&(shared_ptr<Query_base> l,shared_ptr<Query_base> r) {return shared_ptr<Query_base>(new AndQuery(l,r)); }inline shared_ptr<Query_base>operator|(shared_ptr<Query_base> l,shared_ptr<Query_base> r) {return shared_ptr<Query_base>(new OrQuery(l,r)); }inline shared_ptr<Query_base> operator~(shared_ptr<Query_base> l) {return shared_ptr<Query_base>(new NotQuery(l)); }inline ostream & print(ostream &os,shared_ptr<Query_base> p) {return os << p->rep(); }#endif

運(yùn)行結(jié)果是:

(~(you) | are) occurs 1 times: (line 1) you are my good friend , and you are so good too . (~(you) | are)

成功~~~

回顧:

如果運(yùn)行后發(fā)現(xiàn)如下結(jié)果:

segmentation fault,core dumped.

那么對(duì)于本題的程序,很大程度上可能是指針沒(méi)有智能沒(méi)有分配空間就使用了,然后就會(huì)發(fā)生這種問(wèn)題。

然后,本程序有以下幾個(gè)地方需要去檢查:

? ? ? ? ? ? ?程序中已經(jīng)做提示了

15.38? 答:

(a)不合法,& 運(yùn)算符返回的類型是 Query?類型,不能轉(zhuǎn)換為BinaryQuery類型。而且BinaryQuery是抽象基類,不能定義自己類型對(duì)象。

(b)不合法,& 運(yùn)算符返回的類型是 Query?類型,不能轉(zhuǎn)換為BinaryQuery類型。

(c)不合法,道理同(b)

提醒:要解決這個(gè)問(wèn)題,必須收先自己想想,如果類有動(dòng)態(tài)內(nèi)存,而類的成員也有動(dòng)態(tài)內(nèi)存的時(shí)候,析構(gòu)函數(shù)應(yīng)該怎么寫?

//textquery.cc #include <string> #include <iostream> #include <fstream> #include <vector> #include <map> #include <set> #include "textquery.h" #include <memory> #include <sstream> using namespace std; TextQuery::TextQuery(ifstream &in):file(new vector<string>()) { string line; //cnt 表示讀入文件的行號(hào) int cnt = 0; while(getline(in,line)){//首先把行插入到文件file中file->push_back(line);istringstream in_s(line);string word;while(in_s >> word){//在wm中插入單詞的行號(hào)//注意這里ret是引用類型auto &ret = wm[word];if(!ret){//這里無(wú)論有沒(méi)有括號(hào)都是空集合ret.reset(new set<line_no>()); }ret->insert(cnt);} ++ cnt; //行號(hào)遞增 } }QueryResult TextQuery::query(const string &s)const { //不能用下標(biāo)操作查詢單詞s是否存在,因?yàn)橄聵?biāo)操作在單詞不存在的 //情況下會(huì)往map中添加單詞,正確的做法用find auto ret = wm.find(s); //find返回的是迭代器 if(ret == wm.end()){//這里必須新建一個(gè)set<line_no>對(duì)象,內(nèi)容為空,不然//對(duì)此時(shí)返回的QueryResult對(duì)象中的有關(guān)wm對(duì)象的一切操作均會(huì)報(bào)錯(cuò),因?yàn)闆](méi)有分配內(nèi)存,是不能使用的。//智能指針使用前必須要里面有內(nèi)容,也就是分配了內(nèi)存auto nodata = make_shared<set<line_no>>();return QueryResult(file,nodata,s);}//注意迭代器其實(shí)就是一個(gè)指針,用->訪問(wèn)迭代器所指的pair elsereturn QueryResult(file,ret->second,s); } query.cc //query.h中的函數(shù)都定義為內(nèi)聯(lián)函數(shù)了,這里空了 #include <string> #include <iostream> #include <memory> #include <vector> #include <map> #include <set> #include "query.h" using namespace std; //main.cc #include <string> #include <iostream> #include "query.h" #include "textquery.h" #include <fstream> #include <set> #include <memory> using namespace std;int main() { ifstream in("data.txt"); TextQuery t(in); Query q = Query("my") & Query("good") | Query("you"); cout << q.rep() << endl; QueryResult ret = q.eval(t); print(cout,ret);return 0; } //textquery.h #ifndef TEXTQUERY_H #define TEXTQUERY_H#include <string> #include <iostream> #include <fstream> #include <vector> #include <map> #include <set> #include <memory> using namespace std; class QueryResult; class TextQuery{public: using line_no = vector<string>::size_type;TextQuery() = default; TextQuery(ifstream &in); QueryResult query(const string &s)const;private:map<string,shared_ptr<set<line_no>>> wm; shared_ptr<vector<string>> file; };class QueryResult { friend ostream& print(ostream &,const QueryResult &);public: using line_no = TextQuery::line_no; QueryResult() = default; QueryResult(shared_ptr<vector<string>> f,shared_ptr<set<line_no>> l,const string &w):file(f),lines(l),query_word(w){} shared_ptr<vector<string>> get_file()const{return file;} set<line_no>::iterator begin()const{return lines->begin();} set<line_no>::iteratorend()const{return lines->end();} size_t size()const{return lines->size();}private: shared_ptr<set<line_no>> lines; shared_ptr<vector<string>> file; string query_word;}; inline ostream& print(ostream & os,const QueryResult &q) { os << q.query_word << " occurs "<<q.lines->size() << " times:" << endl; auto file = q.get_file(); for(auto i : *(q.lines)){os << "(line " << i+1 << ") " << (*file)[i] << endl;}return os; }#endif

//query.h/************************************************ 1.constructor may not be cv-qualified(構(gòu)造函數(shù)不能是 const的),道理很簡(jiǎn)單,構(gòu)造函數(shù)會(huì)改變對(duì)象的值* 2.constructor may not be ref-qualified(構(gòu)造函數(shù)不可以加& 或者 &&,賦值運(yùn)算符卻可以)* //道理也簡(jiǎn)單,構(gòu)造函數(shù)是定義對(duì)象時(shí)候用,定義的對(duì)象當(dāng)然不分左值和右值,也就是在定義對(duì)象之前* //對(duì)象還不存在,也就是說(shuō)定義對(duì)象之前根本沒(méi)東西,當(dāng)然就不能分左值和右值了。* //其它函數(shù)是建立在有對(duì)象的基礎(chǔ)上使用的,當(dāng)然這個(gè)對(duì)象就可以是左值或者右值了。* //一句話:“只有成員函數(shù)或者賦值運(yùn)算符才可以是& 或者 &&的”,構(gòu)造函數(shù)不在此,構(gòu)造函數(shù)不在此列列* 3.構(gòu)造函數(shù)不能分左值和右值版本,賦值運(yùn)算符在本程序中不要分左值和右值版本,只要給參數(shù)類型分* 左值版本和右值版本就可以了,也就是說(shuō)遇到左值/右值類型的參數(shù)(具體賦值過(guò)程中是右操作數(shù)),調(diào)用對(duì)應(yīng)版本即可,左操作數(shù)不需要定義左右版本* 4.構(gòu)造函數(shù)和賦值運(yùn)算符都不可以定義成const的函數(shù),因?yàn)樗鼈兌夹枰淖儗?duì)象本身* 5.拷貝賦值運(yùn)算符:首先需要把右側(cè)值存起來(lái),存的時(shí)候就存必要的成員還是整體全部* 其次需要釋放左側(cè)資源,調(diào)用左側(cè)類型的的析構(gòu)函數(shù)就可以了吧,還是要把左側(cè)的基類部分 和非基類部分分開(kāi)釋放。* 最后給左側(cè)賦值。** 暫時(shí)結(jié)論:析構(gòu)的時(shí)候就析構(gòu)左側(cè)部分就可以。析構(gòu)函數(shù)會(huì)自動(dòng)遞歸調(diào)用基類的析構(gòu)函數(shù)* 釋放基類部分,但是賦值或者拷貝的時(shí)候必須要首先拷貝基類部分或者給基類部分賦值。* ** 6.析構(gòu)函數(shù)的安排* 7.在類的對(duì)象的析構(gòu)中,必須手動(dòng)釋放類的資源,對(duì)于普通的內(nèi)置類型的值,不用做任何事情。* 8.類值版本的賦值運(yùn)算符定義的時(shí)候,左側(cè)對(duì)象的析構(gòu)能否直接調(diào)用左側(cè)對(duì)象的析構(gòu)函數(shù)?還是必須只手動(dòng)析構(gòu)動(dòng)態(tài)內(nèi)存成員就可以,但是如果普通成員是類類型,也包含動(dòng)態(tài)內(nèi)存成員又該怎么辦呢?此時(shí)是調(diào)用左側(cè)對(duì)象的析構(gòu)函數(shù)呢?還是只釋放動(dòng)態(tài)內(nèi)存成員* 9.賦值運(yùn)算符能不能這樣工作,直接調(diào)用拷貝構(gòu)造函數(shù),新建個(gè)對(duì)象把右側(cè)對(duì)象放進(jìn)來(lái),然后再釋放左側(cè)對(duì)象(能不能直接調(diào)用左側(cè)對(duì)象的西溝函數(shù)),然后再把左側(cè)值賦予右側(cè)的值。* 10.可能有點(diǎn)眉目了,如果在賦值運(yùn)算符中左側(cè)對(duì)象調(diào)用對(duì)象本身析構(gòu)函數(shù),可能會(huì)導(dǎo)致,賦值之前左側(cè)對(duì)象就失效了...為了防止這類事情發(fā)生,只能是逐個(gè)成員地去釋放即可.* 11.所有的純虛函數(shù)必須都要有定義,因?yàn)檫\(yùn)行時(shí)候才能知道調(diào)用哪個(gè)版本?如果不給虛函數(shù)定義,那么申明一個(gè)純虛函數(shù)。否則直接繼承父類的虛函數(shù)。* ***********************************************///友元,構(gòu)造函數(shù),拷貝構(gòu)造成員,(虛函數(shù)覆蓋)其它成員函數(shù),析構(gòu)函數(shù),數(shù)據(jù)成員 #ifndef QUERY_H #define QUERY_H#include <string> #include <iostream> #include <memory> #include <vector> #include <map> #include <set> #include "textquery.h" #include <algorithm>using namespace std;class Query_base;class WordQuery; class Binary_query;class NotQuery; class AndQuery; class OrQuery; class Query;/*類值版本的*/ class Query_base { friend class Query; protected:using line_no = TextQuery::line_no;//共有5個(gè)虛函數(shù)(成員函數(shù)):eval,rep,2 clones,~Query_base virtual QueryResult eval(const TextQuery &)const = 0; virtual string rep()const = 0; virtual Query_base *clone() && = 0; virtual Query_base *clone()const & = 0;protected: virtual ~Query_base()=default; //析構(gòu)函數(shù)可不可以protected?};class WordQuery :public Query_base{friend class Query;private:WordQuery(const string &s):query_word(s){}protected:WordQuery(const WordQuery &); //constructors may not be ref-qualified WordQuery(WordQuery && ); //constructors may not be ref-qualified WordQuery & operator=(const WordQuery &); WordQuery & operator=(WordQuery && );//覆蓋虛函數(shù) QueryResult eval(const TextQuery &t) const override {return t.query(query_word);} string rep()const override {return query_word;} WordQuery * clone()&& override; WordQuery * clone()const& override;~WordQuery();private: string query_word; };//拷貝控制成員 inline WordQuery::WordQuery(const WordQuery &w):query_word(w.query_word){} inline WordQuery::WordQuery(WordQuery && w):query_word(std::move(w.query_word)){} inline WordQuery & WordQuery::operator=(const WordQuery &w) {Query_base::operator=(w);//只是個(gè)形式,為了說(shuō)明語(yǔ)法形式,實(shí)際不起作用query_word = w.query_word;return *this; } inline WordQuery & WordQuery::operator=(WordQuery && w) {Query_base::operator=(std::move(w)); //可不可以這樣使用?光竊取基類部分,不會(huì)破壞基類部分外的部分嗎?query_word = std::move(w.query_word);return *this; }inline WordQuery * WordQuery::clone()const& {return new WordQuery(*this);//克隆就是把自己復(fù)制一次 } inline WordQuery * WordQuery::clone()&& {return new WordQuery(std::move(*this)); //復(fù)制自己,調(diào)用自己的拷貝構(gòu)造函數(shù) }//WordQuery類型析構(gòu)的時(shí)候,只要析構(gòu)在內(nèi)存中自己本身即可。 inline WordQuery::~WordQuery(){}class Query {public: friend Query operator&(const Query &,const Query &); friend Query operator|(const Query &,const Query &); friend Query operator~(const Query &);//構(gòu)造函數(shù)public: Query(const string &s); //constructors may not be cv-qualified (構(gòu)造函數(shù)用限定符是不合法的) //限定符就是const和volatile//拷貝控制成員 //note:constructors may not be ref-qualified(構(gòu)造函數(shù)不能加引用限定符) Query(const Query &); Query(Query &&); Query & operator=(const Query &); Query & operator=(Query &&);QueryResult eval(const TextQuery &)const; string rep()const; //clone函數(shù)/*開(kāi)始Query類自己定義了下面兩個(gè)函數(shù),后來(lái)發(fā)現(xiàn)是多余的,Query的clone函數(shù)只是他自己用與克隆自己的query部分,完全可以直接調(diào)用自己的query的clone就可以。此時(shí)如果clone是各個(gè)類的私有成員函數(shù),只需要Query是各個(gè)類的友元即可 Query_base* clone()const &; Query_base* clone()&&; *///析構(gòu)函數(shù) ~Query();private: Query_base * query; //請(qǐng)確定這里用不用重新分配內(nèi)存 Query(Query_base * q):query(q){} //主要是三個(gè)函數(shù)使用,不能是explicit的 };//構(gòu)造函數(shù) inline Query::Query(const string &s):query(new WordQuery(s)){}//拷貝控制成員 inline Query::Query(const Query &s):query(s.query->clone()){} //拷貝構(gòu)造函數(shù)inline Query::Query(Query &&s):query(s.query->clone()){s.query == nullptr;} //移動(dòng)構(gòu)造函數(shù)函數(shù),調(diào)用右值版本的cloneinline Query & Query::operator=(const Query &s) {//必須能正確處理自賦值的情況auto new_data = s.query->clone(); //新開(kāi)辟了內(nèi)存,現(xiàn)在new_data中有了s中的內(nèi)容//開(kāi)始自己是這樣寫的,后來(lái)發(fā)現(xiàn)不妥this->~Query(); ,改成下面的delete query;query = new_data;return *this; } inline Query & Query::operator=(Query && s) {auto new_data = s.query->clone(); //為了正確處理自賦值情況,先把右側(cè)值暫時(shí)存起來(lái)//這么寫會(huì)破壞整個(gè)對(duì)下你給this->~Query();delete query;query = new_data; //最后給左側(cè)對(duì)象賦值return *this;} inline Query::~Query(){//利用派生類對(duì)象的指針調(diào)用基類的虛函數(shù),就會(huì)發(fā)生動(dòng)態(tài)綁定delete query; //虛調(diào)用:利用基類指針調(diào)用虛析構(gòu)函數(shù)}inline QueryResult Query::eval(const TextQuery &t)const {return query->eval(t); } inline string Query::rep()const {return query->rep(); }class BinaryQuery:public Query_base{friend class Query;protected:BinaryQuery(const Query &l,const Query &r,const string & o):lhs(l),rhs(r),opSym(o){}BinaryQuery(const BinaryQuery &);BinaryQuery(BinaryQuery &&); //constructors may not be ref-BinaryQuery&operator=(const BinaryQuery &);BinaryQuery&operator=(BinaryQuery &&);string rep()const;~BinaryQuery();Query lhs,rhs;private:string opSym;};inline BinaryQuery::BinaryQuery(const BinaryQuery &b):lhs(b.lhs),rhs(b.rhs),opSym(b.opSym){} inline BinaryQuery::BinaryQuery(BinaryQuery &&b):lhs(std::move(b.lhs)),rhs(std::move(b.rhs)),opSym(std::move(b.opSym)){}inline BinaryQuery& BinaryQuery::operator=(const BinaryQuery &b) { //這里不用提前釋放lhs和rhs,因?yàn)閘hs和rhs有自己的拷貝賦值運(yùn)算符。賦值時(shí)候會(huì)調(diào)用它們的拷貝賦值運(yùn)算符 //先釋放左邊對(duì)象,然后再賦值 Query_base::operator=(b); //調(diào)用直接基類的拷貝賦值運(yùn)算符,給直接基類部分賦值 lhs = b.lhs; //會(huì)調(diào)用lhs和rhs的拷貝賦值運(yùn)算符,進(jìn)行賦值 rhs = b.rhs; opSym = b.opSym;return *this; } inline BinaryQuery& BinaryQuery::operator=(BinaryQuery &&b) { //基類部分該怎么表示Query_base::operator=(std::move(b)); lhs = std::move(b.lhs);rhs = std::move(b.rhs);opSym = std::move(b.opSym);return *this; }inline BinaryQuery::~BinaryQuery(){} //沒(méi)有本身動(dòng)態(tài)內(nèi)存,它也沒(méi)有動(dòng)態(tài)分配的成員指針inline string BinaryQuery::rep()const {return "(" + lhs.rep() + opSym + rhs.rep() + ")"; }class AndQuery:public BinaryQuery{friend class Query;friend Query operator&(const Query &,const Query&);public:AndQuery(const AndQuery &);AndQuery(AndQuery &&);AndQuery& operator=(const AndQuery &);AndQuery& operator=(AndQuery&&);private:AndQuery(const Query &l,const Query &r):BinaryQuery(l,r,"&"){}QueryResult eval(const TextQuery &t)const override;AndQuery* clone()const & override;AndQuery* clone()&& override;protected:~AndQuery(){ }; //如果少了這句,會(huì)怎么樣?};inline AndQuery::AndQuery(const AndQuery &a):BinaryQuery(a) {}inline AndQuery::AndQuery(AndQuery &&a):BinaryQuery(std::move(a)){}inline AndQuery& AndQuery::operator=(const AndQuery &a) {//賦值和構(gòu)造函數(shù)過(guò)程必須給直接基類賦值或者構(gòu)造,每個(gè)構(gòu)造函數(shù)必須負(fù)責(zé)直接基類部分的構(gòu)造BinaryQuery::operator=(a);//調(diào)用基類的拷貝賦值運(yùn)算符給基類部分賦值return *this; } inline AndQuery& AndQuery::operator=(AndQuery && a) {BinaryQuery::operator=(std::move(a)); //調(diào)用基類部分的移動(dòng)賦值運(yùn)算符移動(dòng)基類部分//AndQUery 沒(méi)有自己的數(shù)據(jù)成員,這里為空return *this; }inline QueryResult AndQuery::eval(const TextQuery &t)const { auto left = lhs.eval(t),right = rhs.eval(t); auto new_file = left.get_file(); auto new_set = make_shared<set<line_no>>(); set_intersection(left.begin(),left.end(),right.begin(),right.end(),inserter(*new_set,new_set->begin()));return QueryResult(new_file,new_set,rep()); }inline AndQuery * AndQuery::clone()const & {return new AndQuery(*this); //復(fù)制自己,調(diào)用自己的拷貝構(gòu)造函數(shù) }inline AndQuery * AndQuery::clone()&& {return new AndQuery(std::move(*this)); //復(fù)制自己,調(diào)用自己的拷貝構(gòu)造函數(shù) }class OrQuery:public BinaryQuery{friend class Query; friend Query operator|(const Query &,const Query &);OrQuery(const Query &l,const Query &r):BinaryQuery(l,r,"|"){} QueryResult eval(const TextQuery &)const; OrQuery * clone() const &; OrQuery * clone()&&;public:OrQuery(const OrQuery &); //constructors may not be cv-qualified(不能加限定符const) OrQuery(OrQuery &&); OrQuery& operator=(const OrQuery &); OrQuery& operator=(OrQuery &&);protected: ~OrQuery(){} //不希望普通用戶使用這個(gè)函數(shù)};//OrQuery沒(méi)有自己的數(shù)據(jù)成員,只要拷貝直接基類部分即可 inline OrQuery::OrQuery(const OrQuery &o):BinaryQuery(o) {} inline OrQuery::OrQuery(OrQuery && o):BinaryQuery(std::move(o)) {} inline OrQuery& OrQuery::operator=(const OrQuery &o ) {BinaryQuery::operator=(o);return *this; } inline OrQuery& OrQuery::operator=(OrQuery && o) {BinaryQuery::operator=(std::move(o));return *this; }inline QueryResult OrQuery::eval(const TextQuery &t)const { auto left = rhs.eval(t),right = rhs.eval(t); auto l = left.get_file(); auto r = right.get_file(); auto new_set = make_shared<set<line_no>>(); //這里不加圓括號(hào)會(huì)報(bào)錯(cuò)的 set_intersection(left.begin(),left.end(),right.begin(),right.end(),inserter(*new_set,new_set->begin()));return QueryResult(l,new_set,rep()); } inline OrQuery * OrQuery::clone()const& {return new OrQuery(*this); } inline OrQuery * OrQuery::clone()&& {return new OrQuery(std::move(*this)); }class NotQuery:public Query_base{friend class Query;friend Query operator~(const Query &);private: Query query; //唯一的一個(gè)數(shù)據(jù)成員 NotQuery(const Query &q):query(q){}NotQuery(const NotQuery &); NotQuery(NotQuery &&); //copy constructor and copy assignment operator may not be const //拷貝構(gòu)造函數(shù)和拷貝賦值運(yùn)算符都不能是const的,因?yàn)橐淖儗?duì)象的成員 NotQuery& operator=(const NotQuery &); NotQuery& operator=(NotQuery &&);protected: //虛函數(shù)在這個(gè)類中是什么角色?取決于直接基類和間接基類的定義 //虛函數(shù)如果沒(méi)有定義自己版本,會(huì)繼承最近的那個(gè)基類的版本 //string rep()const;直接基類已經(jīng)定義了一個(gè)可用的版本,這里會(huì)直接繼承 //rep()會(huì)先繼承最親的那個(gè)基類的代碼 QueryResult eval(const TextQuery &)const override; string rep()const override{return "~(" + query.rep() + ")";} NotQuery * clone()const & override; NotQuery * clone()&& override; ~NotQuery();}; inline //必須慎重 NotQuery::NotQuery(const NotQuery &n):query(n.query){} inline NotQuery::NotQuery(NotQuery &&n):query(std::move(n.query)){}inline NotQuery& NotQuery::operator=(const NotQuery &n) {Query_base::operator=(n);query = n.query;return *this; } inline NotQuery& NotQuery::operator=(NotQuery && n) {Query_base::operator=(std::move(n));query = std::move(n.query);return *this; }inline QueryResult NotQuery::eval(const TextQuery &t)const { auto ret = query.eval(t); auto file = ret.get_file(); auto new_set = make_shared<set<line_no>>(); auto n = file->size(); //file是一個(gè)vector的shared_ptr對(duì)象 auto iter = ret.begin(); for(int i = 0; i != n; ++i){if(i != *iter || iter == ret.end())new_set->insert(i);else{if(iter != ret.end())++ iter;}} return QueryResult(file,new_set,rep()); }inline NotQuery * NotQuery::clone()const & {return new NotQuery(*this); }inline NotQuery * NotQuery::clone()&& {return new NotQuery(std::move(*this)); }inline NotQuery::~NotQuery(){}//沒(méi)有自己的動(dòng)態(tài)成員inline Query operator&(const Query &l,const Query &r) {return new AndQuery(l,r); } inline Query operator|(const Query &l,const Query &r) {return new OrQuery(l,r); }inline Query operator~(const Query& q) {return new NotQuery(q); } #endif

?文件data.txt是外部讀取單詞的,自己隨意編寫的,內(nèi)容如下:

i am a good boy and you are a good boy too if you want to improve your c++ programming language you should write codes everyday best wishes

?在g++中執(zhí)行代碼

g++ main.cc query.cc textquery.cc -o 123

?執(zhí)行文件 123

./123

結(jié)果如下:

((my&good)|you) ((my&good)|you) occurs 3 times: (line 1) i am a good boy and you are a good boy too (line 2) if you want to improve your c++ programming language (line 4) you should write codes everyday

?未完待續(xù)。。。

補(bǔ)充一點(diǎn)知識(shí):讀者自己看吧,這點(diǎn)知識(shí)我自己作為初學(xué)者體會(huì)的,只可意會(huì),不可言傳。

#include <string> #include <iostream> using namespace std; class A{public:A() = default;virtual void print()const{cout << "A::print()" << endl;}int a = 111; int b = 11;}; class B : public A {public:B() = default;void print()const override{cout << "B::print()" << endl;}void f()const{cout << "B::f()" << endl;}private:int c= 222;int d = 22;};int main() { B b; A * pa = &b; pa->print(); A & ra = *pa; ra.print(); A * pb = &ra; pb->print(); pb->f();return 0; }

運(yùn)行結(jié)果:

1.cc: In function ‘int main()’: 1.cc:48:5: error: ‘class A’ has no member named ‘f’48 | pb->f();| ^

用我自己的語(yǔ)言來(lái)說(shuō),如果一旦把一個(gè)派生類對(duì)象放在了基類的引用或者指針上,那么這個(gè)對(duì)象再也不能通過(guò)后續(xù)的(直接賦值或者把指針解引用賦值,不能用new或者make_shared重新分配內(nèi)存)操作賦值給派生類對(duì)象了。而且,無(wú)論這個(gè)對(duì)象接下來(lái)通過(guò)多少次的解引用或者直接賦值,只要都是經(jīng)過(guò)指針或者引用傳遞,那么它終究還是一個(gè)動(dòng)態(tài)類型是派生類行的對(duì)象,而且靜態(tài)類型始終都是A類型。

要注意下面2個(gè)結(jié)論:

1.除了動(dòng)態(tài)綁定之外,那么其它部分都是按照靜態(tài)類型來(lái)解析的,比如說(shuō)“不存在基類向派生類的類型轉(zhuǎn)換。”

2.如果用new或者make_shared分配內(nèi)存。那么無(wú)論這個(gè)對(duì)象的靜態(tài)類型和動(dòng)態(tài)類型是否一致,那么始終結(jié)果都是按照靜態(tài)類型來(lái)分配的。也就是除了動(dòng)態(tài)綁定的事實(shí),其余都是按照以前靜態(tài)類型來(lái)操作的。也試試說(shuō),調(diào)用new(或者make_shared)分配新的內(nèi)存,靜態(tài)類型和動(dòng)態(tài)類型不一致的對(duì)象被破壞。new分配的結(jié)果的對(duì)象中,動(dòng)態(tài)類型和靜態(tài)類型是一致的(結(jié)果都是靜態(tài)對(duì)象類型)。

3.再進(jìn)一步,只要一直是用引用、指針、解引用+指針(把一個(gè)靜態(tài)類型和動(dòng)態(tài)類型不一致的類型先解引用再綁定到基類的指針上),那么“動(dòng)態(tài)綁定”的事實(shí)就可以一直持續(xù)下去。(千萬(wàn)不要中途去new或者make_shared)

4.關(guān)于更多相關(guān)內(nèi)容,參見(jiàn)如下百度百科鏈接

dynamic_cast_百度百科

把上面這個(gè)程序作如下改動(dòng),可以發(fā)現(xiàn)一個(gè)更有趣的事實(shí):

#include <string> #include <iostream> #include <memory> using namespace std; class A{public:A() = default;virtual void print()const{cout << "A::print()" << endl;}int a = 111; int b = 11;}; class B : public A {public:B() = default;void print()const override{cout << "B::print()" << endl;}void f()const{cout << "B::f()" << endl;}private:int c= 222;int d = 22;};int main() { B b; A * pa = &b; pa->print(); A & ra = *pa; ra.print(); A * pb = &ra; pb->print(); //pb->f(); //這句代碼是錯(cuò)誤的,發(fā)生動(dòng)態(tài)綁定的時(shí)候,只能調(diào)用虛函數(shù),不能調(diào)用普通成員。 A * pc = new A(*pa); //調(diào)用new分配內(nèi)存,動(dòng)態(tài)類型對(duì)象被破壞。new分配的結(jié)果對(duì)象pc中,動(dòng)態(tài)類型和靜態(tài)類型是一致的。 //下面一句錯(cuò)誤更厲害,g++編譯器會(huì)直接報(bào)如下錯(cuò)誤: //no matching function for call to 'B::B(&A)',也就是B類中不存在參數(shù)類型是A&的構(gòu)造函數(shù) A * pd = new B(*pa); pc -> print(); shared_ptr<A> pd = make_shared<A>(*pa); pd->print();return 0; }

g++編譯結(jié)果如下:

1.cc: In function ‘int main()’: 1.cc:51:19: error: no matching function for call to ‘B::B(A&)’51 | A * pd = new B(*pa);| ^ 1.cc:21:3: note: candidate: ‘constexpr B::B()’21 | B() = default;| ^ 1.cc:21:3: note: candidate expects 0 arguments, 1 provided 1.cc:18:7: note: candidate: ‘constexpr B::B(const B&)’18 | class B : public A| ^ 1.cc:18:7: note: no known conversion for argument 1 from ‘A’ to ‘const B&’ 1.cc:18:7: note: candidate: ‘constexpr B::B(B&&)’ 1.cc:18:7: note: no known conversion for argument 1 from ‘A’ to ‘B&&’ 1.cc:53:15: error: conflicting declaration ‘std::shared_ptr<A> pd’53 | shared_ptr<A> pd = make_shared<A>(*pa);| ^~ 1.cc:51:5: note: previous declaration as ‘A* pd’51 | A * pd = new B(*pa);| ^~

關(guān)于dynamic的一個(gè)例子,如下:

B * pc = dynamic_cast<B*>(pb); pc -> print(); pc->f();B &rb = dynamic_cast<B&>(ra); rb.print(); rb.f();

總結(jié)

以上是生活随笔為你收集整理的c++primer 5th第15章基础、课后习题自己解析、心得体会等的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。