【8-25】C++ Primer 習題答案

C++ Primer Answers


Part 1 基本語言

Part 2 容器和算法

Part 3 類和數據抽象

Part 4 面向對象編程與泛型編程

 

Part 5 高級主題

附錄:操做符優先級

Part 1 基本語言

Chapter 3

Exercise 3.1: 用適當的 using聲明,而不用 std::,訪問標準庫中名字的方法,從新編寫第 2.3 節的程序,計算一給定數的給定次冪的結果。

#include <iostream>
    using  std::cin;
    using std::cout;
    using std::endl;
    int main()
    {
        int base,exponent;
        long result=1;
        cout<<"Enter base and exponent:"<<endl;
        cin>>base>>exponent;
        if(exponent<0)
        {
            cout<<"Exponent can't be smaller than 0"<<endl;
            return -1;
        }
        else
        {
            for(int cnt=1;cnt<=exponent;++cnt)
            {
                result*=base;
            }
        }
        cout<<base<<" raised to the power of "<<exponent<<":"<<result<<endl;
        //cout << "Hello world!" << endl;
        return 0;
    }

Exercise 3.5: 編寫程序實現從標準輸入每次讀入一行文本。而後改寫程序,每次讀入一個單詞。

//讀入一行
    #include<iostream>
    using namespace std;
    int main()
    {
        string word;
        while(getline(cin,word))
        {
            cout<<word<<endl;
        }
        return 0;
    }
    //讀入單詞
    #include<iostream>
    using namespace std;
    int main()
    {
        string word;
        while(cin>>word)
        {
            cout<<word<<endl;
        }
        return 0;
    }

Exercise 3.8: 編一個程序,從標準輸入讀取多個 string 對象,把它們鏈接起來存放到一個更大的 string 對象中。並輸出鏈接後的 string 對象。接着,改寫程序,將鏈接後相鄰 string 對象以空格隔開。

#include<iostream>
    using namespace std;
    int main()
    {
    string result_str,str;
    cin>>result_str;
    while(cin>>str)
        result_str=result_str+" "+str;
    cout<<result_str<<endl;
        return 0;
    }

Exercise 3.10: 編一個程序,從 string 對象中去掉標點符號。要求輸入到程序的字符串必須含有標點符號,輸出結果則是去掉標點符號後的 string 對象。

#include<iostream>
    using namespace std;
    int main()
    {
    bool has_punct=false;
    string s,result_str;
    cout<<"Enter a String:"<<endl;
    getline(cin,s);
    for(string::size_type index=0;index!=s.size();++index)
    {
        if(ispunct(s[index]))
        {
            has_punct=true;
        }
        else
        {
            result_str+=s[index];
        }
    }
        if(has_punct)
            cout<<"Result:"<<result_str<<endl;
        else
        {
            cout<<"No punctuation character in the string"<<endl;
                    return -1;
        }
        return 0;
    }

Exercise 3.13: 讀一組整數到 vector 對象,計算並輸出每對相鄰元素的和。若是讀入元素個數爲奇數,則提示用戶最後一個元素沒有求和,並輸出其值。而後修改程序:頭尾元素兩兩配對(第一個和最後一個,第二個和倒數第二個,以此類推),計算每對元素的和,並輸出。

#include<iostream>
    #include<vector>
    using namespace std;
    int main()
    {
    vector<int> ivec;
    vector<int> sum;
    int ival;
    cout << "Enter numbers(Ctrl+Z to end):" << endl;
    while(cin>>ival)
            ivec.push_back(ival);
            if(ivec.size()==0)
            {
                cout<<"No elements"<<endl;
            }
    for (vector<int>::size_type index=0;index<ivec.size()-1;index=index+2)
    {
        if(ivec.size()%2!=0)
        {
            if(index<ivec.size()-1)
            {
                sum.push_back(ivec[index]+ivec[index+1]);
                //sum.push_back(ivec[index]+ivec[ivec.size()-2-index]);
            }
        }
        else
        {
             sum.push_back(ivec[index]+ivec[index+1]);
                // sum.push_back(ivec[index]+ivec[ivec.size()-1-index]);
        }
    }
        if(ivec.size()%2!=0)
        {
            cout<<"Last element is not computed:"<<endl;
        }
        cout << "Sum of each pair of adjacent elements in the vector:"<<endl;
        for (vector<int>::size_type index=0;index!=sum.size();++index)
            {
        cout<<sum[index]<<" ";
            }
        cout<<endl;
    return 0;
    }

Exercise 3.14: 讀入一段文本到 vector 對象,每一個單詞存儲爲 vector 中的一個元素。把 vector 對象中每一個單詞轉化爲大寫字母。輸出 vector 對象中轉化後的元素,每八個單詞爲一行輸出。

#include<iostream>
    #include<vector>
    #include<string>
    #include<cctype>
    using namespace std;
    int main()
    {
        cout<<"Enter some words:"<<endl;
        vector <string> istr;
        string iword;
        while(cin>>iword)
        istr.push_back(iword);
        cout<<"After transformation:"<<endl;
        for (vector<string>::size_type index=0;index<istr.size();++index)
        {
            for (string::size_type index2 = 0; index2 != istr[index].size(); ++index2)
            {
                istr[index][index2]=toupper(istr[index][index2]);
            }
            cout<<istr[index]<<"\t";
            if((index%8==0)&&(index>0))
            {
                cout<<endl;
            }
        }
        return 0;
    }

Exercise 3.17: 重作3.13

#include<iostream>
    #include<vector>
    using namespace std;
    int main()
    {
    vector<int> ivec;
    vector<int> sum;
    int ival;
    cout << "Enter numbers(Ctrl+Z to end):" << endl;
    while(cin>>ival)
    ivec.push_back(ival);
    if(ivec.size()==0)
    {
        cout<<"No elements"<<endl;
    }
    for(vector<int>::iterator it=ivec.begin();it!=ivec.end()-1;it=it+2)
    {
        if(ivec.size()%2!=0)
        {
            if(it<ivec.end()-2)
            {
                sum.push_back((*it)+*(it+1));
            }
        }
        else
        {
             sum.push_back((*it)+*(it+1));
        }
    }
        if(ivec.size()%2!=0)
        {
            cout<<"Last element is not computed:"<<endl;
        }
        cout << "Sum of each pair of adjacent elements in the vector:"<<endl;
    for(vector<int>::iterator it2=sum.begin();it2!=sum.end();++it2)
    {
        cout<<*it2<<" ";
    }
        cout<<endl;
    return 0;
    }

重作3.14

#include<iostream>
    #include<vector>
    #include<string>
    #include<cctype>
    using namespace std;
    int main()
    {
    cout<<"Enter some words:"<<endl;
    vector <string> istr;
    string iword;
    while(cin>>iword)
    istr.push_back(iword);
    cout<<"After transformation:"<<endl;
    for(vector<string>::iterator it=istr.begin();it!=istr.end();++it)
    {
        for(string::iterator it2=(*it).begin();it2!=(*it).end();++it2)
        {
            *it2=toupper(*it2);
        }
        cout<<*it<<"\t";
        if((it-istr.begin())%8==0&&it>istr.begin())
        {
            cout<<endl;
        }
    }
    return 0;
    }

Exercise 3.18:編寫程序來建立有 10 個元素的 vector 對象。用迭代器把每一個元素值改成當前值的 2 倍。

#include<iostream>
    #include<vector>
    using namespace std;
    int main()
    {
     vector<int> ivec(10,42);
     for (vector<int>::iterator it=ivec.begin();it!=ivec.end();++it)
     {
         *it=*it*2;
     }
     for (vector<int>::iterator it=ivec.begin();it!=ivec.end();++it)
     {
         cout<<*it<<"\t";
     }
        return 0;
    }

Chapter 4

Exercise 4.25: 編寫程序比較兩個 string 類型的字符串,而後編寫另外一個程序比較兩個C風格字符串的值。

#include<iostream>
    #include<string>
    #include<cstring>
    using namespace std;
    int main()
    {
        const int str_size=80;
        char *str1,*str2;
        str1=new char[str_size];
        str2=new char[str_size];
        if(str1==NULL||str2==NULL)
        {
            cout<<"No enough Memory"<<endl;
            return -1;
        }
        cout<<"Enter two strings:"<<endl;
        cin>>str1>>str2;
        int result;
        result=strcmp(str1,str2);
        if(result>0)
        cout << "\"" << str1 << "\"" << " is bigger than "<< "\"" << str2 << "\"" << endl;
        else if (result < 0)
        cout << "\"" << str2 << "\"" << " is bigger than "<< "\"" << str1 << "\"" << endl;
        else
        cout << "They are equal" << endl;
        delete[] str1;
        delete[] str2;
        return 0;
    }

Exercise 4.29:(a) 這兩段程序的功能是:執行一個循環次數爲1000000 的循環,在該循環的循環體中:建立一個新字符串,將一個已存在的字符串複製給新字符串,而後比較兩個字符串,最後釋放新字符串。

#include<iostream>
    #include<string>
    #include<cstring>
    using namespace std;
    int main()
    {
         const char *pc = "a very long literal string";
         const size_t len = strlen(pc +1);      // space to
         for (size_t ix = 0; ix != 1000000; ++ix) {
                     char *pc2 = new char[len + 1]; // allocate the space
                     strcpy(pc2, pc);               // do the copy
                     if (strcmp(pc2, pc))           // use the new string
                         ;   // do nothing
                     delete [] pc2;                 // free the memory
              }
             string str("a very long literal string");
                 // performance test on string allocation and copy
         for (int ix = 0; ix != 1000000; ++ix) {
                     string str2 = str; // do the copy, automatically allocated
                     if (str != str2)           // use the new string
                           ;  // do nothing
              }
        return 0;
    }

Exercise 4.30: 編寫程序鏈接兩個C風格字符串字面值,把結果存儲在一個C風格字符串中。而後再編寫程序鏈接兩個 string 類型字符串,這兩個 string 類型字符串與前面的C風格字符串字面值具備相同的內容。

  • (Cstring style)
#include <cstring>
        int main()
        {
        const char *cp1 = "Mary and Linda ";
        const char *cp2 = "are firends.";
        size_t len = strlen(cp1) + strlen(cp2);
        char *result_str = new char[len+1];
        strcpy(result_str, cp1);
        strcat(result_str, cp2);
        delete [] result_str;
        return 0;
        }
  • (C++ string style)
#include <string>
        using namespace std;
        int main()
        {
        const string str1("Mary and Linda ");
        const string str2("are firends.");
        string result_str;
        result_str = str1;
        result_str += str2;
        return 0;
        }

Exercise 4.31: 編寫程序從標準輸入設備讀入字符串,並把該串存放在字符數組中。描述你的程序如何處理可變長的輸入。提供比你分配的數組長度長的字符串數據測試你的程序。

#include <iostream>
    #include <string>
    #include <cstring>
    using namespace std;
    int main()
    {
        string in_str;// 用於讀入字符串的string 對象
        const size_t str_size = 10;
        char result_str[str_size+1];// 讀入字符串
        cout << "Enter a string(<=" << str_size<< " characters):" << endl;
        cin >> in_str;// 計算需複製的字符的數目
        size_t len = strlen(in_str.c_str());
        if (len > str_size)
        {
            len = str_size;
            cout << "String is longer than " << str_size<< " characters and is stored only "
            << str_size << " characters!" << endl;
        }
        // 複製len 個字符至字符數組result_str
        strncpy(result_str, in_str.c_str(), len);
        // 在末尾加上一個空字符(null 字符)
        result_str[len+1] = '\0';
        return 0;
    }

Exercise 4.32: 編寫程序用 int 型數組初始化 vector 對象。

Exercise 4.33: 編寫程序把 int 型 vector 複製給 int 型數組.

//int數組賦值給vector<int>
    #include <iostream>
    #include <vector>
    using namespace std;
    int main()
    {
        const size_t arr_size = 8;
        int int_arr[arr_size];// 輸入數組元素
        cout << "Enter " << arr_size << " numbers:" << endl;
        for (size_t ix = 0; ix != arr_size; ++ix)
        cin >> int_arr[ix];// 用int 型數組初始化vector 對象
        vector<int> ivec(int_arr, int_arr + arr_size);
        return 0;
    }
    //vector<int>賦值給int數組
    #include <iostream>
    #include <vector>
    using namespace std;
    int main()
    {
        vector<int> ivec;
        int ival;// 輸入vector 元素
        cout << "Enter numbers: (Ctrl+Z to end)" << endl;
        while (cin >> ival)
            ivec.push_back(ival);// 建立數組
        int *parr = new int[ivec.size()];// 複製元素
        size_t ix = 0;
        for (vector<int>::iterator iter = ivec.begin();iter != ivec.end(); ++iter, ++ix)
            parr[ix] = *iter;// 釋放數組
        delete [] parr;
        return 0;
    }

Exercise 4.34:編寫程序讀入一組 string 類型的數據,並將它們存儲在 vector 中。接着,把該 vector 對象複製給一個字符指針數組。爲 vector 中的每一個元素建立一個新的字符數組,並把該 vector 元素的數據複製到相應的字符數組中,最後把指向該數組的指針插入字符指針數組。

Exercise 4.35:輸出習題 4.34中創建的 vector 對象和數組的內容。輸出數組後,記得釋放字符數組。

#include <iostream>
    #include <string>
    #include <cstring>
    #include <vector>
    using namespace std;
    int main()
    {
        vector<string> ivec;
        string str;
        cout<<"Enter strings:"<<endl;
        while(cin>>str)
            ivec.push_back(str);
        char **s2ptr=new char*[ivec.size()];
        size_t ix=0;
        for (vector<string>::iterator it=ivec.begin();it!=ivec.end();++it,++ix)
        {
            char *strptr=new char[(*it).size()+1];
            strcpy(strptr,(*it).c_str());
            s2ptr[ix]=strptr;
          //  *s2ptr=strptr;
          //  s2ptr=s2ptr+1;
        }
        cout << "Content of character arrays:" << endl;
        for (ix =0; ix != ivec.size(); ++ix)
        cout << *(s2ptr+ix) << endl;
        // 釋放各個字符數組
        for (ix =0; ix != ivec.size(); ++ix)
        delete [] s2ptr[ix];
        // 釋放字符指針數組
        delete [] s2ptr;
        return 0;
    }

Chapter 5

Exercise 5.23:

預測下列程序的輸出是,並解釋你的理由。而後運行該程序,輸出的結果和你的預測的同樣嗎?若是不同,爲何?

int x[10];   int *p = x;
 cout << sizeof(x)/sizeof(*x) << endl;
 cout << sizeof(p)/sizeof(*p) << endl;

Answer:在表達式sizeof(x)中,x 是數組名,該表達式的結果爲數組x 所佔據的存儲空間的字節數,爲10 個int 型元素所佔據的字節數。表達式sizeof(*x)的結果是指針常量x 所指向的對象(數組中第一個int 型元素)所佔據的存儲空間的字節數。

表達式sizeof(p)的結果是指針變量p 所佔據的存儲空間的字節數。

表達式sizeof(*p)的結果是指針變量p 所指向的對象(一個int 型數據)所佔據的存儲空間的字節數。各類數據類型在不一樣的系統中所佔據的字節數不必定相同所以在不一樣的系統中運行上述程序段獲得的結果不必定相同。在Microsoft Visual C++ .NET 2003系統中,一個int 型數據佔據4 個字節,一個指針型數據也佔據4 個字節,所以運行上述程序獲得的輸出結果爲:101

Exercise 5.30: 下列語句哪些(若是有的話)是非法的或錯誤的?

(a) vector<string> svec(10);
         (b) vector<string> *pvec1 = new vector<string>(10);
         (c) vector<string> **pvec2 = new vector<string>[10];
         (d) vector<string> *pv1 = &svec;
         (e) vector<string> *pv2 = pvec1;
    
         (f) delete svec;
         (g) delete pvec1;
         (h) delete [] pvec2;
         (i) delete pv1;
         (j) delete pv2;
#include<string>
        #include<iostream>
        #include<vector>
        using namespace std;
        int main(void)
        {
        vector<string> svec(10);//
        vector<string> *pvec1 = new vector<string>(10);
        //建立一個字符串數組(vector<string>),用10初始化,這個數組含有10個string
        vector<string> *pvec2 = new vector<string>[10];
        //建立十個字符串數組(vector<string>),數組初始大小爲默認(0)
        vector<string> *pv1 = &svec;
        vector<string> *pv2 = pvec1;
        cout<<sizeof(svec)<<endl;
        cout<<sizeof(*pvec1)<<endl;
        cout<<sizeof(*pvec2)<<endl;
        cout<<sizeof(pv1)<<endl;
        cout<<sizeof(pv2)<<endl;
        delete pvec1;//只有一個對象 用delete
        delete [] pvec2;//有十個對象 用delete [];
        delete pv1;
        delete pv2;
        }

Chapter 6

Chapter 7

Exercise 7.1:形參和實參有什麼區別?

【解答】  形參是在函數定義的形參表中進行定義,是一個變量,其做用域爲整個函數。而實參出如今函數調用中,是一個表達式。進行函數調用時,用傳遞給函數的實參對形參進行初始化。

Exercise 7.13: 編寫程序計算數組元素之和。要求編寫函數三次,每次以不一樣的方法處理數組邊界。

#include<iostream>
    using namespace std;
    int sum1(const int *begin,const int *end )
    {
        int sum=0;
        while(begin!=end)
            sum+=*begin++;
        return sum;
    }
    int sum2(int a[],size_t size)
    {
        int sum=0;
        for(size_t ix=0;ix!=size;ix++)
        {
            sum+=a[ix];
        }
    return sum;
    }
    int sum3(int *begin,size_t size)
    {
        int sum=0;
        int*p=begin;
        while(p!=begin+size)
        {
            sum+=*p++;
        }
    return sum;
    }
    int sum4(const int (&a)[4])
    {
        int sum=0;
        for(size_t ix=0;ix!=4;ix++)
        {
            sum+=a[ix];
        }
    return sum;
    }
    int main()
    {
        int ia[]={1,2,3,4};
        int *p=ia;//等價於int *p=&ia[0]
        cout<<sizeof(ia)<<endl;//sizeof()
        cout<<(unsigned int)(&ia+1)-(unsigned int)(&ia)<<endl;//
        cout<<sizeof(p)<<endl;//sizeof(int *)
        //當數組做爲函數的參數進行傳遞時,該數組自動退化爲同類型的指針。下面是個例子
        //不論數組a 的容量是多少,sizeof(a)始終等於sizeof(char *)
        cout<<"sum1 is :"<<sum1(ia,ia+4)<<endl;//數組頭和數組尾
        cout<<"sum2 is :"<<sum2(ia,4)<<endl;//數組形參和數組長度
        cout<<"sum3 is :"<<sum3(ia,4)<<endl;//指針形參和數組長度
        cout<<"sum3 is :"<<sum4(ia)<<endl;//數組引用形參
        return 0;
    }
    //例子:
    #include <iostream>
    using namespace std;
    void foe(int[]);
    int main()
    {
            int myarray[] = {0,1,2,3,4,5};
            cout << sizeof(myarray) / sizeof(*myarray) << endl;
            foe(myarray);
            return 0;
    }
    void foe(int a[]){
            cout << sizeof(a) / sizeof(*a) << endl;
    }

Exercise 7.27: 解釋形參、局部變量和靜態局部變量的差異。並給出一個有效使用了這三種變量的程序例子。

(1) 形參的做用域爲整個函數體,而普通(非靜態)局部變量和靜態局部變量的做用域 爲:從定義處到包含該變量定義的塊的結束處。

(2) 形參由調用函數時所傳遞的實參初始化;而普通(非靜態)局部變量和靜態局部變量 一般用初始化式進行初始化,且均在程序執行流程第一次通過該對象的定義語句時進行初始化。靜態局部變量的初始化在整個程序執行過程當中進行一次。

(3) 形參和普通(非靜態)局部變量均屬自動變量,在每次調用函數時建立,並在函數 結束時撤銷;而靜態局部變量的生命期卻跨越了函數的屢次調用,它在建立後直到程序結束時才撤銷。

#include <iostream>
    using namespace std;
    void func();
    int n=1; //全局變量
    int main()
    {
        static int a; // 靜態局部變量
        int b= -10; // 局部變量
        cout <<"a:" <<a<<" b:" <<b<<" n:" <<n <<endl;
        b+=4;
        func();
        cout <<"a:" <<a<<" b:" <<b<<" n:" <<n <<endl;
        n+=10;
        func();
        return 0;
    }
    void func()
    {
    static int a=2; // 靜態局部變量
    int b=5; // 局部變量
    a+=2;
    n+=12;
    b+=5;
    cout <<"a:" <<a<<" b:" <<b<<" n:" <<n <<endl;
    }

Exercise 7.31&7.32&7.33

sales_item.h

#ifndef SALESITEM_H
    #define SALESITEM_H
    #include <iostream>
    #include <string>
    class sales_item
    {
    public:
        std::istream& input(std::istream &in);
        std::ostream& output(std::ostream &out) const;
        double avg_price()const;
        bool same_isbn(const sales_item &rhs) const
        {
            return isbn==rhs.isbn;
        }
        sales_item():units_sold(0),revenue(0.0){}
    private:    
        std::string isbn;
        unsigned int units_sold;
        double revenue;
    };
    #endif

sales_item.cpp

#include "main.h"
    #include <iostream>
    std::istream& sales_item::input(std::istream& in)
    {
        double price;
        in>>isbn>>units_sold>>price;
        if(in)
        {
            revenue=units_sold*price;
        }
        else
        {
            units_sold=0;
            revenue=0;
        }
        return in;
    }
    std::ostream& sales_item::output(std::ostream& out) const
    {
        out<<"isbn:"<<isbn<<"\t"<<"units_sold:"<<units_sold<<"\t"
        <<"revenue:"<<revenue<<"\t"<<"ave_price:"<<avg_price();
        return out;
    }
    double sales_item::avg_price() const
    {
        if(units_sold)
            return revenue/units_sold;
        else
            return 0;
    }
    using namespace std;
    int main()
    {
        sales_item item;
        cout<<"the transaction readed is:"<<endl;
        while(item.input(cin))
        {
            item.output(cout);
            cout<<endl;
        }
        return 0;
    }

Chapter 8

Exercise 8.2: 下面的聲明是錯誤的,指出其錯誤並改正之:

ostream print(ostream os);

答:標準庫類型不容許作複製或賦值操做。形參或返回類型不能爲流類型,因此上句代碼錯誤,由於它把流類型的對象當作了形參。應改成傳遞指向該對象的指針或引用:

ostream &print( ostream &os );

Exercise 8.3: 編寫一個函數,其惟一的形參和返回值都是 istream& 類型。該個函數應一直讀取流直到到達文件結束符爲止,還應將讀到的內容輸出到標準輸出中。最後,重設流使其有效,並返回該流。

#include <iostream>
    #include <stdexcept>
    using namespace std;
    istream& f(istream& in)
    {
        int ival;
        while(in>>ival,!in.eof())
        {
            if(in.bad())
                throw runtime_error("IO stream corrupted");
            if(in.fail())
            {
                cerr<<"bad data,try again:";
                in.clear();
                in.setstate(istream::eofbit);
                continue;
            }
            cout<<ival<<endl;
        }
        in.clear();
        return in;
    }
    int main()
    {
         cout<<"Input some numbers(ctrl+z end):\n";
         f(cin);
        return 0;
    }

Exercise 8.6: 因爲 ifstream 繼承了 istream,所以可將 ifstream 對象傳遞給形參爲 istream 引用的函數。使用第 8.2 節第一個習題編寫的函數讀取已命名的文件。

#include <iostream>
    #include <fstream>
    #include <stdexcept>
    using namespace std;
    istream& f(istream& in)
    {
        string ival;
        while(in>>ival,!in.eof())
        {
            if(in.bad())
                throw runtime_error("IO stream corrupted");
            if(in.fail())
            {
                cerr<<"bad data,try again:";
                in.clear();
                in.setstate(istream::eofbit);
                continue;
            }
            cout<<ival<<endl;
        }
        in.clear();
        return in;
    }
    int main()
    {
        string filename;
        cout<<"Input name of file(ctrl z end):\n";
        cin>>filename;
        ifstream readname;
        readname.open(filename.c_str(),ios::app);
        if(!readname)
        {
            cerr<<"error:cnannot open the input file:"<<filename<<endl;
            return -1;
        }
        f(readname);
        return 0;
    }

8.3 流狀態的查詢和控制

( 在保證程序的可靠性時常常遇到的問題 )

C和C++的標準裏歷來沒有定義過 fflush(stdin)。也許有人會說:「但是我用 fflush(stdin) 解決了這個問題,你怎麼能說是錯的呢?」的確,某些編譯器(如VC6)支持用 fflush(stdin)來清空輸入緩衝,可是並不是全部編譯器都要支持這個功能(linux下的 gcc 就不支持),由於標準中根本沒有定義fflush(stdin)。MSDN 文檔裏也清楚地寫着fflush on input stream is an extension to the C standardfflush 操做輸入流是對 C 標準的擴充)。

固然,若是你絕不在意程序的移植性,用 fflush(stdin) 也沒什麼大問題。如下是 C99 對 fflush 函數的定義:

/*
     * 流狀態的查詢和控制
     * 2010-3-26 wcdj
    */
    #include <iostream>
    #include <stdexcept>
    #include "stdio.h"
    using namespace std;
    void way1_cleario();
    void way2_cleario();
    int main()
    {
        int ival;
        cout<<"Enter an interger:";
        // read cin and test only for EOF;
        // loop is executed even if there are other IO failures
        while (cin>>ival, !cin.eof())
        {
            // input stream is corrupted; bail out
            if (cin.bad())
            {
                throw runtime_error("IO stream corrupted");
            }
            // bad input
            if (cin.fail())
            {
                cerr<<"bad data, try again/n";// warn the user
                // reset the stream
                //cin.clear(istream::failbit);// error, why?
                cin.clear();// ok
                way2_cleario();// eat excess bad stream
                //way2_cleario();
                continue;// get next input
            }
            // ok, to process ival
            cout<<"ok, to process ival"<<endl;
        }
        return 0;
    }
    void way1_cleario()
    {
        int ival=0;
        fflush(stdin); //不良代碼,C++ codeblock下運行經過,下面代碼輸入要帶空格
        // 在C中,刷新緩衝區可使用下面這樣的代碼
        // 經過 while 循環把輸入流中的餘留數據「吃」掉
        //一種移植性比較高的清空輸入緩衝區辦法
     //   while((ival=getchar())!='/n'&&ival!=EOF);
      //  clearerr( stdin );
    }
    void way2_cleario()
    {
        cin.ignore(200,' ');// 輸入的數據必須以空格分開,輸入數據必定要有空格
    }

Exercise 8.14: 使用 open_file 函數以及第 8.2 節第一個習題編寫的程序,打開給定的文件並讀取其內容。

#include <iostream>
    #include <fstream>
    #include <stdexcept>
    using namespace std;
    istream& f(istream& in)
    {
        string ival;
        while(in>>ival,!in.eof())
        {
            if(in.bad())
                throw runtime_error("IO stream corrupted");
            if(in.fail())
            {
                cerr<<"bad data,try again:";
                in.clear();
                in.setstate(istream::eofbit);
                continue;
            }
            cout<<ival<<endl;
        }
        in.clear();
        return in;
    }
    bool open_file(const string &file)
    {
        fstream fopen;
        fopen.clear();
        fopen.open(file.c_str());
        if(!fopen)
        {
            cerr<<"cannot open the file"<<endl;
            return -1;
        }
        string s;
      //  while(fopen>>s)
      //  {
           // cout<<s<<" ";
       // }
         f(fopen);
        fopen.close();
        return 1;
    }
    int main()
    {
        cout<<"input name of file is: \n";
        string fName;
        cin>>fName;
        open_file(fName);
        return 0;
    }

Exercise 8.16: 編寫程序將文件中的每一行存儲在 vector 容器對象中,而後使用 istringstream 從 vector 裏以每次讀一個單詞的形式讀取存儲的行

#include <iostream>
    #include <fstream>
    #include <sstream>
    #include <string>
    #include <vector>
    using namespace std;
    int main()
    {
        string line,word;
        ifstream input("out.txt");
        if(!input)
        {
            cerr<<"error:can not open input file:"<<endl;
            return -1;
        }
        // 打開後,將文件內容讀入string類型的vector容器,每一行存儲爲
        // 該容器對象的一個元素。
        vector<string> fileword;
        while(getline(input,line))
        {
            fileword.push_back(line);
            input.clear();
        }
        input.close();
        vector<string>::const_iterator it =fileword.begin();
        while(it!=fileword.end())
        {
            istringstream divword(*it);
            while (divword>>word)
            {
                cout<<word<<",";
            }
            cout<<endl;
            ++it;
        }
        return 0;
    }

8.4 文件讀寫

#include <fstream>
    #include <iostream>
    using namespace std;
    const char * filename = "out.txt";
    int main()
    {
        ofstream out;//寫入文件處理
        out.open("out.txt",ios_base::app);
         if (out.is_open())
        {
             out << "This is a line.";
             out << "This is another line.\n";
             out.close();
             out.clear();
        }
        char buffer0[256];
        ifstream in("out.txt");//讀取文件處理
        if (! in.is_open())
        {
           cout << "Error opening file";
           return 0;
        }
           while (!in.eof() )
        {
            in.getline (buffer0,100);
            cout << buffer0 << endl;
        }
    }

8.5. 字符串流

#include <sstream>
    #include <iostream>
    using namespace std;
    int main()
    {
        int val1=512,val2=1024;
        ostringstream format_message;
        format_message<<"val1:"<<val1<<"~"<<"val2:"<<val2<<"\n";
        //format_message<<"val1:"<<val1<<"\n"<<"val2:"<<val2<<"\n";//這種輸出,獲得val1爲0
        istringstream input_istring(format_message.str());
        cout <<format_message.str();
        string dump;
        input_istring >> dump >> val1 >> dump >> val2;
        cout << val1 << " " << val2 << endl;  // prints 512 1024
       return 0;
    }

Part 2 容器和算法

Chapter 9

Exercise 9.12: 編寫一個函數,其形參是一對迭代器和一個 int 型數值,實如今迭代器標記的範圍內尋找該 int 型數值的功能,並返回一個 bool 結果,以指明是否找到指定數據。

#include <iostream>
    #include <vector>
    using namespace std;
    typedef vector <int>::iterator ITER;
    bool find_int(ITER begin,ITER end,int i)
    {
    //    assert( begin <= end );
        if ( begin > end )
            cout << " iterator error." << endl;
        for (ITER it=begin;it!=end;++it)
        {
            if ((*it)==i)
            {
                return true;
            }
        }
          return false;
    }
    int main()
    {
       int ia[]={0,1,2,3,4,5};
       vector<int> ivec(ia,ia+6);
       bool find=false;
       find=find_int(ivec.begin(),ivec.end(),3);
       if(find)
       {
           cout<<"we got 3 in ia[]."<<endl;
       }
       else
        cout<< "there is no 3 in ia[]."<<endl;
    }

Exercise 9.13: 重寫程序,查找元素的值,並返回指向找到的元素的迭代器。確保程序在要尋找的元素不存在時也能正確工做。

#include <iostream>
    #include <vector>
    using namespace std;
    typedef vector <int>::iterator ITER;
    ITER find_int(ITER begin,ITER end,int i,ITER &ref)
    {
    //    assert( begin <= end );
        if ( begin > end )
            cout << " iterator error." << endl;
        for (ITER it=begin;it!=end;++it)
        {
            if ((*it)==i)
            {
                ref=it;
            }
        }
        return ref;
    }
    int main()
    {
       int ia[]={0,1,2,3,4,5};
       vector<int> ivec(ia,ia+6);
       // bool find=false;
       ITER ref=ivec.end();
       ITER findit=find_int(ivec.begin(),ivec.end(),3,ref);
       if(findit!=ivec.end())
       {
           cout<<"we got 3 in ia[]."<<endl;
       }
       else
        cout<< "there is no 3 in ia[]."<<endl;
    }

Exercise 9.14: 使用迭代器編寫程序,從標準輸入設備讀入若干 string 對象,並將它們存儲在一個 vector 對象中,而後輸出該 vector 對象中的全部元素。

#include <iostream>
    #include <vector>
    #include <string>
    using namespace std;
    int main()
    {
        cout << "\tInput some strings ( ctrl+z to end ):" << endl;
        vector<string> strVec;
        string str;
        while ( cin >> str )
        {
            strVec.push_back( str );
        }
        cout << " All the member of the vector<string> strVec are:\n";
        for ( vector<string>::iterator it = strVec.begin(); it != strVec.end(); ++it )
        {
            cout << *it << endl;
        }
        return 0;
    }

Exercise 9.18: 編寫程序將 int 型的 list 容器的全部元素複製到兩個 deque 容器中。list 容器的元素若是爲偶數,則複製到一個 deque 容器中;若是爲奇數,則複製到另外一個 deque 容器裏。

#include <iostream>
    #include <list>
    #include <deque>
    #include <string>
    using namespace std;
    int main()
    {
        cout<<"input some int numbers:"<<endl;
        list<int> ilist;
        int iVal;
        while(cin>>iVal)
        {
            ilist.push_back(iVal);
        }
        deque<int> iOddDeque,iEvenDeque;
        for(list<int>::iterator it=ilist.begin();it!=ilist.end();++it)
        {
            if(*it%2==0)
            {
                iEvenDeque.push_back(*it);
            }
            else if(*it%2==1)
            {
                iOddDeque.push_back(*it);
            }
        }
        cout<<"All numbers inputed,the odd numbers are:"<<endl;
        for(deque<int>::iterator it=iOddDeque.begin();it!=iOddDeque.end();++it)
        {
            cout<<*it<<" ";
        }
        cout<<"\nAll the number inputed,the even numbers are:"<<endl;
        for(deque<int>::iterator it=iEvenDeque.begin();it!=iEvenDeque.end();++it)
        {
            cout<<*it<<" ";
        }
        return 0;
    }

Exercise 9.19: 假設 iv 是一個 int 型的 vector 容器,下列程序存在什麼錯誤?如何改正之。

vector<int>::iterator mid = iv.begin() + iv.size()/2;
     while (vector<int>::iterator iter != mid)
         if (iter == some_val)
             iv.insert(iter, 2 * some_val);

(1)當執行it.insert操做以後,迭代器 mid 就失效了,是由於 iv.end() 失效了。

(2)迭代器iter沒有初始化;

(3)if語句中錯誤,由於if ( *iter == some_val ) 可改成:

vector<int>::iterator iter = iv.begin();
    while ( iter != iv.begin() + iv.end() / 2 )
    {
             if ( *iter == some_val )
             {
                       it.insert ( iter, 2 * some_val );
                       iter += 2; // important
             }
             else 
                       ++iter;
    }

Exercise 9.26:

假設有以下 ia 的定義,將 ia 複製到一個 vector 容器和一個 list 容器中。
使用單個迭代器參數版本的 erase 函數將 list 容器中的奇數值元素刪除掉,而後將 vector 容器中的偶數值元素刪除掉。int ia[] = { 0, 1, 1, 2, 3, 5, 8, 13, 21, 55, 89 };

#include <iostream>
    #include <list>
    #include <vector>
    #include <string>
    using namespace std;
    int main()
    {
        int ia[]={0,1,1,2,2,3,5,8,8,13,21,55,89};
        vector<int> ivec(ia,ia+13);
        list<int> ilist(ia,ia+13);
        cout<<"before erase,the elements of ivec are:"<<endl;
        for(vector<int>::iterator it=ivec.begin();it!=ivec.end();++it)
        {
            cout<<*it<<" ";
        }
        cout<<"\nbefore erase,the elements of ilist are:"<<endl;
        for(list<int>::iterator it=ilist.begin();it!=ilist.end();++it)
        {
            cout<<*it<<" ";
        }
        for(vector<int>::iterator iter=ivec.begin();iter!=ivec.end();)
        {
                    cout<<"\nbefore erase *it:"<<*iter<<endl;
            if((*iter)%2==0)
            {
                iter=ivec.erase(iter);//erase擦除iter迭代器後iter爲野指針,要把下一個迭代器值付給它
            }
            else
            {
                iter++;//不刪除就向後搜索
            }
                    cout<<"after erase *it:"<<*iter<<endl;
        }
        for(list<int>::iterator iter=ilist.begin();iter!=ilist.end();++iter)
        {
              cout<<"\n2:before erase *it:"<<*iter<<endl;
            if((*iter)%2==1)
            {
                iter=ilist.erase(iter);//第二種寫法,擦除以後將指針往前進一個
                       --iter;
            }
             cout<<"2:after erase *it:"<<*iter<<endl;
        }
        cout << "\n  After erase, the elements of ivec are:" << endl;
        for ( vector<int>::iterator it = ivec.begin(); it != ivec.end(); ++it )
        {
                cout << *it << " ";
        }
        cout << "\n  After erase, the elements of list are:" << endl;
        for ( list<int>::iterator it = ilist.begin(); it != ilist.end(); ++it )
        {
                cout << *it << " ";
        }
        return 0;
    }

Exercise 9.28: 編寫程序將一個 list 容器的全部元素賦值給一個 vector 容器,其中 list 容器中存儲的是指向 C 風格字符串的 char* 指針,而 vector 容器的元素則是 string 類型。

#include <iostream>
    #include <list>
    #include <vector>
    #include <string>
    #include <algorithm>
    using namespace std;
    int main()
    {
        char *c_arr[] = { "one", "two", "three" };
        list<char*> pLst;
        pLst.assign( &c_arr[0], &c_arr[0]+3 );
        cout << "\tAll the members in the list<char*> pLst are:\n";
        for ( list<char*>::iterator it = pLst.begin(); it != pLst.end(); ++it )
        {
            cout << *it << " ";
        }
        vector<string> strVec;
        strVec.assign( pLst.begin(), pLst.end() );
        cout << "\n\tAfter assignment from list, the vector<string> strVec are:\n";
        for ( vector<string>::iterator it = strVec.begin(); it != strVec.end(); ++it )
        {
            cout << *it << " ";
        }
        cout << endl;
        return 0;
    }

Exercise 9.38: 已知有以下 string 對象:"ab2c3d7R4E6", 編寫程序尋找該字符串中全部的數字字符,而後再尋找全部的字母字符。以兩種版本編寫該程序:第一個版本使用 find_first_of 函數,而第二個版本則使用 find_first_not_of 函數。

#include <iostream>
    #include <list>
    #include <vector>
    #include <string>
    #include <algorithm>
    using namespace std;
    int main()
    {
    string s1("ab2c3d7r4e6");
    vector <string::size_type> index;
    string s2("0123456789");
    string::size_type ix=0;
    while((ix=s1.find_first_not_of(s2,ix))!=string::npos)
    {
        //int id=static_cast<int> (ix);
        index.push_back(ix);
        ++ix;
    }
    for(vector <string::size_type> ::iterator it=index.begin();it!=index.end();++it)
        {
            cout<<s1[*it]<<endl;
        }
    return 0;
    }

Exercise 9.39:

已知有以下 string 對象:

string line1 = "We were her pride of 10 she named us:";
     string line2 = "Benjamin, Phoenix, the Prodigal"
     string line3 = "and perspicacious pacific Suzanne";
     string sentence = line1 + ' ' + line2 + ' ' + line3;

編寫程序計算 sentence 中有多少個單詞,並指出其中最長和最短的單詞。若是有多個最長或最短的單詞,則將它們所有輸出。

#include <iostream>
    #include <list>
    #include <vector>
    #include <string>
    #include <algorithm>
    using namespace std;
    int main()
    {
         string line1 = "We were her pride of 10 she named us:";
         string line2 = "Benjamin, Phoenix, the Prodigal";
         string line3 = "and perspicacious pacific Suzanne";
         string sentence = line1 + ' ' + line2 + ' ' + line3;
         string separators(" :\t,\v\r\n\f");//分隔字符
         for(size_t ix=0;ix<separators.size();++ix)
         {
          cout<<" "<<separators[ix]<<" ";
         }
         cout<<endl;
         string word;
         string::size_type maxlen,minlen,wordlen;
         vector<string> longestword,shortestword;
         string::size_type startpos ,endpos=0;
         size_t cnt=0;
            cout << "\n The sentence is :\n" << sentence << endl;
         while((startpos=sentence.find_first_not_of(separators,endpos))!=string::npos)
         {
             ++cnt;
             endpos=sentence.find_first_of(separators,startpos);
             if(endpos==string::npos)//若是到達句子的末尾,則認爲這個句子只有一個單詞
             {
                 wordlen=sentence.size()-startpos;
             }
             else //不然的話該單詞長度爲末尾點減初始點阿
             wordlen=endpos-startpos;
             word.assign(sentence.begin()+startpos,sentence.begin()+startpos+wordlen);
            if(cnt==1)
            {
                maxlen=minlen=wordlen;
                longestword.push_back(word);
                shortestword.push_back(word);
            }
            else //處理最長字符和最短字符
            {
                if(wordlen>maxlen)
                {
                    maxlen=wordlen;
                    longestword.clear();
                    longestword.push_back(word);
                }
                else if(wordlen==maxlen)
                {
                    longestword.push_back(word);
                }
                if(wordlen<minlen)
                {
                    minlen=wordlen;
                    shortestword.clear();
                    shortestword.push_back(word);
                }
                else if(wordlen==minlen)
                {
                    shortestword.push_back(word);
                }
            }
         }
         cout << "\n There are " << cnt << " words in the sentence." << endl;
         vector<string>::iterator iter;
         // out the longest word
         cout << "\n longest word :" << endl;
         iter = longestword.begin();
         while ( iter != longestword.end() )
         {
            cout << *iter++ << endl;
         }
            // out the shortest word
         cout << "\n shortest word :" << endl;
         iter = shortestword.begin();
         while ( iter != shortestword.end() )
         {
            cout << *iter++ << endl;
         }
    return 0;
    }

Exercise 9.43: 使用 stack 對象處理帶圓括號的表達式。遇到左圓括號時,將其標記下來。而後在遇到右加括號時,彈出 stack 對象中這兩邊括號之間的相關元素(包括左圓括號)。接着在 stack 對象中壓入一個值,用以代表這個用一對圓括號括起來的表達式已經被替換。

#include <iostream>
    #include <string>
    #include <stack>
    #include <deque>
    using namespace std;
    int main( )
    {
        stack<char> sExp;
        string strExp;
        cout << " Input a expression: ";
        cin >> strExp;
        // deal the sExp
        string::iterator it = strExp.begin();
        while ( it != strExp.end() )
        {
            if ( *it != ')' )
                sExp.push( *it );//若是不是)則將字符push進來,一直push到(爲止
            else
            {
                while ( ( sExp.top() != '(' ) && !sExp.empty() )//檢測到),如今pop頂元素,一直到(爲止
                {
                    sExp.pop();
                }
            //  sExp.pop();
                if ( sExp.empty() )//若是檢測不到(則沒有匹配到(
                cout << " It's not matched. " << endl;
                else
                {
                    sExp.pop();
                    sExp.push('@');
                }
            }
            ++it;
        }
        // show out the elements of the stack
        cout << "\nThe elements of the stack are:" << endl;
        while ( ! sExp.empty() )
        {
            cout << sExp.top() << endl;
            sExp.pop();
        }
        return 0;
    }

Chapter 10

Exercise 10.1:編寫程序讀入一系列 string 和 int 型數據,將每一組存儲在一個 pair 對象中,而後將這些 pair 對象存儲在 vector 容器裏。

#include <iostream>
    #include <utility>
    #include <string>
    #include <vector>
    using namespace std;
    int main()
    {
    //    typedef pair <string,string> Author;
    //    pair <string,string> author("James","Smith");
    //    Author proud("Marvell","Joy");
    //    cout<<author.first<<"\t"<<author.second<<endl;
    //    cout<<proud.first<<"\t"<<proud.second<<endl;
    //pair<string,string> next_auth;
    //string first,last;
    //while (cin>>first>>last)
    //{
    //    next_auth=make_pair(first,last);
    //    cout<<next_auth.first<<"\t"<<next_auth.second;
    //}
        string str;
        int ival;
        vector< pair<string,int> > pairVec;
            while(cin>>str>>ival)
                {
                    pairVec.push_back(make_pair(str,ival));
                }
        cout<<"\nThe content of pairVec is : \n";
            for(vector< pair<string,int> >::iterator it=pairVec.begin();it!=pairVec.end();++it)
                {
                    cout<<it->first<<"\t"<<it->second<<endl;
                }
        return 1;
    }

Exercise 10.6: 能否定義一個 map 對象以 vector ::iterator 爲鍵關聯 int 型對象?若是以 list ::iterator 關聯 int?對於每種狀況,若是不容許,請解釋其緣由。

支持第一種,不支持list ::iterator 由於不支持比較符號操做

Exercise 10.14:

What is the difference between the map operations count and find?

map 容器的 count 和 find 運算有何區別?

Exercise 10.15:

What kinds of problems would you use count to solve? When might you use find instead?

你認爲 count 適合用於解決哪一類問題?而 find 呢?

Exercise 10.16:

Define and initialize a variable to hold the result of a call to find on a map from string to vector of int.

定義並初始化一個變量,用來存儲調用鍵爲 string、值爲 vector 的 map 對象的 find 函數的返回結果。

count 返回被尋找元素的次數,結果爲0或者1.find函數返回被尋找元素的迭代器。
count用來查找元素是否存在,find用來查找該鍵值對應的元素

10.17 The Word Transformation Program 單詞轉換程序

#include <iostream>
    #include <utility>
    #include <string>
    #include <vector>
    #include <map>
    #include <fstream>
    #include <sstream>
    using namespace std;
    int main()
    {
    //    typedef pair <string,string> Author;
    //    pair <string,string> author("James","Smith");
    //    Author proud("Marvell","Joy");
    //    cout<<author.first<<"\t"<<author.second<<endl;
    //    cout<<proud.first<<"\t"<<proud.second<<endl;
    //    pair<string,string> next_auth;
    //    string first,last;
    //    while (cin>>first>>last)
    //    {
    //        next_auth=make_pair(first,last);
    //        cout<<next_auth.first<<"\t"<<next_auth.second;
    //    }
    //    string str;
    //    int ival;
    //    vector< pair<string,int> > pairVec;
    //    while(cin>>str>>ival)
    //    {
    //        pairVec.push_back(make_pair(str,ival));
    //    }
    //    cout<<"\nThe content of pairVec is £º \n";
    //    for(vector< pair<string,int> >::iterator it=pairVec.begin(); it!=pairVec.end(); ++it)
    //    {
    //        cout<<it->first<<"\t"<<it->second<<endl;
    //    }
    //    map<string,int> WordCount;
    //    string word;
    //    while(cin>>word)
    //    {
    //        // ++WordCount[word];
    //        // cout<<"The word "<<word<<" appears for "<<WordCount[word]<<" times "<<endl;
    //        //WordCount.insert(make_pair(word,1));
    //        pair<map<string,int>::iterator,bool> ret=WordCount.insert(make_pair(word,1));
    //        if(!ret.second)
    //            ++ret.first->second;
    //
    //    }
    //    map<string,int>::iterator map_it=WordCount.begin();
    //   // while(map_it!=WordCount.end())
    //    {
    //
    ////        cout<<map_it->first<<" "<<map_it->second<<endl;
    ////        ++map_it;
    //        int occurs = 0;
    //        if (WordCount.count("foobar")&&WordCount.find("foobar")!=WordCount.end())
    //        {
    //            occurs = WordCount["foobar"];
    //            cout<<"foobar occurs"<<occurs<<" times ";
    //        }
        map<string,string> trans_map;
        string key,value;
        ifstream map_file("C://Users//allen//Desktop//mapfile.txt");
        ifstream input("C://Users//allen//Desktop//input.txt");
        if(map_file.is_open()&&input.is_open())
        {
            while(map_file>>key>>value)
                trans_map.insert(make_pair(key,value));
                string line;
            while(getline(input,line))
            {
                  istringstream stream(line);
                  string word;
                  bool firstword=true;
                  while(stream>>word)
                  {
                      map<string,string>::const_iterator map_it=trans_map.find(word);
                      if(map_it!=trans_map.end())
                      {
                          word=map_it->second;
                      }
                      if(firstword)
                        firstword=false;
                      else
                        cout<<" ";
                      cout<<word;
                  }
                  cout<<endl;
            }
        }
        else
        {
    //        throw runtime_error("no transformation file");
                cout<<"No file information"<<endl;
        }
        return 1;
    }

Exercise 10.23: 編寫程序將被排除的單詞存儲在 vector 對象中,而不是存儲在 set 對象中。請指出使用 set 的好處。

#include <iostream>
    #include <utility>
    #include <string>
    #include <vector>
    #include <map>
    #include <fstream>
    #include <sstream>
    #include <set>
    using namespace std;
    void restricted_wc(vector<string> strVec,map<string,int>&wordCount)
    {
        set<string> excluded;
        for ( vector<string>::iterator it = strVec.begin(); it != strVec.end(); ++it )
        {
            excluded.insert( *it );
        }
        string word;
        cout << " Input some words to count the words in wordCount(map) ( ctrl + z to end): "
             << endl;
        cin.clear();
        while ( cin >> word )
        {
            if ( !excluded.count( word ) )
                ++wordCount[ word ];
        }
    }
    int main()
    {
        cout << " Input some words to vector<string> excluded ( ctrl + z to end): " << endl;
        vector<string> excludedVec;
        string excludedWord;
        while ( cin >> excludedWord )
            excludedVec.push_back( excludedWord );
        map<string, int > wordCount;
        restricted_wc( excludedVec, wordCount );
        cout << "\n\tShow out the map:wordCount: " << endl;
        for ( map< string, int >::iterator it = wordCount.begin(); it != wordCount.end(); ++it )
        {
            cout << " The word '" << (*it).first << "' appears for " << (*it).second << " times. " << endl;
        }
        return 1;
    }

Exercise 10.26:編寫程序創建做者及其做品的 multimap 容器。使用 find 函數在 multimap 中查找元素,並調用 erase 將其刪除。當所尋找的元素不存在時,確保你的程序依然能正確執行。

#include <iostream>
    #include <map>
    #include <utility>
    #include <string>
    using namespace std;
    int main()
    {
    //    cout << "Hello world!" << endl;
        multimap<string,string> mmapAuthor;
        string author,book;
        cout<<"input Author and his books:\n";
        while(cin>>author>>book)
        {
            mmapAuthor.insert(make_pair(author,book));
        }
        string searchitem;
        cout<<"which author you wanna search: ";
        cin.clear();
        cin>>searchitem;
        multimap<string,string>::iterator iter=mmapAuthor.find(searchitem);
        typedef multimap<string,string>::size_type sz_type;
        sz_type amount=mmapAuthor.count(searchitem);//count返回查找元素的數量,find返回第一個指針
        for(sz_type cnt=0; cnt!=amount; ++cnt,++iter)
        {
            cout<<"\n we got the author: "<<iter->first<<endl<<"\t==>>his book:\t"<<iter->second<<endl;
        }
        amount=mmapAuthor.erase(searchitem);
        if(amount)
        {
            cout<<"\n we have erase"<<amount<<"books of the author"<<endl;
        }
        cout<<endl;
        return 0;
    }
multimap< string, string > mmapAuthor;
        string author, book;
        cin.clear();
        cout << " \t=>> Input Author and his Book( ctrl + z to end ):\n";
        while ( cin >> author >> book )
        {
            mmapAuthor.insert( make_pair( author, book ) );
        }
        typedef multimap<string, string >::iterator author_it;
        author_it iter = mmapAuthor.begin();
        if ( iter == mmapAuthor.end() )
        {
            cout << "\n\t Empty multimap! " << endl;
            return 0;
        }
        string currAuthor, preAuthor;
        do
        {
            currAuthor = iter->first;
            if ( preAuthor.empty() || currAuthor[0] != preAuthor[0] )
            {
                cout << "Author Names Beginning with ' "
                    << iter->first[0] << " ' : " << endl;
            }
            cout << currAuthor;
            pair< author_it, author_it > pos = mmapAuthor.equal_range( iter->first );
            while ( pos.first != pos.second )
            {
                cout << ", " << pos.first->second;
                ++pos.first;
            }
            cout << endl;
            iter = pos.second;
            preAuthor = currAuthor;
        } while ( iter != mmapAuthor.end() );

10.32 test_query 程序

#include <iostream>
    #include <utility>
    #include <string>
    #include <vector>
    #include <map>
    #include <fstream>
    #include <sstream>
    #include <set>
    using namespace std;
    class TextQuery
    {
    public:
        typedef vector<string>::size_type line_no;
        void read_file(ifstream &is){store_file(is);build_map();}
        set<line_no> run_query(const string&) const;
        string text_line(line_no) const;
    private:
        void store_file(ifstream&);
        void build_map();
        vector<string> lines_of_text;
        map< string,set<line_no> > word_map;
    };
    void TextQuery::store_file(ifstream& is)
    {
        string line;
        while(getline(is,line))
        {
            lines_of_text.push_back(line);
        }
    }
    void TextQuery::build_map()
    {
        for (line_no line_num=0;line_num!=lines_of_text.size();++line_num)
        {
            istringstream line(lines_of_text[line_num]);
            string word;
            while(line>>word)
            {
                word_map[word].insert(line_num);//word_map[word]==set
            }
        }
    }
    set<TextQuery::line_no> TextQuery::run_query(const string&query_word) const
    {
        map< string,set<line_no> >::const_iterator loc=word_map.find(query_word);
        if(loc==word_map.end())
            return set<line_no>();
        else
            return loc->second;
    }
    string TextQuery::text_line(line_no line) const
    {
        if(line<lines_of_text.size())
            return lines_of_text[line];
      //  throw std::out_of_range("line number out of range");
    }
    void print_results(const set<TextQuery::line_no>& locs,const string& sought,const TextQuery &file)
    {
        typedef set<TextQuery::line_no> line_nums;
        line_nums::size_type size1 =locs.size();
        cout<<"\n"<<sought<<" occurs "<<size1<<" "<<" times "<<endl;
        line_nums::const_iterator it=locs.begin();
        for(;it!=locs.end();++it)
        {
            cout<<"\t(line "<<(*it)+1<<")"<<file.text_line(*it)<<endl;
        }
    }
    int main()
    {
        ifstream infile("C://Users//allen//Desktop//input.txt");
        TextQuery tq;
        tq.read_file(infile);
        while(true)
        {
            cout<<"Enter a word to look for, or q to quit it: ";
            string s;
            cin>>s;
            if(!cin||s=="q")
                break;
            set<TextQuery::line_no> locs=tq.run_query(s);
            print_results(locs,s,tq);
        }
        return 1;
    }

Part 3 類和數據抽象

Chapter 11

Exercise 11.16:重寫(第 11.3.2 節第 3 小節)的程序,使用 copy 算法將一個文件的內容寫到標準輸出中。

#include <iostream>
    #include <iterator>
    #include <vector>
    #include <algorithm>
    #include <fstream>
    using namespace std;
    int main()
    {
    //    istream_iterator <int> cin_it(cin);
    //    istream_iterator <int> eof;
    //    vector<int> vec(cin_it,eof);
    //    sort(vec.begin(),vec.end());
    //    ostream_iterator <int> output(cout," ");
    //    unique_copy(vec.begin(),vec.end(),output);
        ifstream ifile("C://Users//melo//Desktop//1.txt");
        string istr;
        vector <string> inputfile;
        ostream_iterator <string> output(cout," ");
        while(ifile.is_open()&&ifile>>istr)
        {
            inputfile.push_back(istr);
        }
        copy(inputfile.begin(),inputfile.end(),output);
        return 0;
    }
    #include <iostream>
    #include <iterator>
    #include <vector>
    #include <algorithm>
    #include <fstream>
    using namespace std;
    int main()
    {
        ifstream ifile("C://Users//melo//Desktop//1.txt");
        istream_iterator <string> cin_it(ifile);
        istream_iterator <string> eof;
        ostream_iterator <string> output(cout," ");
        vector<string> inputfile(cin_it,eof);
        copy(inputfile.begin(),inputfile.end(),output);
        //sort(inputfile.begin)
        return 0;
    }

Exercise 11.18: 編寫程序使用 istream_iterator對象從標準輸入讀入一系列整數。使用 ostream_iterator 對象將其中的奇數寫到一個文件中,並在每一個寫入的值後面加一個空格。一樣使用 ostream_iterator 對象將偶數寫到第二個文件,每一個寫入的值都存放在單獨的行中。

#include <iostream>
    #include <iterator>
    #include <vector>
    #include <algorithm>
    #include <fstream>
    using namespace std;
    bool IsOdd (int i) { return ((i%2)==1); }
    int main()
    {
        istream_iterator <int> cin_it(cin);
        istream_iterator <int> eof;
        ofstream outputfile1("C://Users//melo//Desktop//1.txt");
        ofstream outputfile2("C://Users//melo//Desktop//2.txt");
        if ( !outputfile1 || !outputfile2  )
        {
            cerr << " File can't be open. " << endl;
            return -1;
        }
        ostream_iterator <int> output1(outputfile1," ");
        ostream_iterator <int> output2(outputfile2,"\n");
        while(cin_it!=eof)
        {
            if((*cin_it)%2==0)
            {
                *output2++=*cin_it++;
            }
            else
            {
                *output1++=*cin_it++;
            }
            //cin_it++;
        }
        outputfile1.close();
        outputfile2.close();
        return 0;
    }

Exercise 11.21:使用 find 在一個 int 型的 list 中尋找值爲 0 的最後一個元素。

#include <iostream>
    #include <iterator>
    #include <vector>
    #include <algorithm>
    #include <fstream>
    #include <list>
    using namespace std;
    int main()
    {
        int ia[]={1,2,3,4,0,6};
        list <int> iList(ia,ia+6);
        list <int> :: reverse_iterator last_0_it=find(iList.rbegin(),iList.rend(),0);
        if(last_0_it!=iList.rend())
            cout<<"get the last 0,it's value is:"<<*last_0_it<<endl;
        else
            cout<<endl;
        return 0;
    }

Chapter 12

Exercise 12.13:擴展 Screen 類以包含 move、set 和 display 操做。經過執行以下表達式來測試類:// move cursor to given position, set that character and display the screen

myScreen.move(4,0).set('#').display(cout);

#include <iostream>
    #include <iterator>
    #include <vector>
    #include <algorithm>
    #include <fstream>
    #include <list>
    using namespace std;
    class Screen
    {
        public:
            typedef std::string::size_type index;
            Screen():cursor(0),height(0),width(0),contents("") {};
            Screen(index hei,index wid,const string&content=""):cursor(0),height(hei),width(wid),contents(content) {};
            Screen& move(index r,index c)
            {
                index row=r*width;
                cursor=row+c;
                return *this;
            }
            Screen& set(char c)
            {
                contents[cursor]=c;
                return *this;
            }
            Screen& display(ostream& os)
            {
                do_display(os);
                return *this;
            }
            const Screen& display(ostream &os) const
            {
                do_display(os);
                return *this;
            }
        private:
            string contents;
            index cursor;
            index height,width;
            void do_display(ostream&os)const
            {
                os<<contents;
            }
    };
    int main()
    {
        Screen myscreen(5,5,"bbbbbgggggfffffiiiiimmmmm");
        myscreen.move(4,0).set('$').display(cout);
        return 0;
    }

Chapter 13

Exercise 13.14:

理解複製控制成員和構造函數的一個良好方式是定義一個簡單類,該類具備這些成員,每一個成員打印本身的名字:

struct Exmpl {
     Exmpl() { std::cout << "Exmpl()" << std::endl; }
     Exmpl(const Exmpl&)
       { std::cout << "Exmpl(const Exmpl&)" << std::endl; }
 // ...
 };

編寫一個像 Exmpl 這樣的類,給出複製控制成員和其餘構造函數。而後寫一個程序,用不一樣方式使用 Exmpl 類型的對象:做爲非引用形參和引用形參傳遞,動態分配,放在容器中,等等。研究什麼時候執行哪一個構造函數和複製構造函數,能夠幫助你融會貫通地理解這些概念。

#include <iostream>
    #include <iterator>
    #include <vector>
    #include <algorithm>
    #include <fstream>
    #include <list>
    using namespace std;
    class exmpl
    {
    public:
        exmpl()
        {
            cout<<"Using Constructor exmpl"<<endl;
        }
        exmpl(const exmpl& ex1)
        {
            cout<<"Using Copy Constructor exmpl(const exmpl&)"<<endl;
        }
        exmpl& operator=(const exmpl& ex1)
        {
            cout<<"Using operator="<<endl;
        }
        ~exmpl()
        {
            cout<<"Using deconstructor"<<endl;
        }
    };
    void func1(exmpl obj)
    {
    }
    void func2(exmpl& obj)
    {
    }
    exmpl func3()
    {
        exmpl obj;
        return obj;
    }
    int main()
    {
        exmpl ex1;
        exmpl ex2(ex1);
        exmpl ex3=ex1;
        ex2=ex3;
        func1(ex1);
        func2(ex1);
        ex1=func3();
        exmpl *p=new exmpl;
        delete p;
        vector<exmpl> iVec(3);
        return 0;
    }

Exercises Section 13.4

A Message-Handling Example:有些類爲了作一些工做須要對複製進行控制。爲了給出這樣的例子,咱們將概略定義兩個類,
這兩個類可用於郵件處理應用程序。Message 類和 Folder 類分別表示電子郵件(或其餘)消息和消息所出現的目錄,
一個給定消息能夠出如今多個目錄中。Message 上有 save 和 remove 操做,用於在指定 Folder 中保存或刪除該消息。

#include <iostream>
    #include <iterator>
    #include <vector>
    #include <algorithm>
    #include <fstream>
    #include <list>
    using namespace std;
    class Message
    {
    public:
        Message(const string& str=""):contents(str) {}
        Message(const Message&);
        Message& operator=(const Message&);
        ~Message()
        {
            remove_Msg_from_Folders();
        }
        void save(Folder&);
        void remove(Folder&);
        void addFldr(Folder*);
        void remFldr(Folder*);
    private:
        string contents;
        set<Folder*> folders;
        void put_Msg_in_Folders(const set<Folder*> &);
        void remove_Msg_from_Folders();
    };
    class Folder
    {
    public:
        Folder() {}
        Folder(const Folder&);
        Folder& operator=(const Folder&);
        ~Folder();
        void save(Message&);
        void remove(Message&);
        void addMsg(Message&);
        void remMsg(Message&);
    private:
        set<Message*> messages;
        void put_Fldr_In_Messages(const set<Message*>&);
        void remove_Fldr_Messages();
    };
    /*******************Folder 類 的定義************************/
    Folder::Folder(const Folder&f):messages(f.messages)
    {
        put_Fldr_In_Messages(messages);
    }
    void Folder::put_Fldr_In_Messages(const set<Message*>&rhs)
    {
        for(set<Message*>::const_iterator beg=rhs.begin();beg!=rhs.end();++beg)
            (*beg)->addFldr(this);
    }
    Folder& Folder::operator=(const Folder& rhs)
    {
        if(&rhs!=this)
        {
            remove_Fldr_Messages();
            messages=rhs.messages;
            put_Fldr_In_Messages(rhs.messages);
        }
        return *this;
    }
    void Folder::remove_Fldr_Messages()
    {
        for(set<Message*>::const_iterator beg=messages.begin();beg!=messages.end();++beg)
        (*beg)->remFldr(this);
    }
    Folder::~Folder()
    {
        remove_Fldr_Messages();
    }
    void Folder::save(Message &msg)
    {
        addMsg(&msg);
        msg.addFldr(this);
    }
    void Folder::remove(Message& msg)
    {
        remMsg(&msg);
        msg.remFldr(this);
    }
    void Folder::addMsg(Message & msg)
    {
        messages.insert(mag);
    }
    void Folder::remMsg(Message & msg)
    {
        messages.erase(msg);
    }
    /*******************Message類 的定義************************/
    Message::Message(const Message& m):contents(m.contents),folders(m.folders)
    {
        put_Msg_in_Folders();
    }
    Message&  Message::operator=(const Message&rhs)
    {
        if(&rhs!=this)
        {
            remove_Msg_from_Folders();
            contents=rhs.contents;
            folders=rhs.folders;
            put_Msg_in_Folders(rhs.folders);
        }
        return *this;
    }
    void Message::put_Msg_in_Folders(const set<Folder*> &rhs)
    {
        for(set<Folder*>::const_iterator beg=rhs.begin(); beg!=rhs.end(); ++beg)
            (*beg)->addMsg(this);
    }
    void Message::remove_Msg_from_Folders()
    {
        for(set<Folder*>::const_iterator beg=folders.begin(); beg!=folders.end(); ++beg)
            (*beg)->remMsg(this);
    }
    void Message::save(Folder &fldr)
    {
        addFldr(&fldr);
        fldr.remMsg(this);
    }
    void Message::remove(Folder & fldr)
    {
        remFldr(&fldr);
        fldr.remMsg(this);
    }
    void Message::addFldr(Folder* fldr)
    {
        folders.insert(fldr);
    }
    void Message::remFldr(Folder* fldr)
    {
        folders.erase(fldr);
    }
    int main()
    {
        return 0;
    }

帶指針的類

Exercise 13.24:實現你本身的使用計數的 HasPtr 類的版本

#include <iostream>
    #include <iterator>
    #include <vector>
    #include <algorithm>
    #include <fstream>
    #include <list>
    using namespace std;
    class HasPtr
    {
    public:
        HasPtr(int *p,int i):ptr(new U_Ptr(p)),val(i){}
        HasPtr(const HasPtr&orig):ptr(orig.ptr),val(orig.val){++ptr->use;}
        HsaPtr& operator=(const HasPtr& rhs)
        {
        ++rhs.ptr->use;
        if(--ptr->use==0)
            delete ptr;
        ptr=rhs.ptr;
        val=rhs.val;
        return *this;
        }
        ~HasPtr()
        {
            if(--ptr->use==0)
                delete ptr;
        }
        int *get_ptr() const {return ptr->ip;}
        int get_int() const {return val;}
        void set_ptr(int *p){ptr->ip=p;}
        void set_int(int i){val=i;}
        int get_ptr_val() const {return *(ptr->ip);}
        void set_ptr_val(int val) {*(ptr->ip=i);}
    private:
        U_ptr* ptr;
        int val;
    };
    class U_ptr
    {
        friend class HasPtr;
        int *ip;
        size_t use;
        U_Ptr(int* p) :ip(p),use(1){}
        ~U_Ptr() {delete p;}
    };
    int main()
    {
        return 0;
    }

Exercise 13.27:

The valuelike HasPtr class defines each of the copy-control members. Describe what would happen if the class defined
值型 HasPtr 類定義了全部複製控制成員。描述將會發生什麼,若是該類:

  • 1.定義了複製構造函數和析構函數但沒有定義賦值操做符。
  • 2.定義了複製構造函數和賦值操做符但沒有定義析構函數。
  • 3.定義了析構函數但沒有定義複製構造函數和賦值操做符。

(a)此種狀況下,使用編譯器合成的賦值操做符。所以若將一個HasPtr對象賦值給另外一個HasPtr對象,則兩個對象的ptr成員值相同,
即兩者指向同一基礎int對象,當其中一個對象被撤銷後,該基礎int對象也被撤銷,使得另外一個對象中的ptr成員指向一個失效的基礎int對象。
並且當另外一個對象被撤銷時,會由於析構函數對同一指針進行重複刪除而出現內存訪問非法的錯誤。此外,被賦值的HasPtr對象
的ptr成員原來所指向的基礎int對象不能再被訪問,但也沒有被撤銷。'

(b) 此時使用編譯器合成的析構函數,當一個對象被撤銷後,其成員所指向的基礎int對象不會被撤銷,會一直存在,從而致使內存泄露。

(c) 此時,使用編譯器合成的複製構造函數和賦值操做符。當將一個對象賦值給另外一個HasPtr對象時或複製構造另外一個HasPtr對象時,
則兩個HasPtr對象的ptr成員值相同,其餘出現的問題與(a)的狀況相同。

Part 4 面向對象編程與泛型編程

Chapter 14

Exercises Section 14.2.1

Exercise 14.7:

爲下面的 CheckoutRecord 類定義一個輸出操做符:

class CheckoutRecord {
         public:
             // ...
         private:
             double book_id;
             string title;
             Date date_borrowed;
             Date date_due;
             pair<string,string> borrower;
             vector< pair<string,string>* > wait_list;
         };

Exercise 14.8:第 12.4 節的習題中,你編寫了下面某個類的框架:爲所選擇的類編寫輸出操做符

(a) Book     (b) Date     (c) Employee
 (d) Vehicle  (e) Object   (f) Tree

c++ #include <iostream> #include <iterator> #include <vector> #include <algorithm> #include <fstream> #include <list> using namespace std; class Date { public: Date(){} Date(int y,int m,int d):year(y),month(m),day(d){} friend ostream& operator<<(ostream&,const Date&); private: int year,month,day; }; ostream& operator<<(ostream& out,const Date&d) { out<<"year:"<<d.year<<"\t"<<"month:"<<d.month<<"\t"<<"day:"<<d.day<<endl; } int main() { Date d(1988,12,1); cout<<d<<endl; return 0; }c++

Exercise 14.12:編寫 Sales_item 操做符,用 + 進行實際加法,而 += 調用 +。與本節中操做符的實現方法相比較,討論這個方法的缺點。

Sales_item Sales_item::operator+( const Sales_item& rhs )
    {
        units_sold += rhs.units_sold;
        revenue += rhs.revenue;
        return *this;
    }
    //將下面定義的非成員+=操做符聲明爲類Sales_item的友元:
    Sales_item operator+=( Sales_item& lhs, const Sales_item& rhs )
    {
        lhs = lhs + rhs;
        return lhs;
    }

這個方法缺點:在+=操做中須要建立和撤銷一個臨時Sales_item對象,來保存+操做的結果,沒有本節中的方法簡單有效。

Exercise 14.15:爲第 14.2.1 節習題中介紹的 CheckoutRecord 類定義賦值操做符

Exercise 14.16: CheckoutRecord 類還應該定義其餘賦值操做符嗎?若是是,解釋哪些類型應該用做操做數並解釋爲何。爲這些類型實現賦值操做符

Exercise 14.17:第 14.2.1 節習題中定義了一個 CheckoutRecord 類,爲該類定義一個下標操做符,從等待列表中返回一個名字。

#include <iostream>
    #include <iterator>
    #include <vector>
    #include <algorithm>
    #include <fstream>
    #include <list>
    using namespace std;
    class Date
    {
    public:
        Date(){}//默認構造函數
        Date(int y,int m,int d):year(y),month(m),day(d){}//構造函數
        Date(Date& d):year(d.year),month(d.month),day(d.day){}//複製構造函數
        friend ostream& operator<<(ostream&,const Date&);//輸出操做符重載函數
        int year,month,day;
    };
    ostream&  operator<<(ostream& out,const Date& d)
    {
        out<<"year:"<<d.year<<"\t"<<"month:"<<d.month<<"\t"<<"day:"<<d.day<<endl;
    }
    class CheckoutRecord
    {
    public:
        CheckoutRecord(){}
        friend istream& operator>>(istream& ,CheckoutRecord&);
        friend ostream& operator<<(ostream& ,CheckoutRecord&);
        CheckoutRecord& operator=(const CheckoutRecord&);
    private:
        double book_id;
        string title;
        Date date_borrowed;
        Date date_due;
        pair<string,string> borrower;
        vector<pair<string,string>*> wait_list;
    };
    CheckoutRecord& CheckoutRecord::operator=(const CheckoutRecord& cr)
    {
        book_id=cr.book_id;
        title=cr.title;
        date_borrowed=cr.date_borrowed;
        date_due=cr.date_borrowed;
        borrower.first=cr.borrower.first;
        borrower.second=cr.borrower.second;
        wait_list.clear();
        for(vector <pair<string,string>*>::const_iterator it=cr.wait_list.begin();it!=wait_list.end();++it)
        {
            pair<string,string> *ppr=new pair<string,string>;
            ppr->first=(*it)->first;
            ppr->second=(*it)->second;
            wait_list.push_back(ppr);
        }
        return *this;
    }
    istream& operator>>(istream& in, CheckoutRecord& c)
    {
        cout << " Input book_id(double) and title(string) :\n";
        in >>  c.book_id >> c.title;
        cout << " Input data_borrowed (3 ints: year, month , day) :\n";
        in >> c.date_borrowed.year >>c.date_borrowed.month >>c.date_borrowed.day;
        cout << " Input data_due (3 ints: year, month , day) :\n";
        in >> c.date_due.year >> c.date_due.month >> c.date_due.day;
        cout << " Input the pair<string,string> borrower (string) :\n";
        in >> c.borrower.first >> c.borrower.second;
        if ( !in )//檢查輸入是否錯誤
        {
            c = CheckoutRecord();
            return in;
        }
        cout << " Input the wait_list (string) :\n";
        c.wait_list.clear();
        while(in)
        {
            pair<string,string>* p_pstr=new pair<string,string>;
            in>>p_pstr->first>>p_pstr->second;
            if(!in)//檢查輸入是否錯誤
            {
                delete p_pstr;
                return in;
            }
            else
            {
                c.wait_list.push_back(p_pstr);
            }
        }
        return in;
    }
    ostream& operator<<(ostream& out,CheckoutRecord& s)
    {
        out << s.book_id << "\t" << s.title<< "\t" << s.date_borrowed<< "\t" << s.date_due<<  "\t" ;
        out<< " borrower:" <<s.borrower.first << "," << s.borrower.second << endl;
        out << " wait_list: " << endl;
        for ( vector< pair<string,string>* >::const_iterator it = s.wait_list.begin();it!= s.wait_list.end(); ++it )
        {
             out << "\t" << (*it)->first << "," << (*it)->second << endl;
        }
         return out;
    }
    int main()
    {
        CheckoutRecord c1;
        CheckoutRecord c2;
        cin>>c1;
        c2=c1;
        cout<<c2<<endl;
        return 0;
    }

有問題:vector<pair<string,string>*>保存的是指針,對象的地址。

Exercises Section 14.6:ScreenPtr類(智能指針)以及操做:

#include <iostream>
    #include <iterator>
    #include <vector>
    #include <algorithm>
    #include <fstream>
    #include <list>
    using namespace std;
    class Screen
    {
    public:
        /*****構造函數以及類型聲明*****/
        typedef string::size_type index;
        Screen():cursor(0),height(0),width(0),contents("") {};
        Screen(index he,index wd,string content=""):contents(content),height(he),width(wd),cursor(0) {}
       /*****操做函數*****/
        Screen& move(index r,index c);
        Screen& set(char c);
        Screen& display(ostream& os);
        char get_char() const;
        const Screen& display(ostream &os) const;
        const char get_char(index r, index c) const;
        const index get_cursor() const;
       /*****操做符重載函數*****/
        Screen& operator=(Screen& s);
    private:
        string contents;
        string::size_type cursor;
        string::size_type height,width;
        void do_display(ostream&os)const
        {
            os<<contents<<endl;
        }
    };
    Screen& Screen::move(index r,index c)
    {
        index row=r*width;
        cursor=row+c;
        return *this;
    }
    Screen& Screen::set(char c)
    {
        contents[cursor]=c;
        return *this;
    }
    Screen& Screen::display(ostream& os)
    {
        do_display(os);
        return *this;
    }
    char Screen::get_char() const
    {
        return contents[cursor];
    }
    Screen& Screen::operator=(Screen& s)
    {
        contents=s.contents;
        height=s.height;
        width=s.width;
        cursor=s.cursor;
    }
    const Screen& Screen::display(ostream &os) const
    {
        do_display(os);
        return *this;
    }
    const char Screen::get_char(index r, index c) const
    {
        index row = r * width;    // compute the row location
        return contents[row + c]; // offset by c to fetch specified character
    }
    const Screen::index Screen::get_cursor() const
    {
        return cursor;
    }
      /*****ScrPtr類*****/
    class ScrPtr
    {
        friend class ScreenPtr;
        Screen *sp;
        size_t use;
        ScrPtr (Screen *p):sp(p),use(1) {}
        ~ScrPtr()
        {
            delete sp;
        }
    };
      /*****ScreenPtr類*****/
    class ScreenPtr
    {
    public:
        ScreenPtr(Screen *p):ptr(new ScrPtr(p))
        {
            cout<<"after call the constructor ,use :"<<ptr->use<<endl;
        }
        ScreenPtr(const ScreenPtr &orig):ptr(orig.ptr)
        {
            ++ptr->use;
            cout<<"after call the copy constructor ,use :"<<ptr->use<<endl;
        }
        ScreenPtr& operator=(const ScreenPtr& sp)
        {
            ++sp.ptr->use;
            if ( --ptr->use == 0 )
                delete ptr;
            ptr = sp.ptr;
            return *this;
        }
        Screen& operator*()
        {
            return *ptr->sp;
        }
        Screen* operator->()
        {
            return ptr->sp;
        }
        const Screen& operator*( ) const
        {
            return *ptr->sp;
        }
        const Screen* operator->( ) const
        {
            return ptr->sp;
        }
        ~ScreenPtr()
        {
            if(--ptr->use==0)  delete ptr;
            cout<<"after call the deconstructor ,use :"<<ptr->use<<endl;
        }
    private:
        ScrPtr *ptr;
    };
    int main()
    {
        ScreenPtr s1=new Screen(5,5,"bbbbbgggggfffffiiiiimmmmm");
        ScreenPtr s2=s1;
        //s1->move()
        s1->move(4,0).set('$').display(cout);
        (*s2).move(4,0).set('$').display(cout);
        return 0;
    }

Exercises Section 14.7:

CheckedPtr 類 表示指向數組的指針:

#include <iostream>
    #include <iterator>
    #include <vector>
    #include <algorithm>
    #include <fstream>
    #include <list>
    #include <stdexcept>
    using namespace std;
    class CheckedPtr
    {
    public:
        CheckedPtr(int*b,int*e):beg(b),end(e),curr(b) {}
        CheckedPtr& operator++();
        CheckedPtr& operator--();
        CheckedPtr operator++(int);
        CheckedPtr operator--(int);
        int& operator* ();
        int& operator[](const size_t index);
        const int& operator*() const;
        const int& operator[](const size_t index)const;
        friend bool operator==(const CheckedPtr& lhs,const CheckedPtr& rhs);
        friend bool operator!=(const CheckedPtr& lhs,const CheckedPtr& rhs);
        friend bool operator>(const CheckedPtr& lhs,const CheckedPtr& rhs);
        friend bool operator<(const CheckedPtr& lhs,const CheckedPtr& rhs);
        friend bool operator>=(const CheckedPtr& lhs,const CheckedPtr& rhs);
        friend bool operator<=(const CheckedPtr& lhs,const CheckedPtr& rhs);
    private:
        int* beg;
        int* end;
        int* curr;
    };
    CheckedPtr& CheckedPtr::operator++()
    {
        if(curr==end)
            throw out_of_range ("increment past the end of CheckedPtr");
        ++curr;
        return  *this;
    }
    CheckedPtr& CheckedPtr::operator--()
    {
        if(curr==beg)
            throw out_of_range ("decrement past the begining of the CheckedPtr");
        --curr;
        return  *this;
    }
    CheckedPtr CheckedPtr::operator++(int)
    {
        CheckedPtr ret(*this);
        ++(*this);
        return ret;
    }
    CheckedPtr CheckedPtr::operator--(int)
    {
        CheckedPtr ret(*this);
        --(*this);
        return ret;
    }
    int& CheckedPtr::operator*()
    {
        if(curr==end)
            throw out_of_range("invalid ptr");
        return *curr;
    }
    const int& CheckedPtr::operator*() const
    {
        if(curr==end)
            throw out_of_range("invalid ptr");
        return *curr;
    }
    int& CheckedPtr::operator[](const size_t index)
    {
        if(beg+index>=end||beg+index<beg)
            throw out_of_range("invalid index");
        return *(beg+index);
    }
    const int& CheckedPtr::operator[](const size_t index) const
    {
        if(beg+index>=end||beg+index<beg)
            throw out_of_range("invalid index");
        return *(beg+index);
    }
     bool operator==(const CheckedPtr& lhs,const CheckedPtr& rhs)
     {
        return lhs.beg == rhs.beg && lhs.end == rhs.end && lhs.curr == rhs.curr;
     }
     bool operator!=(const CheckedPtr& lhs,const CheckedPtr& rhs)
     {
        return !( lhs == rhs );
     }
     bool operator>(const CheckedPtr& lhs,const CheckedPtr& rhs)
     {
        return lhs.beg == rhs.beg && lhs.end == rhs.end
                && lhs.curr > rhs.curr;
     }
    bool operator<(const CheckedPtr& lhs,const CheckedPtr& rhs)
    {
        return lhs.beg == rhs.beg && lhs.end == rhs.end
                && lhs.curr < rhs.curr;
    }
    bool operator>=(const CheckedPtr& lhs,const CheckedPtr& rhs)
    {
        return !( lhs.curr < rhs.curr );
    }
    bool operator<=(const CheckedPtr& lhs,const CheckedPtr& rhs)
    {
        return !( lhs.curr > rhs.curr );
    }
    int main()
    {
        int ia[]={1,2,3,4,5,6};
        CheckedPtr c1(ia,ia+6);
        cout<<&(*c1)<<endl;//1的地址
        cout<<&(*(++c1))<<endl;//2的地址
        cout<<&(*(++c1))<<endl;//3的地址
        cout<<&(*(++c1))<<endl;//4的地址
        //cout<<&(*(c1++))<<endl;//是個臨時變量
        cout<<*c1++<<endl;
        return 0;
    }

Exercise 14.33:使用標準庫算法和 GT_cls 類,編寫一個程序查找序列中第一個比指定值大的元素。

#include <iostream>
    #include <iterator>
    #include <vector>
    #include <algorithm>
    #include <fstream>
    #include <list>
    #include <stdexcept>
    using namespace std;
    class GT_cls
    {
    public:
        GT_cls(const string a=""):str(a){}
        bool operator()(const string &s)
        {
            return (s>str);
        }
    private:
        string str;
    };
    int main()
    {
        std::cout << " Input some words( ctrl + z to end ):" << std::endl;
        vector<string> text;
        string word;
        while ( std::cin >> word )
        {
            text.push_back( word );
        }   // end of input the text
        std::cin.clear();
        std::cout << " Then , input one given word:\t";
        string givenWord;
        std::cin >> givenWord;
        vector<string>::iterator it = find_if( text.begin(), text.end(), GT_cls( givenWord ));
        if  ( it != text.end() )
        std::cout << "\n Then the first word in the text you input," << std::endl
                  << " \twhich is bigger than the given word is:" << std::endl
                  << "\t" <<  *it << std::endl;
        return 0;
    }
#include <iostream>
    #include <iterator>
    #include <vector>
    #include <algorithm>
    #include <fstream>
    #include <list>
    #include <stdexcept>
    using namespace std;
    class Item_base
    {
    public:
        Item_base(const string &book="",
                  double sales_price=0.0):isbn(book),price(sales_price){}
                  string book() const{return isbn;}
                  virtual double net_price(size_t n)const{return n*price;}
                  virtual void print(ostream &os){os <<price;}
                  virtual ~Item_base(){}
    private:
        string isbn;
    protected:
        double price;
    };
    class Bulk_item:public Item_base
    {
    public:
        double net_price(size_t cnt)const
        {
            if(cnt>min_qty)
                return cnt*(1-discount)*price;
            else
                return cnt*price;
        }
        void print(ostream &os)
        {
            Item_base::print(ostream &os);
            os << " " << discount;
        }
    private:
        size_t min_qty;
        double discount;
    };
    class Ltd_item:public Item_base
    {
    public:
        Led_item(const string& book="",double sales_price,size_t qty=0,double disc_rate=0):item_base(book,sales_price),max_qty(qty),discount(disc_rate){}
        double net_price(size_t cnt) const
        {
            if(cnt<max_qty)
                return cnt*(1-discount)*price;
            else
                return cnt*price-max_qty*discount*price;
        }
    private:
        size_t max_qty;
        double discount;
    };
    int main()
    {
        return 0;
    }

Chapter 15

派生類的構造函數與複製控制

#### Exercise 15.20:回憶在第 13.3 節習題中編寫的類,該類的複製控制成員打印一條消息,爲 Item_base 和 Bulk_item 類的構造函數增長打印語句。定義複製控制成員,使之完成與合成版本相同的工做外,還打印一條消息。應用使用了 Item_base 類型的那些對象和函數編寫一些程序,在每種狀況下,預測將會建立和撤銷什麼對象,並將你的預測與程序所產生的結果進行比較。繼續實驗,直至你可以正確地預測對於給定的代碼片斷,會執行哪些複製控制成員

#### Exercise 15.28:定義一個 vector 保存 Item_base 類型的對象,並將一些 Bulk_item 類型對象複製的到 vector 中。遍歷並計算容器中元素的總和。

#### Exercise 15.29: 重複程序,但此次存儲 Item_base 類型對象的指針。比較結果總和。

Exercise 15.30:解釋上兩題程序所產生總和的差別。若是沒有差別,解釋爲何沒有。

綜合:
#include <iostream>
    #include <iterator>
    #include <vector>
    #include <algorithm>
    #include <fstream>
    #include <list>
    #include <stdexcept>
    using namespace std;
    //基類定義:Item_base
    class Item_base
    {
    public:
        Item_base(const string& book="",double sales_price=0):isbn(book),price(sales_price)
        {
            cout<<"Using Item_base's constructor"<<endl;
        }
        Item_base(const Item_base& bi)
        {
            isbn=bi.isbn;
            price=bi.price;
            cout<<"Using Item_base's copy constructor"<<endl;
        }
        string book() const
        {
            return isbn;
        }
        virtual double net_price(size_t n) const
        {
            cout<<"Using Item_base's net_price"<<endl;
            return price*n;
        }
       // friend ostream& operator<<(ostream&,const Item_base&);
        virtual ~Item_base()
        {
            cout<<"Using Item_base's destructor"<<endl;
        }
    private:
        string isbn;
    protected:
        double price;
    };
    ostream& operator<<(ostream& os,const Item_base &ib)
    {
        os<<"Using operator<< (ostream&,Item_base&)"<<endl
        <<"Item_base's book():"<<ib.book()<<endl
        <<"Item_base's net_price():"<<ib.net_price(3)<<endl;
        return os;
    }
    //派生類定義:Bulk_item
    class Bulk_item:public Item_base
    {
    public:
        Bulk_item(const string& book,double sales_price,size_t qty=0,double disc=0):
        Item_base(book,sales_price),min_qty(qty),discount(disc)
        {
            cout<<"Using Bulk_item's constructor "<<endl;
        }
        Bulk_item(const Bulk_item& bi):Item_base(bi)
        {
            min_qty=bi.min_qty;
            discount=bi.discount;
            cout<<"Using Bulk_item's copy constructor"<<endl;
        }
        virtual double net_price(size_t cnt) const
        {
            cout<<"Using Bulk_item's net_price"<<endl;
            if(cnt>min_qty)
                return cnt*(1-discount)*price;
            else
                return cnt*price;
        }
        ~Bulk_item()
        {
            cout<<"Using Bulk_item's destructor "<<endl;
        }
    private:
        size_t min_qty;
        double discount;
    };
    ostream& operator<<(ostream& os,const Bulk_item& bi)
    {
        os<<"Using operator<< (ostream&, Bulk_item&)"<<endl
        <<"Bulk_item's book():"<<bi.book()<<endl
        <<"Bulk_item's net_price():"<<bi.net_price(3)<<endl;
        return os;
    }
    
    int main()
    {
        Item_base* p=new Item_base("C++ Primer",42.00);
        Bulk_item* p222=new Bulk_item("How to program",42,1,0.2);
        cout<<*p<<endl;
        cout<<*p222<<endl;
        delete p;
        delete p222;//析構函數先刪除派生類的成員後刪除基礎類的成員
        Item_base p11("C++ Primer",42.00);
        Bulk_item p22("How to program",42,1,0.2);
        cout<<p11<<endl;
        cout<<p22<<endl;
        Item_base base0("C++ Primer_0",50);
        Bulk_item bulk0("How to program_0",50,1,0.2);
        vector<Item_base> basket;
        basket.push_back(base0);//此處調用Item_base的複製構造函數
        basket.push_back(bulk0);//此處調用Item_base的複製構造函數 生成一箇中間變量 傳遞給basket中元素 再刪除這個中間變量
        double SumPrice=0;
        for (vector<Item_base>::iterator it=basket.begin();it!=basket.end();++it)
        {
            SumPrice+=(*it).net_price(3);
        }
        cout<<"\n\tthe sum price of the basket is :\t"<<SumPrice<<endl;
        vector<Item_base*> basket2;
        Item_base *p1=&base0;
        Item_base *p2=&bulk0;
        basket2.push_back(p1);
        basket2.push_back(p2);
        SumPrice = 0.0;
        for ( vector<Item_base*>::iterator it = basket2.begin(); it != basket2.end(); ++it )
        {
            SumPrice += (*it)->net_price(3);
        }
        cout << "\n\tthe sum price of the basket is :\t" << SumPrice << endl;
        return 0;
    }

句柄類與繼承:item_base(基類)->Bulk_item(派生類)->sales_item(句柄類)->Basket(容器)

Exercise 15.35:編寫本身的 compare 函數和 Basket 類的版本並使用它們管理銷售

item_base(基類)&Bulk_item(派生類)

//item.h
    #ifndef ITEM_H
    #define  ITEM_H
    #include <iostream>
    #include <string>
    using namespace std;
    //基類
    class Item_base
    {
    public:句柄類與繼承
        Item_base(const string& book="",double sales_price=0):isbn(book),price(sales_price)
        {
            cout<<"Using Item_base's constructor"<<endl;
        }
        Item_base(const Item_base& bi)
        {
            isbn=bi.isbn;
            price=bi.price;
            cout<<"Using Item_base's copy constructor"<<endl;
        }
        string book() const
        {
            return isbn;
        }
        virtual double net_price(size_t n) const
        {
            cout<<"Using Item_base's net_price"<<endl;
            return price*n;
        }
         virtual Item_base* clone() const
        {
            return new Item_base(*this);
        }
       // friend ostream& operator<<(ostream&,const Item_base&);
        virtual ~Item_base()
        {
            cout<<"Using Item_base's destructor"<<endl;
        }
    private:
        string isbn;
    protected:
        double price;
    };
    ostream& operator<<(ostream& os,const Item_base &ib)
    {
        os<<"Using operator<< (ostream&,Item_base&)"<<endl
        <<"Item_base's book():"<<ib.book()<<endl
        <<"Item_base's net_price():"<<ib.net_price(3)<<endl;
        return os;
    }
    //打折的派生類
    class Bulk_item:public Item_base
    {
    public:
        Bulk_item(const string& book,double sales_price,size_t qty=0,double disc=0):Item_base(book,sales_price),min_qty(qty),discount(disc)
        {
            cout<<"Using Bulk_item's constructor "<<endl;
        }
        Bulk_item(const Bulk_item& bi):Item_base(bi)
        {
            min_qty=bi.min_qty;
            discount=bi.discount;
            cout<<"Using Bulk_item's copy constructor"<<endl;
        }
        virtual double net_price(size_t cnt) const
        {
            cout<<"Using Bulk_item's net_price"<<endl;
            if(cnt>min_qty)
                return cnt*(1-discount)*price;
            else
                return cnt*price;
        }
        virtual Bulk_item* clone() const
        {
            return new Bulk_item(*this);
        }
        ~Bulk_item()
        {
            cout<<"Using Bulk_item's destructor "<<endl;
        }
    private:
        size_t min_qty;
        double discount;
    };
    ostream& operator<<(ostream& os,const Bulk_item& bi)
    {
        os<<"Using operator<< (ostream&, Bulk_item&)"<<endl
        <<"Bulk_item's book():"<<bi.book()<<endl
        <<"Bulk_item's net_price():"<<bi.net_price(3)<<endl;
        return os;
    }
    #endif

sales_item(句柄類)

//sales_item
    #ifndef SALES_ITEM_H
    #define  SALES_ITEM_H
    #include "item.h"
    class Sales_item
    {
    public:
        Sales_item():p(0),use(new size_t(1)){}//空的構造函數
        Sales_item(const Item_base& item):p(item.clone()),use(new size_t(1)){}//用Item_base類的賦值構造函數
        Sales_item(const Sales_item& i):p(i.p),use(i.use){++*use;}//複製構造函數
        ~Sales_item(){decr_use();}
        Sales_item& operator=(const Sales_item&);//複製函數
        const Item_base* operator->() const{if(p) return p;else throw logic_error("Unbound Sales_item");}
        const Item_base& operator*() const {if(p) return *p;else throw logic_error("Unbound Sales_item");}
    private:
        Item_base *p;
        size_t *use;
        void decr_use()
        {
            if(--*use==0)
            {
                delete p;
                delete use;
            }
        }
    };
    Sales_item& Sales_item::operator=(const Sales_item &rhs)
    {
        ++*rhs.use;
        decr_use();
        p=rhs.p;
        use=rhs.use;
        return *this;
    }
    #endif // SALES_ITEM_H

Basket(容器)

//basket.h
    #ifndef __BASKET_H_
    #define __BASKET_H_
    #include "sales_item.h"
    #include <set>
    inline bool compare(const Sales_item &lhs,const Sales_item& rhs)
    {
        return lhs->book()<rhs->book();
    }
    class Basket
    {
        typedef bool (*Comp)(const Sales_item&, const Sales_item&);
    public:
        typedef multiset<Sales_item,Comp> set_type;
        typedef set_type::size_type size_type;
        typedef set_type::const_iterator const_iter;
        Basket():items(compare){}
        void add_item(const Sales_item& item){items.insert(item);}
        size_type size(const Sales_item& i) const {return items.count(i);}
        double total() const;
    private:
        multiset<Sales_item,Comp> items;
    };
    double Basket::total() const
    {
        double sum=0;
        for(const_iter it=items.begin();it!=items.end();it=items.upper_bound(*it))
        {
            size_t i=items.count(*it);
            cout<<i<<endl;
            sum+=(*it)->net_price(i);
        }
        return sum;
    }
    #endif

main.cpp

#include <iostream>
    #include <iterator>
    #include <vector>
    #include <algorithm>
    #include <fstream>
    #include <list>
    #include <stdexcept>
    #include "basket.h"
    #include "sales_item.h"
    int main()
    {
        Basket basket;
        Sales_item item1 ( Bulk_item( "0-0001-0001-1", 99, 5, 0.5 ));
        //Sales_item item2 ( Bulk_item( "0-0001-0001-2", 50 ));
        //Sales_item item3 ( Bulk_item( "0-0001-0001-3", 59, 200, 0.3 ));
        //Sales_item item4 ( Bulk_item( "0-0001-0001-1", 99, 20, 0.2 ));
        basket.add_item(item1);
        //basket.add_item(item2);
        //basket.add_item(item3);
        //basket.add_item(item4);
        cout << basket.total() << endl;
        return 0;
    }

15.9. Text Queries Revisited

Exercise 15.41:實現 Query 類和 Query_base 類,併爲第十章的 TextQuery 類增長鬚要的 size 操做。經過計算和打印如圖 15.4 所示的查詢,測試你的應用程序。

TextQuery.h

#pragma once
    #include <iostream>
    #include <string>
    #include <vector>
    #include <map>
    #include <fstream>
    #include <set>
    using namespace std;
    class TextQuery
    {
    public:
        typedef vector<string>::size_type line_no;
        void read_file(ifstream &is)
        {
            store_file(is);build_map();
        }
        set<line_no> run_query(const string&) const;
        string text_line(line_no) const;
        line_no size() const { return lines_of_text.size(); }
    private:
        void store_file(ifstream&);
        void build_map();
        vector<string> lines_of_text;
        map< string,set<line_no> > word_map;
    };

TextQuery.cpp

#include "TextQuery.h"
    #include <fstream>
    #include <sstream>
    using namespace std;
    void TextQuery::store_file(ifstream& is)
    {
        string line;
        while(getline(is,line))
        {
            lines_of_text.push_back(line);
        }
    }
    void TextQuery::build_map()
    {
        for (line_no line_num=0;line_num!=lines_of_text.size();++line_num)
        {
            istringstream line(lines_of_text[line_num]);
            string word;
            while(line>>word)
            {
                word_map[word].insert(line_num);//word_map[word]==set
            }
        }
    }
    set<TextQuery::line_no> TextQuery::run_query(const string&query_word) const
    {
        map< string,set<line_no> >::const_iterator loc=word_map.find(query_word);
        if(loc==word_map.end())
            return set<line_no>();
        else
            return loc->second;
    }
    string TextQuery::text_line(line_no line) const
    {
        if(line<lines_of_text.size())
            return lines_of_text[line];
    }

Query.h

#include "TextQuery.h"
    #include <string>
    #include <set>
    #include <iostream>
    #include <fstream>
    using namespace std;
    /********************************class Query_Base***************************/
    //private, abstract class acts as a base for concrete query types
    class Query_base
    {
    public:
        friend class Query;
    protected:
        typedef TextQuery::line_no line_no;
        virtual ~Query_base(){}
    private:
        virtual set<line_no> eval(const TextQuery&) const=0;
        virtual ostream& display(ostream& =cout) const=0;
    };
    /********************************class Query***************************/
    class Query
    {
        //typedef TextQuery::line_no line_no;
    public:
        Query(const string&);
        /****複製控制*****/
        Query(const Query& c):q(c.q),use(c.use){++*use;}
        ~Query(){decr_use();}
        Query& operator=(const Query&);
        set<TextQuery::line_no> eval(const TextQuery& t) const
        {
            return q->eval(t);
        }
        ostream& display(ostream& os) const
        {
            return q->display(os);
        }
        friend Query operator~(const Query&);
        friend Query operator|(const Query&,const Query&);
        friend Query operator&(const Query&,const Query&);
    private:
        Query(Query_base *query):q(query),use(new size_t(1)){}
        Query_base* q;
        size_t* use;
        void decr_use()
        {
            if(--*use==0)
            {
                delete q;
                delete use;
            }
        }
    };
    inline ostream& operator<<(ostream& os,const Query &q)
    {
        return q.display(os);
    }
    inline Query& Query::operator=(const Query& rhs)
        {
            ++*rhs.use;
            decr_use();
            q=rhs.q;
            use=rhs.use;
            return *this;
        }
    /********************************class WordQuery***************************/
    class WordQuery:public Query_base
    {
        public:
        friend class Query;
        private:
        WordQuery(const string& s):query_word(s){}
        set<line_no> eval(const TextQuery& t)const
        {
            return t.run_query(query_word);
        }
        ostream& display (ostream& os) const
        {
            return os<<query_word;
        }
        string query_word;
    };
    inline Query::Query(const string& word):
        q(new WordQuery(word)), use(new std::size_t(1)) {}
    /********************************class NotQuery***************************/
    class NotQuery:public Query_base
    {
        friend Query operator~(const Query&);
        private:
        NotQuery(Query q):query(q){}
        set<line_no> eval(const TextQuery&) const;
        ostream& display(ostream& os) const
        {
            return os<<"~("<<query<<")";
        }
        const Query query;
    };
    /********************************class BinaryQuery***************************/
    class BinaryQuery:public Query_base
    {
    protected:
        BinaryQuery(Query left,Query right,string op):lhs(left),rhs(right),oper(op){}
        ostream& display(ostream &os) const
        {
            return os<<"("<<lhs<<" "<<oper<<" "<<rhs<<")";
        }
        const Query lhs,rhs;
        const string oper;
    };
    /********************************class AndQuery***************************/
    class AndQuery:public BinaryQuery
    {
        friend Query operator&(const Query&,const Query&);
        AndQuery(Query left,Query right):BinaryQuery(left,right,"&"){}
        set<line_no> eval(const TextQuery&) const;
    };
    /********************************class OrQuery***************************/
    class OrQuery:public BinaryQuery
    {
        friend Query operator|(const Query&,const Query&);
        OrQuery(Query left,Query right):BinaryQuery(left,right,"|"){}
        set<line_no> eval(const TextQuery&) const;
    };
    inline Query operator&(const Query &lhs,const Query &rhs)
    {
        return new AndQuery(lhs,rhs);
    }
    inline Query operator|(const Query &lhs,const Query &rhs)
    {
        return new OrQuery(lhs,rhs);
    }
    inline Query operator~(const Query &oper)
    {
        return new NotQuery(oper);
    }

Query.cpp

#include "Query.h"
    #include "TextQuery.h"
    #include <map>
    #include <algorithm>
    set<TextQuery::line_no> OrQuery::eval(const TextQuery& file) const
    {
        set<line_no> right=rhs.eval(file);
        set<line_no> ret_lines=lhs.eval(file);
        ret_lines.insert(right.begin(),right.end());
        return ret_lines;
    }
    set<TextQuery::line_no> AndQuery::eval(const TextQuery& file) const
    {
        set<line_no> left=lhs.eval(file);
        set<line_no> right=rhs.eval(file);
        set<line_no> ret_lines;
        set_intersection(left.begin(),left.end(),right.begin(),right.end(),inserter(ret_lines,ret_lines.begin()));
        return ret_lines;
    }
    set<TextQuery::line_no> NotQuery::eval(const TextQuery& file) const
    {
        set<line_no> has_val=query.eval(file);
        set<line_no> ret_lines;
        for(TextQuery::line_no n=0;n!=file.size();++n)
        {
            if(has_val.find(n)==has_val.end())
                ret_lines.insert(n);
        }
        return ret_lines;
    }

main.cpp

#include <iostream>
    #include "TextQuery.h"
    #include "Query.h"
    using namespace std;
    void print_result(const set<TextQuery::line_no>& locs, const string& sought, const TextQuery& file)
    {
        typedef set<TextQuery::line_no> line_nums;
        line_nums::size_type size = locs.size();
        cout<<"\n"<<sought<<" occurs "<<size<<(size>1?" times ":"Time")<<endl;
        line_nums::const_iterator it = locs.begin();
        for(; it!=locs.end(); ++it)
            cout<<(*it)+1<<"\t"<<file.text_line(*it)<<endl;
    }
    int main()
    {
        ifstream is("1.txt");
        TextQuery tq;
        tq.read_file(is);
        Query q=Query("fiery")&Query("bird")|Query("wind");
        set<TextQuery::line_no> locs=q.eval(tq);
        string s("((fiery & bird) | wind)");
        print_result(locs,s,tq);
       // cout << "Hello world!" << endl;
        return 0;
    }

Chapter 16

Exercise 16.12:編寫一個函數模板,接受表示未知類型迭代器的一對值,找出在序列中出現得最頻繁的值。

#include <iostream>
    #include <utility>
    #include <string>
    #include <vector>
    #include <map>
    #include <fstream>
    #include <sstream>
    #include <set>
    #include <algorithm>
    using namespace std;
    template <typename T> typename T::value_type frq(T first,T last)
    {
        size_t amount=0;
        T start=first;
        while(start!= last)
        {
            amount++;
            start++;
        }
        typedef vector <typename T::value_type> VecType;
        VecType vec(amount);
        typename VecType::iterator newFirst=vec.begin();
        typename VecType::iterator newLast=vec.end();
        uninitialized_copy( first, last, newFirst );
        sort ( newFirst, newLast );
        size_t maxOccu = 0, occu = 0;
        typename    VecType::iterator preIter = newFirst;
        typename VecType::iterator maxOccuElement = newFirst;
        while( newFirst != newLast )
        {
            if ( *newFirst != *preIter )  // 當前值與前一值不一樣
            {
                if ( occu > maxOccu )
                {
                    maxOccu = occu;          // 修改最大次數
                    maxOccuElement = preIter;    // 修改指向當前出現最頻繁的值的迭代器
                }
                occu = 0;
            }
            ++occu;
            preIter = newFirst;
            ++newFirst;
        }
        if ( occu > maxOccu )
        {
            maxOccu = occu;
            maxOccuElement = preIter;
        }
        return *maxOccuElement;
    }
    template<typename T> int compare(const T&v1,const T& v2)
    {
        if(v1<v2) return -1;
        if(v1>v2) return 1;
        if(v1==v2) return 0;
    }
    template<typename T> inline T abs(const T& v1)
    {
        return v1>0?v1:-(v1);
    }
    template<typename T> inline testOstream(ostream& os,T v1)
    {
        os<<v1;
    }
    template <class Type> class Queue
    {
    public:
        Queue();
        Type& front();
        const Type& front() const;
        void push(const Type&);
        void pop();
        bool empty() const;
    private:
    };
    int main()
    {
    //    cout << compare(1, 0) << endl;
    //    string s1="hi",s2="world";
    //    cout<<compare(s1,s2)<<endl;
    //    std::cout << "abs( s1) is:" << abs(false) << std::endl
    //              << "abs( -3 ) is:" << abs( -3 ) << std::endl
    //              << "abs( -8.6 ) is:" << abs( -8.6 ) << std::endl;
    //    cout << " Test of testOstream( cout, 6 ):";
    //    testOstream( cout, 6 );
    //    cout << "\n Test of testOstream( cout, true ):\t";
    //    testOstream( cout, true );
    //    cout << "\n Test of testOstream( cout, 8.6 ):\t";
    //    testOstream( cout, 8.6 );
    //    cout << "\n Test of testOstream( cout, \"Good!\" ):\t";i.begin()
    //    testOstream( cout, "Good!" );
    //
    //    ofstream outfile;
    //    outfile.open("out.txt");
    ////    assert( outfile );
    //    cout << "\nTest of ofstream, Please check the file just create.\n";
    //    if ( !outfile )
    //    {
    //        return NULL;
    //    }
    //    testOstream(outfile, "\n Test of testOstream( outfile, 6 ):");
    //    testOstream( outfile, 6 );
    //    testOstream(outfile, "\n Test of testOstream( outfile, true ):");
    //    testOstream( outfile, true );
    //    testOstream(outfile, "\n Test of testOstream( outfile, 8.6 ):");
    //    testOstream( outfile, 8.6 );
    //    testOstream(outfile, "\n Test of testOstream( outfile, \"Good!\" ):");
    //    testOstream( outfile, "Good!" );
    //    outfile.close();
    //    cout << endl;
    //
    //
    //    stringstream oss;
    //    cout << "\n Test of testOstream( oss, 6 )/( oss, true )/( oss, 8.6 )/( oss, \"Good!\"):" << endl;
    //    testOstream( oss, 6 );
    //    testOstream( oss, "\n" );
    //    testOstream( oss, true );
    //    testOstream( oss, "\n" );
    //    testOstream( oss, 8.6 );
    //    testOstream( oss, "\n" );
    //    testOstream( oss, "Good!");
    //    testOstream( oss, "\n" );
    //    cout << oss.str() << endl;
        int ia[]={1,2,3,4,2,3,2,2,4,5,6,7,8};
        vector<int> i(13);
        copy(ia,ia+13,i.begin());
        cout<<frq(i.begin(),i.end());
        return 1;
    }

Exercise 16.9:編寫行爲相似於標準庫中 find 算法的模板。你的模板應接受一個類型形參,該形參指定函數形參(一對迭代器)的類型。使用你的函數在 vector 和 list 中查找給定值。

#include <iostream>
    #include <utility>
    #include <string>
    #include <vector>
    #include <map>
    #include <fstream>
    #include <sstream>
    #include <set>
    #include <algorithm>
    #include <stdexcept>
    using namespace std;
    /***************************************************/
    //    template<class Iterator>
    //       struct iterator_traits {
    //       typedef typename Iterator::iterator_category iterator_category;
    //       typedef typename Iterator::value_type value_type;
    //       typedef typename Iterator::difference_type difference_type;
    //       typedef typename Iterator::pointer pointer;
    //       typedef typename Iterator::reference reference;
    //       };
    //    template<class Type>
    //       struct iterator_traits<Type*> {
    //       typedef random_access_iterator_tag iterator_category;
    //       typedef Type value_type;
    //       typedef ptrdiff_t difference_type;
    //       typedef Type *pointer;
    //       typedef Type& reference;
    //       };
    //    template<class Type>
    //       struct iterator_traits<const Type*> {
    //       typedef random_access_iterator_tag iterator_category;
    //       typedef Type value_type;
    //       typedef ptrdiff_t difference_type;
    //       typedef const Type *pointer;
    //       typedef const Type& reference;
    //       };
    //iterator_traits是一個類模板 它接受一個指針類型或者一個iterator類型,
    //這個traits(顯著的特色)保存了迭代器的類型以及其指針和地址
    /***************************************************/
    template<typename Iterator,typename Object> Iterator Find(Iterator v1,Iterator v2,const Object& s)
    {
        for(Iterator it=v1;it!=v2;++it)
        {
            if(*it==s)
                return it;
        }
            return v2;
    }
    template<typename T> T Find2(T v1,T v2,typename iterator_traits<T>::value_type s)
    {
        for(T it=v1;it!=v2;++it)
        {
            if(*it==s)
                return it;
        }
            return v2;
    }
    int main()
    {
        int ia[]={1,2,3,4,5,6,7};
        vector<int> ip(ia,ia+6);
        cout<<*(Find2(ip.begin(),ip.end(),5))<<endl;
        cout<<*(Find2(ia,ia+6,5));
        return 1;
    }

Exercise 16.13:編寫一個函數,接受一個容器的引用並打印該容器的元素。使用容器的 size_type 和 size 成員控制打印元素的循環。

Exercise 16.14:從新編寫上題的函數,使用從 begin 和 end 返回的迭代器來控制循環

#include <iostream>
    #include <utility>
    #include <string>
    #include <vector>
    #include <map>
    #include <fstream>
    #include <sstream>
    #include <set>
    #include <algorithm>
    #include <stdexcept>
    using namespace std;
    template <typename T> void PrintValue(const vector<T>& v1)
    {
        typedef typename vector<T>::size_type sizet;
        for(sizet i=0;i!=v1.size();++i)
        {
            cout<<v1[i]<<" ";
        }
    }
    template <typename T> void PrintValue2(const vector<T>& v1)
    {
        typedef typename vector<T>::const_iterator iter;
        for(iter i=v1.begin();i!=v1.end();++i)
        {
            cout<<*i<<" ";
        }
    }
    int main()
    {
         int ia[]={1,2,3,4,5,6,7};
        vector<int> ip(ia,ia+7);
        PrintValue2(ip);
        return 1;
    }

Exercise 16.15:編寫能夠肯定數組長度的函數模板。

Exercise 16.16: 將第 7.2.4 節的 printValues 函數從新編寫爲可用於打印不一樣長度數組內容的函數模板

Exercise 16.16:

#include <iostream>
    #include <utility>
    #include <string>
    #include <vector>
    #include <map>
    #include <fstream>
    #include <sstream>
    #include <set>
    #include <algorithm>
    #include <stdexcept>
    using namespace std;
    template<typename T,size_t N> void print_array(T (&parm)[N])
    {
        for (size_t i = 0; i != N; ++i)
            {
                 cout<<parm[i]<<" ";
             }
        cout<<endl;
    }
    int main()
    {
         int ia[7]={1,2,3,4,5,6,7};
        vector<int> ip(ia,ia+7);
        print_array(ia);
        return 1;
    }

Exercise 16.42:編寫一個輸入操做符,讀一個 istream 對象並將讀到的值放入一個 Queue 對象中

16.4.6. 完整的 Queue 類以及測試

#include <iostream>
    #include <utility>
    #include <string>
    #include <vector>
    #include <map>
    #include <fstream>
    #include <sstream>
    #include <set>
    #include <algorithm>
    using namespace std;
    template <class Type> class Queue;//Queue類聲明
    /********************operator<<函數聲明********************/
    template <class T>
    ostream& operator<<(ostream &os, const Queue<T> &q);
    /********************QueueItem類定義********************/
    template <class Type> class QueueItem
    {
        friend class Queue<Type>;
        friend ostream& operator<< <Type> (ostream &, const Queue<Type> &);
        QueueItem (const Type&t):item(t),next(0) {}
        Type item;
        QueueItem* next;
    };
    /********************Queue類定義********************/
    template <class Type> class Queue
    {
    public:
        friend ostream& operator<< <Type>(ostream &, const Queue<Type> &);
        Queue():head(0),tail(0) {}
        Queue(const Queue& Q):head(0),tail(0)
        {
            copy_elems(Q);   //複製構造
        }
        Queue& operator=(const Queue&);//賦值構造
        ~Queue()
        {
            destory();   //析構函數
        }
        template<class It> Queue(It beg,It end):head(0),tail(0){copy_elems(beg,end);}
        template<class Iter> void assign(Iter,Iter);
        Type& front()
        {
            return head->item;
        }
        const Type& front() const
        {
            return head->item;
        }
        void push(const Type&);//
        void pop();//
        bool empty() const
        {
            return head==0;
        }
    private:
        QueueItem<Type> *head;
        QueueItem<Type> *tail;
        void destory();//
        void copy_elems(const Queue&);//
        template <class Iter> void copy_elems(Iter,Iter);
    };
    /********************Queue類函數destory定義********************/
    template <class Type> void Queue<Type>::destory()
    {
        while(!empty())
            pop();
    }
    /********************Queue類函數pop定義********************/
    template <class Type> void Queue<Type>::pop()
    {
        QueueItem<Type>* p=head;
        head=head->next;
        delete p;
    }
    /********************Queue類函數push定義********************/
    template <class Type> void Queue<Type>::push(const Type&val)
    {
        QueueItem<Type> *pt=new QueueItem<Type> (val);
        if(empty())
            head=tail=pt;
        else
        {
            tail->next=pt;
            tail=pt;
        }
    }
    /********************Queue類函數copy_elems定義********************/
    template<class Type> void Queue<Type>::copy_elems(const Queue& orig)
    {
        for(QueueItem<Type>* pt=orig.head; pt; pt=pt->next)
        {
            push(pt->item);
        }
    }
    /********************Queue類函數assign定義********************/
    template<class T> template<class Iter>
    void Queue<T>::assign(Iter beg,Iter end)
    {
        destory();
        copy_elems(beg,end);
    }
    /********************Queue類函數copy_elems定義********************/
    template <class Type> template <class It>
    void Queue<Type>::copy_elems(It beg,It end)
    {
        while(beg!=end)
          {
            push(*beg);
            ++beg;
          }
    }
    /********************Queue類輸出函數opeator<<定義********************/
    template <class Type>
    ostream& operator<<(ostream &os, const Queue<Type> &q)
    {
        os << "< ";
        QueueItem<Type> *p;
        for (p = q.head; p; p = p->next)
            os << p->item << " ";
        os <<">";
        return os;
    }
    template<typename T> int compare(const T&v1,const T& v2)
    {
        if(v1<v2) return -1;
        if(v1>v2) return 1;
        if(v1==v2) return 0;
    }
    int main()
    {
        short a[4]={0,3,6,9};
        Queue<int> qi(a,a+4);
        vector<int> vi(a,a+4);
        qi.assign(vi.begin(),vi.end());
        Queue<int> xi(vi.begin(),vi.end());//xi被實例化
        cout<<qi<<endl;
        cout<<xi<<endl;
        xi.pop();
        cout<<xi<<endl;
        xi.push(3.1);//發生類型轉換 double 3.1->int 3
        cout<<xi<<endl;
        cout<<compare<string>("Hi","World");
        return 1;
    }

泛型句柄類: Handle 類行爲相似於指針:複製 Handle 對象將不會複製基礎對象,複製以後,兩個 Handle 對象將引用同一基礎對象。要建立 Handle 對象,用戶須要傳遞屬於由 Handle 管理的類型(或從該類型派生的類型)的動態分配對象的地址,今後刻起,Handle 將「擁有」這個對象。並且,一旦再也不有任意 Handle 對象與該對象關聯,Handle 類將負責刪除該對象。

Exercise 16.45:實現一個 Handle 類的本身的版本

#include <iostream>
    #include <utility>
    #include <string>
    #include <vector>
    #include <map>
    #include <fstream>
    #include <sstream>
    #include <set>
    #include <algorithm>
    #include <stdexcept>
    using namespace std;
    /**********************泛式句柄Handle類*************************/
    template <class T> class Handle
    {
    public:
        Handle (T* p=0):ptr(p),use(new size_t(1)) {cout<<"Using Handle's Constructor;"<<endl;cout<<"The use is: "<<*use<<endl;}
        T& operator*();//
        T* operator->();//
        const T& operator*() const;//
        const T* operator->() const;//
        Handle (const Handle& h):ptr(h.ptr),use(h.use)
        {
            ++*use;   //複製構造函數
            cout<<"Using Handle's Copy Constructor;"<<endl;
            cout<<"The use is: "<<*use<<endl;
        }
        Handle& operator=(const Handle&);//
        ~Handle()
        {
            cout<<"Using Handle's Deconstructor;"<<endl;
           // cout<<"The use is: "<<*use<<endl;
            rem_ref();
        }
    private:
        T* ptr;
        size_t* use;
        void rem_ref()
        {
            if(--*use==0)
              {
                cout<<"The use is: 0"<<endl;
                delete ptr;
                delete use;
              }
        }
    };
    /**********************賦值操做符operator=*************************/
    template<class T> inline Handle<T>& Handle<T>::operator=(const Handle& rhs)
    {
        ++*rhs.use;
        rem_ref();
        ptr=rhs.ptr;
        use=rhs.use;
        cout<<"Using Handle's operator=;"<<endl;
        cout<<"The use is: "<<*use<<endl;
        return *this;
    }
    /**********************解引用操做符operator**************************/
    template<class T> inline T& Handle<T>::operator*()
    {
        if(ptr)
        {
            return *ptr;
        }
        else
        throw runtime_error("dereference of unbound handle");
    }
    /**********************取地址操做符operator->**************************/
    template<class T>  inline const T* Handle<T>::operator->() const
    {
        if(ptr)
        {
            return ptr;
        }
        else
        throw runtime_error("access through unbound handle");
    }
    template<class T> inline const T& Handle<T>::operator*() const
    {
        if(ptr)
        {
            return *ptr;
        }
        else
        throw runtime_error("dereference of unbound handle");
    }
    int main()
    {
        Handle<int> hp(new int(42));
        {
            Handle<int> hp2=hp;
            cout<<*hp<<" "<<*hp2<<endl;
            *hp2=10;
        }
        cout<<*hp<<endl;
        return 1;
    }

Exercise 16.49: 實現本節提出的 Sales_item 句柄的版本,該版本使用泛型 Handle 類管理 Item_base 指針。

#include <iostream>
    #include <utility>
    #include <string>
    #include <vector>
    #include <map>
    #include <fstream>
    #include <sstream>
    #include <set>
    #include <algorithm>
    #include <stdexcept>
    using namespace std;
    /**********************基類Item_base類*************************/
    class Item_base
    {
    public://句柄類與繼承
        Item_base(const string& book="",double sales_price=0):isbn(book),price(sales_price)
        {
            cout<<"Using Item_base's constructor"<<endl;
        }
        Item_base(const Item_base& bi)
        {
            isbn=bi.isbn;
            price=bi.price;
            cout<<"Using Item_base's copy constructor"<<endl;
        }
        string book() const
        {
            return isbn;
        }
        virtual double net_price(size_t n) const
        {
            cout<<"Using Item_base's net_price"<<endl;
            return price*n;
        }
         virtual Item_base* clone() const
        {
            return new Item_base(*this);
        }
       // friend ostream& operator<<(ostream&,const Item_base&);
        virtual ~Item_base()
        {
            cout<<"Using Item_base's destructor"<<endl;
        }
    private:
        string isbn;
    protected:
        double price;
    };
    /**********************基類Item_base類輸出函數*************************/
    ostream& operator<<(ostream& os,const Item_base &ib)
    {
        os<<"Using operator<< (ostream&,Item_base&)"<<endl
        <<"Item_base's book():"<<ib.book()<<endl
        <<"Item_base's net_price():"<<ib.net_price(3)<<endl;
        return os;
    }
    /**********************派生類Bulk_item類*************************/
    class Bulk_item:public Item_base
    {
    public:
        Bulk_item(const string& book,double sales_price,size_t qty=0,double disc=0):Item_base(book,sales_price),min_qty(qty),discount(disc)
        {
            cout<<"Using Bulk_item's constructor "<<endl;
        }
        Bulk_item(const Bulk_item& bi):Item_base(bi)
        {
            min_qty=bi.min_qty;
            discount=bi.discount;
            cout<<"Using Bulk_item's copy constructor"<<endl;
        }
        virtual double net_price(size_t cnt) const
        {
            cout<<"Using Bulk_item's net_price"<<endl;
            if(cnt>min_qty)
                return cnt*(1-discount)*price;
            else
                return cnt*price;
        }
        virtual Bulk_item* clone() const
        {
            return new Bulk_item(*this);
        }
        ~Bulk_item()
        {
            cout<<"Using Bulk_item's destructor "<<endl;
        }
    private:
        size_t min_qty;
        double discount;
    };
    /**********************派生類Bulk_item類的輸出函數*************************/
    ostream& operator<<(ostream& os,const Bulk_item& bi)
    {
        os<<"Using operator<< (ostream&, Bulk_item&)"<<endl
        <<"Bulk_item's book():"<<bi.book()<<endl
        <<"Bulk_item's net_price():"<<bi.net_price(3)<<endl;
        return os;
    }
    /****************************************************************/
    /**********************泛式句柄Handle類*************************/
    template <class T> class Handle
    {
    public:
        Handle (T* p=0):ptr(p),use(new size_t(1)) 
        {
          cout<<"Using Handle's Constructor;"<<endl;
          cout<<"The use is: "<<*use<<endl;
        }
        T& operator*();//
        T* operator->();//
        const T& operator*() const;//
        const T* operator->() const;//
        Handle (const Handle& h):ptr(h.ptr),use(h.use)
        {
            ++*use;   //複製構造函數
            cout<<"Using Handle's Copy Constructor;"<<endl;
            cout<<"The use is: "<<*use<<endl;
        }
        Handle& operator=(const Handle&);//
        ~Handle()
        {
            cout<<"Using Handle's Deconstructor;"<<endl;
           // cout<<"The use is: "<<*use<<endl;
            rem_ref();
        }
    private:
        T* ptr;
        size_t* use;
        void rem_ref()
        {
            if(--*use==0)
              {
                cout<<"The use is: 0"<<endl;
                delete ptr;
                delete use;
              }
        }
    };
    /**********************賦值操做符operator=*************************/
    template<class T> inline Handle<T>& Handle<T>::operator=(const Handle& rhs)
    {
        ++*rhs.use;
        rem_ref();
        ptr=rhs.ptr;
        use=rhs.use;
        cout<<"Using Handle's operator=;"<<endl;
        cout<<"The use is: "<<*use<<endl;
        return *this;
    }
    /**********************解引用操做符operator**************************/
    template<class T> inline T& Handle<T>::operator*()
    {
        if(ptr)
        {
            return *ptr;
        }
        else
        throw runtime_error("dereference of unbound handle");
    }
    /**********************取地址操做符operator->**************************/
    template<class T>  inline const T* Handle<T>::operator->() const
    {
        if(ptr)
        {
            return ptr;
        }
        else
        throw runtime_error("access through unbound handle");
    }
    template<class T> inline const T& Handle<T>::operator*() const
    {
        if(ptr)
        {
            return *ptr;
        }
        else
        throw runtime_error("dereference of unbound handle");
    }
    /**********************採用泛式句柄的Sales_item類*************************/
    class Sales_item
    {
    public:
        Sales_item():h(){}
        Sales_item(const Item_base &item):h(item.clone()){}
        const Item_base& operator*()const {return *h;}
        const Item_base* operator->() const {return h.operator->();}
    private:
        Handle <Item_base> h;
    };
    /**********************採用泛式句柄的Basket類*************************/
    inline bool compare(const Sales_item &lhs,const Sales_item& rhs)
    {
        return lhs->book()<rhs->book();
    }
    class Basket
    {
        typedef bool (*Comp)(const Sales_item&, const Sales_item&);
    public:
        typedef multiset<Sales_item,Comp> set_type;
        typedef set_type::size_type size_type;
        typedef set_type::const_iterator const_iter;
        Basket():items(compare){}
        void add_item(const Sales_item& item){items.insert(item);}
        size_type size(const Sales_item& i) const {return items.count(i);}
        double total() const;
    private:
        multiset<Sales_item,Comp> items;
    };
    double Basket::total() const
    {
        double sum=0;
        for(const_iter it=items.begin();it!=items.end();it=items.upper_bound(*it))
        {
            size_t i=items.count(*it);
            cout<<i<<endl;
            sum+=(*it)->net_price(i);
        }
        return sum;
    }
    int main()
    {
        Basket basket;
        Sales_item item1 ( Bulk_item( "0-0001-0001-1", 99, 5, 0.5 ));
        //Sales_item item2 ( Bulk_item( "0-0001-0001-2", 50 ));
        //Sales_item item3 ( Bulk_item( "0-0001-0001-3", 59, 200, 0.3 ));
        //Sales_item item4 ( Bulk_item( "0-0001-0001-1", 99, 20, 0.2 ));
        basket.add_item(item1);
        //basket.add_item(item2);
        //basket.add_item(item3);
        //basket.add_item(item4);
        cout <<"The total is: "<<basket.total() << endl;
        return 1;
    }

#### Exercise 16.51:從新編寫Section 15.9.4第 15.9.4 節的 Query 類以使用泛型 Handle 類。注意你須要將 Handle 類設爲 Query_base 類的友元,以使它可以訪問 Query_base 構造函數。列出並解釋讓程序工做要作的其餘全部修改

#### Exercise 16.52:定義函數模板 count 計算一個 vector 中某些值的出現次數。

#### Exercise 16.53:編寫一個程序調用上題中定義的 count 函數,首先傳給該函數一個 double 型 vector,而後傳遞一個 int 型 vector,最後傳遞一個 char 型 vector。

Exercise 16.54:引入 count 函數的一個特化模板實例以處理 string 對象。從新運行你所編寫的調用函數模板實例化的程序。

#include <iostream>
    #include <utility>
    #include <string>
    #include <cstring>
    #include <vector>
    #include <map>
    #include <fstream>
    #include <sstream>
    #include <set>
    #include <algorithm>
    #include <stdexcept>
    using namespace std;
    /*****************************函數模板Count****************************/
    template<typename Type> int Count(vector<Type> const &v1,Type const &v2)
    {
        cout<<"Calling Count's general version:"<<endl;
        int sum=0;
        for(size_t i=0; i!=v1.size(); ++i)
        {
            if(v1[i]==v2)
                ++sum;
        }
        return sum;
    }
    /**********************函數模板Count的string特化*************************/
    template<> int Count( vector<string>  const& v1,string const& v2)
    {
        cout<<"Calling Count's string version:"<<endl;
        int sum=0;
        for(size_t i=0; i!=v1.size(); ++i)
        {
            if(v1[i]==v2)
                ++sum;
        }
        return sum;
    }
    /**************************函數模板Compare******************************/
    template<typename T> int compare(const T &v1, const T &v2)
    {
        cout<<"Calling Compare's general version:"<<endl;
        if (v1 < v2) return -1;
        if (v2 < v1) return 1;
        return 0;
    }
    /*******************函數模板Compare的const char*特化**********************/
    template <>
    int compare<const char*>(const char* const  &v1, const char* const &v2)
    {
        cout<<"Calling Compare's const char* version:"<<endl;
        return strcmp(v1, v2);
    }
    int main()
    {
        int ia[]= {1,2,3,5,5,3,4,5,6,7};
        double ib[]= {23.6,23.4,52.2};
        string ic[]= {"ibg","wings","EG"};
        vector<int> ip(ia,ia+10);
        vector<double> ig(ib,ib+3);
        vector<string> istr(ic,ic+3);
        cout<<Count(ip,5)<<endl;
        cout<<Count(ig,23.6)<<endl;
        cout<<Count(istr,string("EG"))<<endl;
        /*zhihu*/
        const char *cp1 = "world", *cp2 = "hi";
        char * const cp3 = "world", *cp4 = "hi";
        int i2, i1;
        compare(i1, i2);
        compare(cp1, cp2);
        // 這個地方匹配成了通用模板很讓我費解
        compare(cp3, cp4);
        return 1;
    }

Part 5 高級主題

Chapter 17

Chapter 18

優化內存分配:

Exercise 18.1:實現本身的 Vector 類的版本,包括 vector 成員 reserve(第 9.4 節)、resize(第 9.3.5 節)以及 const 和非 const 下標操做符(第 14.5 節)

#include <iostream>
    #include <utility>
    #include <string>
    #include <cstring>
    #include <vector>
    #include <map>
    #include <fstream>
    #include <sstream>
    #include <set>
    #include <algorithm>
    #include <stdexcept>
    #include <memory>
    using namespace std;
    template<class T>
    class Vector
    {
    public:
        Vector():first_free(0),end(0),element(0){}
        void push_back(T t)
        {
            if(first_free==end)
            {
                reallocate();
            }
            alloc.construct(first_free,t);
            //new (first_free)T (t);
            first_free++;
        }
        T& operator[](size_t s)
        {
            if(s>first_free-element)
            {
                throw out_of_range("下標越界!");
            }
            else
            {
                return element[s];
            }
        }
        const T& operator[](size_t s)const
        {
            if(s>first_free-element)
            {
                throw out_of_range("下標越界!");
            }
            else
            {
                return element[s];
            }
        }
        size_t size()
        {
            return first_free-element;
        }
        size_t capacity()
        {
            return end-element;
        }
        void reserve(size_t n)
        {
            size_t Capacity=capacity();
            if(n>0)
            {
                if(Capacity<n)
                {
                    T* newelement=alloc.allocate(n);//在堆上開闢空間
                    uninitialized_copy(element,first_free,newelement);
                    for (T *p = first_free; p != element; /* empty */ )//調用T的析構函數,將原有空間的元素撤銷
                    {
                        alloc.destroy(--p);
                        //p->~T();//顯式調用析構函數。
                    }
                    if(element)
                    {
                        alloc.deallocate(element,end-element);//將原有空間歸還給系統
                        //operator delete (element);//使用operator delete釋放空間。
                    }
                    element=newelement;
                    first_free=element+size();
                    end=element+n;
                }
            }
            else
            {
                throw runtime_error("n<0!");
            }
        }
    //    void resize(size_t n)
    //    {
    //        size_t Size=size();
    //        size_t Capacity=capacity();
    //        if(n<Size)
    //        {
    //                for (T *p = first_free;p!=element+n; /* empty */ )//調用T的析構函數,將原有空間的元素撤銷
    //                {
    //                    alloc.destroy(--p);
    //                    //p->~T();//顯式調用析構函數。
    //                }
    //                first_free=element+n+1;
    //        }
    //        else
    //        {
    //            if(n>Capacity)
    //            {
    //                std::ptrdiff_t num=first_free-element;//原有vector的size
    //                std::ptrdiff_t newcapacity = 2 * max(n, 1);//capacity增長成2*size
    //                T* newelement=alloc.allocate(newcapacity);//在堆上開闢空間
    //                //newelement=static_cast<T*>(operator new(2*num*sizeof(T)));//調用operator new申請空間。
    //                for()
    //                uninitialized_copy(element,first_free,newelement);//將原有的元素複製到現有空間上
    //                for (T *p = first_free; p != element; /* empty */ )//調用T的析構函數,將原有空間的元素撤銷
    //                {
    //                    alloc.destroy(--p);
    //                    //p->~T();//顯式調用析構函數。
    //                }
    //                if(element)
    //                {
    //                    alloc.deallocate(element,end-element);//將原有空間歸還給系統
    //                    //operator delete (element);//使用operator delete釋放空間。
    //                }
    //
    //                element=newelement;
    //                first_free=element+num;
    //                end=element+newcapacity;
    //            }
    //            else
    //            {
    //
    //            }
    //        }
    //    }
    private:
        void reallocate()
        {
            std::ptrdiff_t num=first_free-element;//原有vector的size
            std::ptrdiff_t newcapacity = 2 * max(num, 1);//capacity增長成2*size
            T* newelement=alloc.allocate(newcapacity);//在堆上開闢空間
            //newelement=static_cast<T*>(operator new(2*num*sizeof(T)));//調用operator new申請空間。
            uninitialized_copy(element,first_free,newelement);//將原有的元素複製到現有空間上
            for (T *p = first_free; p != element; /* empty */ )//調用T的析構函數,將原有空間的元素撤銷
            {
                alloc.destroy(--p);
                //p->~T();//顯式調用析構函數。
            }
            if(element)
            {
                alloc.deallocate(element,end-element);//將原有空間歸還給系統
                //operator delete (element);//使用operator delete釋放空間。
            }
            element=newelement;
            first_free=element+num;
            end=element+newcapacity;
        }
    private:
        allocator<T> alloc;
        // T* newelement;
        T* first_free;
        T* end;
        T* element;
    };
    int main()
    {
        Vector<int> vi;
        try
        {
            for(int i=0; i<20; i++)
            {
                vi.push_back(i+5);
            }
            for(int i=0; i<20; i++)
            {
                cout<<i+1<<": "<<vi[i]<<endl;
            }
            cout<<vi[28]<<endl;
        }
        catch (exception &e)
        {
            cout<<e.what()<<endl;
        }
        vi.reserve(20);
        cout<<vi.capacity()<<endl;
        vector<int> pi(20);
        pi.push_back(2);
        cout<<pi.capacity()<<endl;
        return 1;
    }

Exercise 18.12: 爲 Queue 類或你選擇的其餘類實現一個類特定的內存分配器。測量性能的改變,看看到底有多大幫助

Example:

#include<iostream>
    #include<stdexcept>
    using namespace std;
    template<typename T>
    class MemoryAllocate
    {
    public:
        MemoryAllocate()
        {
        }
        void *operator new(size_t s)
        {
            if(s!=sizeof(T))
                throw runtime_error("傳入的類型大小不符!");
            if(!freeList)
            {
                T*array=alloc.allocate(num);
                for(size_t i=0;i<num;i++)
                {
                    addToFreeList(array+i);
                }
            }
            T*p=freeList;
            freeList=freeList->next;
            return p;
        }
        void operator delete(void*s)
        {
            T*p=static_cast<T*>(s);
            addToFreeList(p);
            cout<<"DELETE函數被調用 "<<endl;//這句話被輸出了,說明此函數被調用了。可是爲什麼沒法跟進呢???20120530 21:22
        }
        virtual ~MemoryAllocate()
        {
        }
    private:
        static void addToFreeList(T*t)
        {
            t->next=freeList;
            freeList=t;
        }
    private:
        static T*freeList;
        static T*next;
        static allocator<T> alloc;
        static size_t num;
    };
      template<typename T>  T*MemoryAllocate<T>::freeList=NULL;
      template<typename T> size_t MemoryAllocate<T>::num=10;
      template<typename T> T*MemoryAllocate<T>::next=NULL;
      template<typename T> allocator<T> MemoryAllocate<T>::alloc;
      class Derived:public MemoryAllocate<Derived>
      {
      public:
          Derived()
          {
              i=0;
          }
          int i;
      };
      int main(int argc,char**argv)
      {
         try
         {
             Derived *mai=new Derived;
             Derived *p=new Derived;
             delete mai;
             delete p;
         }
         catch (exception& e)
         {
             cout<<e.what()<<endl;
         }
         return 0;
      }

附錄:操做符優先級

Associativity and Operator Function Use See Page
L :: global scope(全局做用域) :: name p. 450
L :: class scope(類做用域) class :: name p. 85
L :: namespace scope(名字空間做用域) namespace :: name p. 78
L . member selectors(成員選擇) object . member p. 25
L -> member selectors(成員選擇) pointer -> member p. 164
L [] subscript(下標) variable [ expr ] p. 113
L () function call(函數調用) name (expr_list) p. 25
L () type construction(類型構造) type (expr_list) p. 460
R ++ postfix increment(後自增操做) lvalue++ p. 162
R -- postfix decrement(後自減操做) lvalue-- p. 162
R typeid type ID(類型 ID) typeid (type) p. 775
R typeid run-time type ID(運行時類型 ID) typeid (expr) p. 775
R explicit cast(顯式強制類型轉換) type conversion(類型轉換) cast_name  (expr) p. 183
R sizeof size of object(對象的大小) sizeof expr p. 167
R sizeof size of type(類型的大小) sizeof(type) p. 167
R ++ prefix increment(前自增操做) ++ lvalue p. 162
R -- prefix decrement(前自減操做) -- lvalue p. 162
R ~ bitwise NOT(位求反) ~expr p. 154
R ! logical NOT(邏輯非) !expr p. 152
R - unary minus(一元負號) -expr p. 150
R + unary plus(一元正號) +expr p. 150
R * dereference(解引用) *expr p. 119
R & address-of(取地址) &expr p. 115
R () type conversion(類型轉換) (type) expr p. 186
R new allocate object(建立對象) new type p. 174
R delete deallocate object(釋放對象) delete expr p. 176
R delete[] deallocate array(釋放數組) delete[] expr p. 137
L ->* ptr to member select(指向成員操做的指針) ptr ->* ptr_to_member p. 783
L .* ptr to member select(指向成員操做的指針) obj .*ptr_to_member p. 783
L * multiply(乘法) expr * expr p. 149
L / divide(除法) expr / expr p. 149
L % modulo (remainder)(求模(求餘)) expr % expr p. 149
L + add(加法) expr + expr p. 149
L - subtract(減法) expr - expr p. 149
L << bitwise shift left(位左移) expr << expr p. 154
L >> bitwise shift right(位右移) expr >> expr p. 154
L < less than(小於) expr < expr p. 152
L <= less than or equal(小於或等於) expr <= expr p. 152
L > greater than(大於) expr > expr p. 152
L >= greater than or equal(大於或等於) expr >= expr p. 152
L == equality(相等) expr == expr p. 152
L != inequality(不等) expr != expr p. 152
L & bitwise AND(位與) expr & expr p. 154
L ^ bitwise XOR() expr ^ expr p. 154
L | bitwise OR(位異或) expr | expr p. 154
L && logical AND(邏輯與) expr && expr p. 152
L || logical OR(邏輯或) expr || expr p. 152
R ?: conditional(條件操做) expr ? expr : expr p. 165
R = assignment(賦值操做) lvalue = expr p. 159
R *=, /=, %=, compound assign(複合賦值操做) lvalue += expr, etc. p. 159
R +=, -=, p. 159
R <<=, >>=, p. 159
R &=,|=, ^= p. 159
R throw throw exception(拋出異常) throw expr p. 216
L , comma(逗號) expr , expr p. 168
相關文章
相關標籤/搜索