《Essential C++》课后习题代码记录

第一章 C++编程基础

练习 1.4

/*
练习 1.4
试着扩充这个程序的内容:(1)要求用户同时输入名字(first name)和姓氏(last name),
(2)修改输出结果,同时打印出姓氏和名字。
*/
#include <iostream>
#include <string>
using namespace std;

int main()
{
    string first_name, last_name;
    cout << "Please enter your first name:";
    cin >> first_name;

    cout << "hi, " << first_name
         << "Please enter your last name:";
    
    cin >> last_name;
    cout << '\n';
    cout << "Hello, "
         << first_name << ' ' << last_name
         << "... and goodbye!\n";
}

练习 1.5

/*
练习 1.5
编写一个程序,能够询问用户的姓名,并读取用户所输入的内容。请确保用户输入的名称长度大
于两个字符。如果用户的确输入了有效名称,就响应一些信息。请以两种方式实现:第一种使用
C-style字符串,第二种使用string对象。
*/

// 使用string存储用户名,并根据名字长度做出响应
#include <iostream>
#include <string>
using namespace std;

int main()
{
    string user_name;

    cout << "Please enter your name:";
    cin >> user_name;

    switch ( user_name.size() ){
        case 0:
            cout << "Ah, the user with no name."
                 << "Well, ok, hi, user with no name\n";
            break;
    
        case 1:
            cout << "A 1-character name? Hmm, have you read Kafka?:"
                 << "hello, " << user_name << endl;
            break;

        default:
            // 字符串长度超过1个字符
            cout << "Hello, " << user_name
                 << " -- happy to make your acquaintance!\n";
            break;
    }
    return 0;
}

第二种:

//使用C-style字符串存储用户名,并根据名字长度做出响应
#include <iostream>
#include <iomanip>
#include <cstring>
using namespace std;

int main()
{
    // 必须分配一个大小固定的空间
    const int nm_size = 128;
    char user_name[ nm_size ];
    cout << "Please enter your name:";
    cin >> setw( nm_size ) >> user_name;

    switch ( strlen( user_name ) ){
        // 这里处理case 0和case 
        case 127:
            // 也许所得的字符串已被setw()舍弃掉部分内容
            cout << "That is a very big name, indeed -- "
                 << "we may have needed to shorten it!\n"
                 << "In any case,\n";
            
            // 此处不加break,往下继续执行
        default:
            // 如果符合前述条件,也会执行至此处,因为先前并没有break
            cout << "Hello, " << user_name
                 << " -- happy to make your acquaintance!\n";
            break;
    }
    return 0;
}

练习 1.6

/*
练习 1.6
编写一个程序,从标准输入设备读取一串整数,并将读入的整数依次放到array及
vector,然后遍历这两种容器,求取数值总和。将总和及平均值输出至标准输出设备
*/

// 使用vector实现
#include <iostream>
#include <vector>
using namespace std;

int main()
{
    vector<int> ivec;
    int ival;
    while ( cin >> ival ){
        // 将新输入内容添加到ivec之后
        ivec.push_back( ival );
    }
    /*
    原先的代码:
    // 我们可以在数值被输入时就实时计算总和
    // 这里的做法是遍历vector的元素,一一累加
    for (int sum = 0, ix = 0; ix < ivec.size(); ix++)
    {
        sum += ivec[ ix ];
    }
    int average = sum / ivec.size();
    // 根据C++ Standard,sum的作用范围局限于上述的for循环中。
    // 此处的sum会造成Undefined symbol编译错误。作者这么写,未能符合
    // C++ Standard规范(但某些编辑器,如Visual C++,会让它过关)。
    // 请问你应该如何改正这个错误?
    */
    
    // 将sum的声明放到for循环之外,扩大其作用范围
    int sum = 0;
    for (int ix = 0; ix < ivec.size(); ix++){
        sum += ivec[ ix ];
    }
    int average = sum / ivec.size();
    
    cout << "Sum of " << ivec.size()
         << " elements: " << sum
         << ". Average: " << average << endl;
    return 0;
}

第二种

// 使用array实现
#include <iostream>
using namespace std;

int main()
{
    const int array_size = 128;
    int ia[ array_size ];
    int ival, icnt = 0;  // ival用于暂存输入,icnt表示输入数据量

    while ( cin >> ival && icnt < array_size ){
        ia[ icnt++ ] = ival;
    }

    int sum = 0;
    for (int ix = 0; ix < icnt; ++ix ){
        sum += ia[ ix ];
    }

    int average = sum / icnt;
    cout << "Sum of " << icnt
         << " elements: " << sum
         << ". Average: " << average << endl;
}

练习 1.7

/*
练习 1.7
使用你最趁手的编辑工具,输入两行(或更多)文字并存盘。然后编写一个程序,打开该文本文
件,将其中每个字都读取到一个vector<string>对象中。遍历该vector,将内容显示到cout。
然后利用泛型算法sort(),对所有文字排序:
#include <algorithm>
sort( container.beginer(), container.end() );
再将排序后的结果输出到另一个文件。
*/

#include <iostream>
#include <fstream>
#include <algorithm>
#include <string>
#include <vector>
using namespace std;

int main()
{
    // 要读取的文件
    ifstream in_file( "C:\\Users\\Administrator\\Desktop\\essential C++\\cpp_source\\chapter_1\\1_7.txt" );
    if ( !in_file ){
        cerr << "oops! unable to open input file\n"; 
        return -1;
    }
    
    // 需写入的文件
    ofstream out_file( "C:\\Users\\Administrator\\Desktop\\essential C++\\cpp_source\\chapter_1\\1_7_out.txt" );
    if ( ! out_file ){
        cerr << "oops! unable to open output file\n"; 
        return -2;
    }

    // 读取文件中的内容
    string word;
    vector< string > text;
    while ( in_file >> word ){
        text.push_back( word );
    }
    
    int ix;
    cout << "unsorted text: \n";

    // 输入到cout中展示
    for ( ix = 0; ix < text.size(); ++ix){
        cout << text[ ix ] << ' ';
    }
    cout << endl;

    // 排序
    sort( text.begin(), text.end() );

    // 写入到另一个文件中
    out_file << "sorted text: \n";
    for ( ix = 0; ix < text.size(); ++ix ){
        out_file << text[ ix ] << ' ';
    }
    out_file << endl;
    return 0;
}

练习 1.8

/*
练习 1.8
1.4 节的switch语句让我们得以根据用户答错的次数提供不同的安慰语句。请以array储存四种
不同的字符串信息,并以用户答错次数作为array的索引值,以此方式来显示安慰语句。
*/
using namespace std;

const char* msg_to_usr( int num_tries )
{
    const int rsp_cnt = 5;
    static const char* usr_msgs[ rsp_cnt ] = {
        "Go on, make a guess. ",
        "Oops! Nice guess but not quite it.",
        "Hmm, Sorry. Wrong a second time.",
        "Ah, this is harder than it looks, no?",
        "It must be getting pretty frustrating by now!"
    };
    if ( num_tries < 0 ){
        num_tries = 0;
    }
    else if ( num_tries >= rsp_cnt ){
        num_tries = rsp_cnt-1;
    }
    return usr_msgs[ num_tries ];
}

第二章 面向过程的编程风格

练习 2.1

/*
练习 2.1
先前的main()只让用户输入一个位置值,然后便结束程序。如果用户想取得两个甚至更多元素值,
他必须执行这个程序两次或多次。请改写main(),使它允许用户不断输入位置值,直到用户希望
停止为止。
*/

#include <iostream>
using namespace std;

bool fibon_elem( int, int & );

int main()
{
    int pos, elem;
    char ch;
    bool more = true;

    while ( more ){
        cout << "Please enter a position: ";
        cin >> pos;

        if ( fibon_elem( pos, elem )){
            cout << "element # " << pos
                 << " is " << elem << endl;
        }
        else{
            cout << "Sorry. Could not calculate element # "
                 << pos << endl;
        }
        cout << "Do you want to calculate any other numbers?(y/n)";
        cin >> ch;

        if ( ch != 'y' && ch != 'Y'){
            more = false;
        }
    }
}

bool fibon_elem( int pos, int &elem ){
    // 检查位置值是否合理
    if ( pos <= 0 || pos > 1024){
        elem = 0;
        return false;    
    }
    
    elem = 1;
    int n_2 = 1, n_1 = 1;

    for ( int xi = 3; xi <= pos; ++xi){
        elem = n_2 + n_1;
        n_2 = n_1;
        n_1 = elem;
    }
    return true;
}

练习 2.2

/*
练习 2.2
Pentagonal数列的求值公式是P(n)=n(3n-1)/2,借此产生1,2,5,12,22,35等元素值。试定义一个
函数,利用上述公式,将产生的元素放到用户传入的vect之中,元素个数由用户指定。请检查元素
个数的有效性(太大则可能引起overflow问题)。接下来编写第二个函数,能够将给定的vector
的所有元素一一打印出来。此函数的第二个参数接受一个字符串,表示存放在vector内的数列的
类型。最后再写一个main(),测试上述两个函数。
*/

#include <vector>
#include <string>
#include <iostream>
using namespace std;

bool calc_elements( vector<int> &vec, int pos );
void display_elems( vector<int> &vec, 
                    const string &title, ostream &os=cout );  // 赋了初值

int main()
{
    vector<int> pent;
    const string title( "Pentagonal Numeric Series" );
    
    // 检查上面声明的两个函数
    if ( calc_elements( pent, 0 ))
        display_elems( pent, title );
    
    if ( calc_elements( pent, 8 ))
        display_elems( pent, title );
    
    if ( calc_elements( pent, 14 ))
        display_elems( pent, title );
    
    if ( calc_elements( pent, 138 ))
        display_elems( pent, title );
}

bool calc_elements( vector<int> &vec, int pos )
{
    if ( pos <= 0 || pos >64 ){
        cerr << "Sorry. Invalid position: " << pos << endl;
        return false;
    }
    for ( int ix = vec.size()+1; ix <= pos; ++ix){
        vec.push_back( (ix*(3*ix-1))/2 );
    }
    return true;
}

void display_elems( vector<int> &vec,
                        const string &title, ostream &os )
{
    os << '\n' << title << '\n\t';
    for ( int ix = 0; ix < vec.size(); ++ix)
        os << vec[ ix ] << ' ';
        
    os << endl;
}

练习 2.3

/*
练习 2.3
将练习2.2的Pentagonal数列求值函数拆分为两个函数,其中之一为inline,用来检验元素个数
是否合理。如果的确合理,而且尚未被计算,便执行第二个函数,执行实际的求值工作。
*/

#include <vector>
#include <string>
#include <iostream>
using namespace std;

inline bool calc_elems( vector<int> &vec, int pos );
void display_elems( vector<int> &vec, 
                    const string &title, ostream &os=cout );  // 赋了初值
extern void really_calc_elems ( vector<int> &, int );

int main()
{
    vector<int> pent;
    const string title( "Pentagonal Numeric Series" );
    
    // 检查上面声明的两个函数
    if ( calc_elems( pent, 0 ))
        display_elems( pent, title );
    
    if ( calc_elems( pent, 8 ))
        display_elems( pent, title );
    
    if ( calc_elems( pent, 14 ))
        display_elems( pent, title );
    
    if ( calc_elems( pent, 138 ))
        display_elems( pent, title );
}

inline bool calc_elems( vector<int> &vec, int pos )
{
    if ( pos <= 0 || pos >64 ){
        cerr << "Sorry. Invalid position: " << pos << endl;
        return false;
    }
    if ( vec.size() < pos){
        really_calc_elems( vec, pos);
    }
    return true;
}

void really_calc_elems( vector<int> &vec, int pos )
{
     for ( int ix = vec.size()+1; ix <= pos; ++ix){
        vec.push_back( (ix*(3*ix-1))/2 );
    }
}

void display_elems( vector<int> &vec,
                        const string &title, ostream &os )
{
    os << '\n' << title << '\n\t';
    for ( int ix = 0; ix < vec.size(); ++ix)
        os << vec[ ix ] << ' ';

    os << endl;
}

练习 2.4

/*
练习 2.4
写一个函数,以局部静态(local static)的vector储存Pentagonal数列元素。此函数返回一个
const指针,指向该vector。如果vector的大小小于指定的元素个数,就扩充vector的大小。接下
来再实现第二个函数,接受一个位置值,放回该位置上的元素。最后,编写main()测试这些函数。
*/

#include <iostream>
#include <vector>
using namespace std;

inline bool check_validity( int pos )
    { return ( pos <= 0 || pos >64 ) ? false : true; }

const vector<int>* pentagonal_series( int pos )
{
    static vector<int> _elems;

    if ( check_validity( pos ) && ( pos >_elems.size() )){
        for ( int ix = _elems.size(); ix < pos; ++ix){
            _elems.push_back( (ix*(3*ix-1))/2 );
        }
        return &_elems;
    }
}

bool pentagonal_elem( int pos, int &elem )
{
    if ( !check_validity( pos )){
        cout << "Sorry. Invalid position: " << pos << endl;
        elem = 0;
        return false;
    }
    const vector<int> *pent = pentagonal_series( pos );
    elem = (*pent)[pos-1];
    return true;
}

int main()
{
    int elem;
    if ( pentagonal_elem( 8, elem ))
        cout << "element 8 is " << elem << '\n';

    if ( pentagonal_elem( 88, elem ))
        cout << "element 88 is " << elem << '\n';

    if ( pentagonal_elem( 12, elem ))
        cout << "element 12 is " << elem << '\n';
    
    if ( pentagonal_elem( 64, elem ))
        cout << "element 64 is " << elem << '\n';
}

练习 2.5

/*
练习 2.5
实现一个重载的max()函数,让它接受以下参数:(a)两个整数,(b)两个浮点数,(c)两个
字符串,(d)一个整数vector,(e)一个浮点数vector,(f)一个字符串vector,(g)一个
整数数组,以及一个表示数组大小的整数值,(h)一个浮点数数组,以及一个表示数组大小的整数
值,(i)一个字符串数组,以及一个表示数组大小的整数值。最后,编写main()测试这些函数。
*/

#include <string>
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;

inline int max ( int t1, int t2 )
    { return t1 > t2 ? t1 : t2; }

inline float max ( float t1, float t2 )
    { return t1 > t2 ? t1 : t2; }

inline string max ( const string& t1, const string& t2 )
    { return t1 > t2 ? t1 : t2; }

inline int max ( const vector<int> &vec )
    { return *max_element( vec.begin(), vec.end() ); }

inline float max ( const vector<float> &vec )
    { return *max_element( vec.begin(), vec.end() ); }

inline string max ( const vector<string> &vec )
    { return *max_element( vec.begin(), vec.end() ); }

inline int max ( const int *parray, int size )
    { return *max_element( parray, parray+size ); }

inline float max( const float *parray, int size )
    { return *max_element( parray, parray+size ); }

inline string max ( const string *parray, int size )
	{ return *max_element( parray, parray+size ); }

int main()
{
    string sarray[] = { "we", "were", "her", "pride", "of", "ten" };
    vector<string> svec( sarray, sarray+6 );

    int iarray[] = { 12, 70, 2, 169, 1, 5, 29 };
    vector<int> ivec( iarray, iarray+7 );

    float farray[] = { 2.5, 24.8, 18.7, 4.1, 23.9 };
    vector<float> fvec( farray, farray+5 );

    int imax = max( max( ivec ), max( iarray, 7 ));
    float fmax = max( max( fvec ), max( farray, 5 ));
    string smax = max( max( svec ), max( sarray, 6 ));

    cout << "imax should be 169  -- found: " << imax << '\n'
         << "fmax should be 24.8 -- found: " << fmax << '\n'
         << "smax should be were -- found: " << smax << '\n';
}

练习 2.6

/*
练习 2.6
以template重新完成练习2.5,并对main()函数适度的修改。
*/

#include <string>
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;

template <typename Type>
inline Type mymax ( Type t1, Type t2 )
    { return t1 > t2 ? t1 : t2; }

template <typename elemType>
inline elemType mymax ( const vector<elemType> &vec )
    { return *max_element( vec.begin(), vec.end() ); }

template <typename arrayType>
inline arrayType mymax ( const arrayType *parray, int size )
    { return *max_element( parray, parray+size ); }

int main()
{
    string sarray[] = { "we", "were", "her", "pride", "of", "ten" };
    vector<string> svec( sarray, sarray+6 );

    int iarray[] = { 12, 70, 2, 169, 1, 5, 29 };
    vector<int> ivec( iarray, iarray+7 );

    float farray[] = { 2.5, 24.8, 18.7, 4.1, 23.9 };
    vector<float> fvec( farray, farray+5 );

    int imax = mymax( mymax( ivec ), mymax( iarray, 7 ));
    float fmax = mymax( mymax( fvec ), mymax( farray, 5 ));
    string smax = mymax( mymax( svec ), mymax( sarray, 6 ));

    cout << "imax should be 169  -- found: " << imax << '\n'
         << "fmax should be 24.8 -- found: " << fmax << '\n'
         << "smax should be were -- found: " << smax << '\n';
}

第三章 泛型编程风格

练习 3.1

/*
练习 3.1
写一个读取文本文件的程序,将文件中每一个单字存入map。map的key便是刚才所说的单字,map的
value则是该单字在文本文件中的出现次数。在定义一份由“排除字眼”组成的set,其中包含诸如a、
an、or、the、and和but之类的单字。将某些单字放入map之前,先确认该单字并不在“排除字集”
中。一旦文本文件读取完毕,请显示一份单字清单,并显示各单字的出现次数。你甚至可以再加以
扩展,在显示单字之前,允许用户查询某个单字是否出现于文本文件中。
*/

#include <map>
#include <set>
#include <string>
#include <iostream>
#include <fstream>
using namespace std;

void initialize_exclusion_set( set<string>& );
void process_file( map<string,int>&, const set<string>&, ifstream& );
void user_query( const map<string,int>& );
void display_word_count( const map<string,int>&, ofstream& );

int main()
{
    ifstream ifile( "C:\\My Document\\column.txt" );
    ofstream ofile( "C:\\My Document\\column.map" );
    if ( !ifile || !ofile ){
        cerr << "Unable to open file -- bailing out!\n";
        return -1;
    }
    
    set<string> exclude_set;
    initialize_exclusion_set( exclude_set );

    map<string,int> word_count;
    process_file( word_count, exclude_set, ifile );
    user_query( word_count );
    display_word_count( word_count, ofile );
}

// “排除字眼”set初始化函数
void initialize_exclusion_set( set<string> &exs )
{
    static string _excluded_words[25] = {
        "the","and","but","that","then","are","been",
        "can","a","could","did","for","of",
        "had","have","him","his","her","its","is",
        "were","which","when","with","would"
    };

    exs.insert( _excluded_words, _excluded_words+25 );
}

// 将文本文件读取到map中
void process_file( map<string,int> &word_count, 
                   const set<string> &excluded_set, ifstream &ifile )
{
    string word;
    while( ifile >> word ){
        if ( excluded_set.count( word ) )
            continue;
        word_count[word]++;
    }
}

// 用户查询函数
void user_query( const map<string,int> &word_map )
{
    string search_word;
    cout << "Please enter a word to search: q to quit";
    cin >> search_word;
    while ( search_word.size() && search_word != "q" ){
        map<string,int>::const_iterator it;
        if ((it = word_map.find( search_word )) != word_map.end() ){
            cout << "Found! " << it->first
                 << " occurs " << it->second
                 << " times.\n";
        }
        else{
            cout << search_word
                 << " was not found in text.\n";
        }
        cout << "\nAnother search? (q to quit)";
        cin >> search_word;
    }
}

// 将文本文件输出
void display_word_count( const map<string,int> &word_map, ofstream &os )
{
    map<string,int>::const_iterator iter = word_map.begin(), 
                                    end_it = word_map.end();
    while ( iter != end_it ){
        os << iter->first << " ( "
           << iter->second << " )" << endl;
        ++ iter;
    }
    os << endl;
}

练习 3.2

/*
练习 3.2
读取文本文件内容————和练习3.1一样————并将内容储存于vector。以字符串长度为依据,对vector
排序。定义一个function object并传给sort();这一function object接受两个字符串,当第一
字符串的长度小于第二字符串的长度时,就返回true。最后,打印排序后的vector内容。
*/

#include <algorithm>
#include <fstream>
#include <iterator>
#include <vector>
#include <string>
#include <iostream>
#include <functional>
using namespace std;

// 定义一个新的function object用于根据字符串长度排序
class LessThan 
{
    public:
    bool operator()( const string &s1, const string &s2 )
         { return s1.size() < s2.size(); }
};

// 定义一个展示vectot的function template
template <typename elemType>
void display_vector( const vector<elemType> &vec, ostream &os=cout, int len=8 )
{
    vector<elemType>::const_iterator 
             iter = vec.begin(),
             end_it = vec.end();
    
    int elem_cnt = 1;
    while ( iter != end_it ){
        os << *iter++
           << ( !( elem_cnt++ % len ) ? '\n' : ' ' );  // 一行8个字符串
        os << endl;
    }
}

int main()
{
    ifstream ifile( "C:\\My Document\\MooCat.txt" );
    ofstream ofile( "C:\\My Document\\MooCat.sort" );

    // 检测输入输出文件是否为空
    if ( !ifile || !ofile ){
        cerr << "Unable to open file -- bailing out!\n";
        return -1;
    }
    
    vector<string> text;
    string word;

    while ( ifile >> word ){
        text.push_back( word );
    }
    
    sort( text.begin(), text.end(), LessThan() );
    display_vector( text, ofile );
}

练习 3.3

/*
练习 3.3
定义一个map,以家族姓氏为key,value则是家族所有小孩的名字。令此map至少容纳六笔数据。
允许用户根据姓氏来查询,并得以打印map内的每一笔数据。
*/

#include <map>
#include <vector>
#include <string>
#include <fstream>
#include <iostream>
#include <iterator>
#include <algorithm>
using namespace std;

typedef vector<string> vstring;
map<string,vstring> families;

void populate_map( ifstream &, map<string,vstring> & );
void display_map( const map<string,vstring> &, ostream & );
void query_map( const string &, const map<string,vstring> & );

int main()
{
    map<string,vstring> families;
    ifstream nameFile( "C:\\My Documents\\families.txt" );

    if ( !nameFile ){
        cerr << "Unable to find families.txt file. Bailing Out!\n";
        return -1;   // 英文原书未返回任何值,错误
    }
    populate_map( nameFile, families );

    string family_name;
    while ( 1 )
    {
        // 除非用户表示要离开,否则一直执行下去
        cout << "Please enter a family name or q to quit ";
        cin >> family_name;

        if ( family_name == "q" )
            break;
        query_map( family_name, families );
    }
    display_map( families, cout );     // 英文原书只有一个参数,错误
}

void populate_map( ifstream &nameFile, map<string,vstring> &families )
{
    string textline;
    while ( getline( nameFile, textline ) )
    // 此行无法通过Visual C++和Borland C++ Builder,只有GCC可接受
    {
        string fam_name;
        vector<string> child;
        string::size_type
            pos = 0, prev_pos = 0,
            text_size = textline.size();
        
        // ok:找出以空格为分隔开来的所有单字
        while ( ( pos = textline.find_first_of( ' ', pos ) ) != string::npos ){
            // 计算子字符串的终点
            string::size_type end_pos = pos - prev_pos;

            // 倘若prev_pos并未设置(或说其值为0),那么读到的单字就是
            // 家庭姓氏,否则我们就一一读取孩子们的名字......
            if ( !prev_pos )
                fam_name = textline.substr( prev_pos, end_pos );
            else
                child.push_back( textline.substr( prev_pos, end_pos ) );
            prev_pos = ++pos;
        }
        
        // 现在处理最后一个孩子的名字
        if ( prev_pos < text_size )
            child.push_back( textline.substr( prev_pos, pos-prev_pos ) );

        if ( !families.count( fam_name ) )
            families[ fam_name ] = child;
        else
            cerr << "Oops! We already have a " << fam_name 
                 << " family in our map!\n";
    }
}

void display_map( const map<string,vstring> &families, ostream &os )
{
    map<string,vstring>::const_iterator
                 it = families.begin(),
                 end_it = families.end();
    
    while ( it != end_it ){
        os << "The " << it->first << " family ";
        if ( it->second.empty() ){
            os << "has no children\n";
        }
        else{
            // 打印出vector内的小孩名字
            os << "has " << it->second.size() << " children: ";
            vector<string>::const_iterator iter = it->second.begin(),
                                           end_iter = it->second.end();
            while ( iter != end_iter ){
                os << *iter << " ";
                ++iter;
            }
            os << endl;
        }
        ++it;
    }
}

void query_map( const string &family, 
                const map<string,vstring> &families )
{
    map<string,vstring>::const_iterator it = families.find( family );

    if ( it == families.end() ){
        cout << "Sorry. The " << family 
             << " it not currently entered.\n";
        return;
    }
    
    cout << "The " << family;
    if ( !it->second.size() ){
        cout << "has no children\n";
    }
    else{
        // 打印出vector内的小孩名字
        cout << "has " << it->second.size() << " children: ";
        vector<string>::const_iterator 
               iter = it->second.begin(),
               end_iter = it->second.end();
        while ( iter != end_iter ){
            cout << *iter << " ";
            ++iter;
        }
        cout << endl;
    }
}

练习 3.4

/*
练习 3.4
编写一个程序,利用istream_iterator从标准输入设备读取一连串整数。利用 ostream_iterator
将其中的奇数写至某个文件,每个数值皆以空格分隔。再利用ostream_iterator将偶数写到另一个
文件,为各数值单独放一行。
*/

#include <iostream>
#include <iterator>
#include <vector>
#include <algorithm>
#include <fstream>
using namespace std;

class even_elem
{
    public:
    bool operator()( int elem )
        { return elem%2 ? false : true; }
};

int main()
{
    vector<int> input;
    istream_iterator<int> in(cin), eos;    // 英文原书有误,少了<int>

    copy( in, eos, back_inserter( input ) );

    vector<int>::iterator division = 
            partition( input.begin(), input.end(), even_elem() );  // 分为“偶-奇”
    
    // 输出文件位置
    ofstream even_file( "C:\\My Document\\even_file" ),
             odd_file( "C:\\My Document\\odd_file" );
    
    // 确定输出文件正常
    if ( !even_file || !odd_file ){
        cerr << "arghh! unable to open the output files. bailing out!";
        return -1;
    }

    // 第二个参数代表每个元素输出时的分隔符
    ostream_iterator<int> even_iter( even_file, "\n" ),
                          odd_iter( odd_file, " " );
    
    copy( input.begin(), division, even_iter );
    copy( division, input.end(), odd_iter );
}

第四章 基于对象的编程风格

练习 4.1

/*
练习 4.1
建立Stack.h和Stack.suffix,此处suffix是你的编译器所能接受的扩展名,或是你的项目所使用
的扩展名。编写main()函数,练习操作Stack的所有公开接口,并加以编译执行。程序代码文件和
main()都必须包含Stack.h:
#include "Stack.h"
*/

#include "Stack.h"
#include <iostream>

int main()
{
    Stack st;
    string str;

    while ( cin >> str && ! st.full() ){
        st.push( str );
    }
    if ( st.empty() ){
        cout << '\n' << "Ooops: no strings were read -- balling out\n ";
        return 0;
    }
    st.peek( str );
    if ( st.size() == 1 && str.empty() ){
        cout << '\n' << "Ooops: no strings were read -- balling out\n ";
        return 0;
    }
    cout << '\n' << "Read in " << str.size() << " string!\n";

    // 将内容全部输出
    while ( st.size() ){
        if ( st.pop( str ) ){
            cout << str << ' ';
        }
    }
    cout << '\n' << "There are now " << st.size()
         << " elements in the stack!\n";
}
// Stack.h
#include <string>
#include <vector>
#include <algorithm>    // 4_2使用泛型算法
using namespace std;

class Stack
{
private:
    vector<string> _stack;
public:
    bool push( const string& );  // 弹出最后一个
    bool pop( string &elem );    // 查看最后一个
    bool peek( string &elem );   // 压入一个
    bool empty() const { return _stack.empty(); }
    bool full() const { return _stack.size() == _stack.max_size(); }
    int  size() const { return _stack.size(); }

    bool find( const string &elem ) const;
    int  count( const string &elem ) const;
};

bool Stack::pop( string &elem )
{
    if ( empty() ){
        return false;
    }
    elem = _stack.back();
    _stack.pop_back();
    return true;
}

bool Stack::peek( string &elem )
{
    if ( empty() ){
        return false;
    }
    elem = _stack.back();
    return true;
}

bool Stack::push( const string &elem )
{
    if ( full() ){
        return false;
    }
    _stack.push_back( elem );
    return true;
}

bool Stack::find( const string &elem ) const
{
    vector<string>::const_iterator end_it = _stack.end();
    return ::find( _stack.begin(), end_it, elem ) != end_it;
}

int Stack::count( const string &elem ) const
    { return ::count( _stack.begin(), _stack.end(), elem ); }

练习 4.2

/*
练习 4.2
扩展Stack的功能,以支持find()和count()两个操作。find()会查看某值是否存在而返回true或
false。count()返回某字符串的出现次数。重新实现练习4.1的main(),让它调用这两个函数。
*/

#include "Stack.h"
#include <string>
#include <iostream>

int main()
{
    Stack st;
    string str;
    while ( cin >> str && ! st.full() ){  // 有输入,且 stack 未满
        st.push( str );
    }
    cout << '\n' << "Read in " << st.size() << " string!\n";
    cin.clear();  // 清除 end-of-file 的设定

    cout << " what word to search for? ";
    cin >> str;

    bool found = st.find( str );
    int  count = found ? st.count( str ) : 0;

    cout << str << (found ? " is " : " isn\'t " ) << "in the stack. ";
    if ( found )
        cout << "It occurs " << count << " times\n";
}

练习 4.3

/*
练习 4.3
考虑以下所定义的全局(global)数据:
  string program_name;
  string version_stamp;
  int version_number;
  int tests_run;
  int tests_passed;
编写一个用以包装这些数据的类。
*/

#include <string>
using std::string;

class globalWrapper
{
private:
    static string _program_name;
    static string _version_stamp;
    static int    _version_number;
    static int    _tests_run;
    static int    _tests_passed;

public:
    static int tests_passed()      { return _tests_passed; }
    static int tests_run()         { return _tests_run; }
    static int version_number()    { return _version_number; }
    static string version_stamp()  { return _version_stamp; }
    static string program_name()   { return _program_name; }

    static int tests_passed( int nval )  { return _tests_passed = nval; }
    static int tests_run( int nval )     { return _tests_run = nval; }

    static void version_number( int nval )            { _version_number = nval; }
    static void version_stamp( const string& nstamp ) { _version_stamp = nstamp; }
    static void program_name( const string& npn )     { _program_name = npn; }
};

string globalWrapper::_program_name;
string globalWrapper::_version_stamp;
int globalWrapper::_version_number;
int globalWrapper::_tests_run;
int globalWrapper::_tests_passed;

练习 4.4

/*
练习 4.4
一份“用户概要记录(user profile)”内含以下数据:登录记录、实际姓名、登入次数、猜对次数、
猜对次数、等级————包括初级、中级、高级、专家,以及猜对百分比(可实时计算获得,或将其值储
存起来备用)。请写出一个名为UserProfile的class,提供以下操作:输入、输出、相等测试、不
等测试。其constructor必须能够处理默认的用户等级、默认的登记名称("guest")。对于同样名
为guest的多个用户,你如何保证每个guest有他自己独有的登录会话(login session),不会和
其他人混淆?
*/

#include "UserProfile.h"
#include <iostream>

int main()
{
    UserProfile anon;
    cout << anon;  // 测试output运算符
    
    UserProfile anon_too; // 看看我们是否取得一份独一无二的标识符
    cout << anon_too;

    UserProfile anna( "AnnaL", UserProfile::Guru );
    cout << anna;
    anna.bump_guess_count( 27 );
    anna.bump_guess_correct( 25 );
    anna.bump_login_count();
    cout << anna;

    cin >> anon;   // 测试input运算符
    cout << anon;
}
// UserProfile.h
#include <iostream>
#include <string>
#include <map>
using namespace std;

class UserProfile
{
public:
    enum uLevel { Beginner, Intermediate, Advanced, Guru };
    UserProfile( string login, uLevel = Beginner );
    UserProfile();

    bool operator==( const UserProfile& );
    bool operator!=( const UserProfile &rhs );

    // 以下函数用来读取数据
    string login() const { return _login; }
    string user_name() const { return _user_name; }
    int login_count() const { return _times_logged; }
    int guess_count() const { return _guesses; }
    int guess_correct() const { return _correct_guesses; }
    double guess_average() const;
    string level() const;

    // 以下函数用来写入数据
    void reset_login( const string &val ) { _login = val; }
    void user_name( const string &val ) { _user_name = val; }

    void reset_level( const string& );
    void reset_level( uLevel newlevel ) { _user_level = newlevel; }

    void reset_login_count( int val ) { _times_logged = val; }
    void reset_guess_count( int val ) { _guesses = val; }
    void reset_guess_correct( int val ) { _correct_guesses = val; }

    void bump_login_count( int cnt=1 ) { _times_logged += cnt; }
    void bump_guess_count( int cnt=1 ) { _guesses += cnt; }
    void bump_guess_correct( int cnt=1 ) { _correct_guesses += cnt; }

private:
    string _login;
    string _user_name;
    int    _times_logged;
    int    _guesses;
    int    _correct_guesses;
    uLevel _user_level;

    static map<string, uLevel> _level_map;
    static void init_level_map();
    static string guest_login();
};

inline double UserProfile::guess_average() const
{
    return _guesses 
           ? double(_correct_guesses) / double(_guesses) * 100 
           : 0.0;
}

inline UserProfile::UserProfile( string login, uLevel level )
    : _login( login ), _user_level( level ), _times_logged( 1 ), _guesses( 0 ), 
    _correct_guesses( 0 ){}

#include <cstdlib>

inline UserProfile::UserProfile()
    : _login( "guest" ), _user_level( Beginner ), _times_logged( 1 ), _guesses( 0 ), 
    _correct_guesses( 0 )
{
    static int id = 0;
    char buffer[16];

    // _itoa()是C标准库所提供的函数,会将整数转换为对应的ASCII字符串形式
    _itoa( id++, buffer, 10 );

    // 针对guest,加入一个独一无二的会话识别符(session id)
    _login += buffer;
}

inline bool UserProfile::operator==( const UserProfile &rhs )
{
    if( _login == rhs._login && _user_name == rhs._user_name )
        return true;
        
    return false;
}

inline bool UserProfile::operator!=( const UserProfile &rhs )
    { return !( *this == rhs ); }

inline string UserProfile::level() const
{
    static string _level_table[] = { "Beginner", "Intermediate", "Advanced", "Guru" 
    return _level_table[ _user_level ];
}

ostream& operator<<( ostream &os, const UserProfile &rhs )
{
    // 输出格式:stanl Beginner 12 100 10 10%
    os << rhs.login() << ' '
       << rhs.level() << ' '
       << rhs.login_count() << ' '
       << rhs.guess_count() << ' '
       << rhs.guess_correct() << ' '
       << rhs.guess_average() << endl;
    return os;
}

// 以下难度颇高,不过恰可作为示范
map<string, UserProfile::uLevel> UserProfile::_level_map;

void UserProfile::init_level_map()
{
    _level_map[ "Beginner" ] = Beginner;
    _level_map[ "Intermediate" ] = Intermediate;
    _level_map[ "Advanced" ] = Advanced;
    _level_map[ "Guru" ] = Guru;
}

inline void UserProfile::reset_level( const string &level )
{
    map<string, uLevel>::iterator it;
    if( _level_map.empty() ){
        init_level_map();
    }
    // 确保level的确代表一个可识别的用户等级
    _user_level = 
        (( it = _level_map.find( level )) != _level_map.end() ) 
              ? it->second : Beginner;
}

istream& operator>>( istream &is, UserProfile &rhs )
{
    // 是的,以下假设所有输入都有效,不做错误检验。
    string login, level;
    is >> login >> level;

    int lcount, gcount, gcorrect;
    is >> lcount >> gcount >> gcorrect;
    rhs.reset_login( login );
    rhs.reset_level( level );

    rhs.reset_login_count( lcount );
    rhs.reset_guess_count( gcount );
    rhs.reset_guess_correct( gcorrect );

    return is;
}

练习 4.5

/*
练习 4.5
请实现一个4×4的 Matrix class,至少提供以下接口:矩阵加法、矩阵乘法、打印函数print()、
复合运算符+=,以及一组支持下标操作(subscripting)的function call运算符,像下面这样:
  float& operation()( int row, int colunm );
  float  operation()( int row, int colunm ) const;
请提供一个default constructor,可选择性地接受16个数据值。再提供一个constructor,可接
受一个拥有16个元素的数组。你不需要为此class提供copy constructor、copy assignment 
operator、destructor。第六章重新实现 Matrix class时才需要这几个函数,用以支持任意行列
的矩阵。
*/

#include "Matrix.h"

int main()
{
    Matrix m;
    cout << m << endl;

    elemType ar[16] = {
       1., 0., 0., 0., 0., 1., 0., 0.,
       0., 0., 1., 0., 0., 0., 0., 1. };
    
    Matrix identity( ar );
    cout << identity << endl;

    Matrix m2( identity );
    m = identity;
    cout << m2 << endl;
    cout << m << endl;

    elemType ar2[16] = {
       1.3, 0.4, 2.6, 8.2, 6.2, 1.7, 1.3, 8.3,
       4.2, 7.4, 2.7, 1.9, 6.3, 8.1, 5.6, 6.6 };
    Matrix m3( ar2 );
    cout << m3 << endl;

    Matrix m4 = m3 * identity;
    cout << m4 << endl;
    
    Matrix m5 = m3 + m4;
    cout << m5 << endl;
    
    m3 += m4;
    cout << m3 << endl;
}
// Matrix.h
#include <iostream>
using namespace std;

typedef float elemType;   // 方便我们转为template形式

class Matrix
{
    // friend声明不受访问权限的影响
    // 可以放到class一开始处
    friend Matrix operator+( const Matrix&, const Matrix& );
    friend Matrix operator*( const Matrix&, const Matrix& );
    
public:
    Matrix( const elemType* );
    Matrix( elemType=0.,elemType=0.,elemType=0.,elemType=0.,
            elemType=0.,elemType=0.,elemType=0.,elemType=0.,
            elemType=0.,elemType=0.,elemType=0.,elemType=0.,
            elemType=0.,elemType=0.,elemType=0.,elemType=0. );

    // 不需要为Matrix提供copy constructor、destructor、
    // copy assignment operator。

    // 简化“转换至通用型矩阵(general matrix)”的过程
    int rows() const { return 4; }
    int cols() const { return 4; }

    ostream& print( ostream& ) const;
    void operator+=( const Matrix& );
    elemType operator()( int row, int column ) const
            { return _matrix[ row ] [ column ]; }
	elemType& operator()( int row, int column )
            { return _matrix[ row ] [ column ]; }
private:
    elemType _matrix[4][4];
};

inline ostream& operator<<( ostream& os, const Matrix &m )
	{ return m.print( os ); }

Matrix operator+( const Matrix &m1, const Matrix &m2 )
{
    Matrix result( m1 );
    result += m2;
    return result;
}

Matrix operator*( const Matrix &m1, const Matrix &m2 )
{
    Matrix result;
    for ( int ix = 0; ix < m1.rows(); ix++ ){
        for ( int jx = 0; jx < m1.cols(); jx++ ){
            result( ix, jx ) = 0;
            for ( int kx = 0; kx < m1.cols(); kx++ ){
                result( ix, jx ) += m1( ix, kx ) * m2( kx, jx );
            }
        }
    }
    return result;
}

void Matrix::operator+=( const Matrix &m )
{
    for (int ix = 0; ix < 4; ix++ )
        for ( int jx = 0; jx < 4; jx++ )
            _matrix[ix] [jx] += m._matrix[ix] [jx];
}

ostream& Matrix::print( ostream &os ) const
{
    int cnt = 0;
    for ( int ix = 0; ix < 4; ix++ ){
        for ( int jx = 0; jx < 4; jx++, ++cnt ){
            if ( cnt && !( cnt % 8 )){
                os << endl;
            }
            os << _matrix[ix] [jx] << ' ';
        }
    }
    os << endl;
    return os;
}

Matrix::Matrix( const elemType *array )
{
    int array_index = 0;
    for ( int ix = 0; ix < 4; ix++ )
        for ( int jx = 0; jx < 4; ++jx )
            _matrix[ix] [jx] = array[array_index++];
}

Matrix::Matrix(
        elemType a11, elemType a12, elemType a13, elemType a14,
        elemType a21, elemType a22, elemType a23, elemType a24,
        elemType a31, elemType a32, elemType a33, elemType a34,
        elemType a41, elemType a42, elemType a43, elemType a44 )
{
    _matrix[0][0] = a11; _matrix[0][1] = a12; _matrix[0][2] = a13; _matrix[0][3] = a14;
    _matrix[1][0] = a21; _matrix[1][1] = a22; _matrix[1][2] = a23; _matrix[1][3] = a24;
    _matrix[2][0] = a31; _matrix[2][1] = a32; _matrix[2][2] = a33; _matrix[2][3] = a34;
    _matrix[3][0] = a41; _matrix[3][1] = a42; _matrix[3][2] = a43; _matrix[3][3] = a44;
}

第五章 面向对象的编程风格

练习 5.1

/*
练习 5.1
实现一个两层的stack(堆栈)类体系。其基类是个纯抽象类Stack,只提供最简单的接口:pop()、
push()、size()、empty()、full()、peek()和print()。两个派生类则为LIFO_Stack和
Peekback_Stack。Peekback_Stack可以让用户在不更改stack元素的前提下,访问任何一个元素。
*/

#include <string>
#include <iostream>
#include <vector>
using namespace std;

// Stack 类定义
typedef string elemType;
class Stack{
public:
    virtual ~Stack(){};
    virtual bool pop( elemType& ) = 0;
    virtual bool push( const elemType& ) = 0;
    virtual bool peek( int index, elemType& ) = 0;

    virtual int  top() const = 0;
    virtual int  size() const = 0;

    virtual bool empty() const = 0;
    virtual bool full() const = 0;
    virtual void print( ostream& = cout ) const = 0;
};

ostream& operator<<( ostream &os, const Stack &rhs )
      {rhs.print(); return os;}

class LIFO_Stack : public Stack{
public:
    LIFO_Stack( int capacity = 0 ) : _top( 0 )
         { if ( capacity ) _stack.reserve( capacity ); }
    int size()   const { return _stack.size(); }
    bool empty() const { return ! _top; }
    bool full()  const { return size() >= _stack.max_size(); }
    int top()    const { return _top; }
    void print( ostream &os=cout ) const;

    bool pop( elemType &elem );
    bool push( const elemType &elem );
    bool peek( int, elemType& ) { return false; }
private:
    vector< elemType > _stack;
    int _top;
};

class Peekback_Stack : public Stack{
public:
    Peekback_Stack( int capacity = 0 ) : _top( 0 )
         { if ( capacity ) _stack.reserve( capacity ); }
    int size()   const { return _stack.size(); }
    bool empty() const { return ! _top; }
    bool full()  const { return size() >= _stack.max_size(); }
    int top()    const { return _top; }
    void print( ostream &os=cout ) const;

    bool pop( elemType &elem );
    bool push( const elemType &elem );
    bool peek( int, elemType& ) ;
private:
    vector< elemType > _stack;
    int _top;
};

bool LIFO_Stack::pop( elemType &elem ){
    if ( empty() ) return false;
    elem = _stack[ --_top ];
    _stack.pop_back();
    return true;
}

bool LIFO_Stack::push( const elemType &elem ){
    if ( full() ) return false;
    _stack.push_back( elem );
    ++_top;
    return true;
}

void LIFO_Stack::print( ostream &os=cout ) const {
    vector<elemType>::const_reverse_iterator
           rit = _stack.rbegin(),
           rend = _stack.rend();

    os << "\n\t";
    while ( rit != rend )
            os << *rit++ << "\n\t";
    
    os << endl;
}

bool Peekback_Stack::peek( int index, elemType &elem )
{
    if ( empty() )
        return false;
    
    if ( index < 0 || index >= size() )
        return false;

    elem = _stack[ index ];
    return true;
}

void peek( Stack &st, int index )
{
    cout << endl;
    string t;
    if ( st.peek( index, t ) )
         cout << "peek: " << t;
    else cout << "peek failed!";
    cout << endl;
}

// 主函数
int main()
{
    LIFO_Stack st;
    string str;
    while ( cin >> str && ! st.full() )
             st.push( str );
    cout << '\n' << "About to call peek() with LIFO_Stack" << endl;
    peek( st, st.top()-1 );
    cout << st;

    Peekback_Stack pst;

    while ( ! st.empty() ){
        string t;
        if ( st.pop( t ) )
            pst.push( t );
    }
    
    cout << "About to call peek() with Peekback_Stack" << endl;
    peek( pst, pst.top()-1 );
    cout << pst;
}

练习 5.2

/*
练习 5.2
重新实现练习5.1的类体系,令基类Stack实现出各派生类共享的、与类型无关的所有成员。
*/

#include <string>
#include <iostream>
#include <vector>
using namespace std;

typedef string elemType;
class Stack
{
public:
    Stack( int capacity = 0 ) : _top( 0 )
    {
        if ( capacity )
            _stack.reserve( capacity );
    }
    virtual ~Stack(){};

    bool pop( elemType& );
    bool push( const elemType& );
    virtual bool peek( int, elemType& )
            { return false; }
    int size()  const { return _stack.size(); }
    int top()   const { return _top; }

    bool empty() const { return ! _top; }
    bool full()  const { return size() >= _stack.max_size(); }
    void print( ostream &os=cout ) const;

protected:
    vector<elemType> _stack;
    int _top;
};

// 只展示了与5.1不同的内容
class Peekback_Stack : public Stack {
public:
    Peekback_Stack( int capacity = 0 )
        : Stack( capacity ) {}
    
    virtual bool peek( int index, elemType &elem );
};

第六章 以template进行编程

练习 6.1

/*
练习 6.1
试改写一下类,使它成为一个class template:
    class example{
    public:
          example( double min, double max );
          example( const double *array, int size );
          double& operator[]( int index );
          bool operator==( const example& ) const;
          bool insert( const double*, int );
          bool insert( double );
          double min() const { return _min; }
          double max() const { return _max; }
          voud min( double );
          void max( double );
          int count( double value ) const;
    private:
          int size;
          double *parray;
          double _min;
          doubel _max;
    };
*/

template <typename elemType>
class example{
public:
      example( const elemType &min, const elemType &max );
      example( const elemType *array, int size );

      elemType& operator[]( int index );
      bool operator==( const example& ) const;

      bool insert( const elemType*, int );
      bool insert( const elemType& );

      elemType min() const { return _min; }
      elemType max() const { return _max; }

      void min( const elemType& );
      void max( const elemType& );

      int count( const elemType &value ) const;

private:
      int       _size;
      elemType *_parray;
      elemType  _min;
      elemType  _max;
};

练习 6.2

/*
练习 6.2
重新以template形式实现练习4.3的 Matrix class,并扩充其功能,使它能够通过 heap memory
(堆内存)来支持任意行列大小。分配/释放内存的操作,请在 constructor/destructor中进行。
*/

#include <iostream>
using namespace std;

template <typename elemType>
class Matrix
{
    friend Matrix<elemType>
        operator+( const Matrix<elemType>&, const Matrix<elemType>& );
    friend Matrix<elemType>
        operator*( const Matrix<elemType>&, const Matrix<elemType>& );

public:
    Matrix( int rows, int columns );
    Matrix( const Matrix& );
    ~Matrix();
    Matrix& operator=( const Matrix& );

    void operator+=( const Matrix& );
    elemType& operator()( int row, int column )
        { return _matrix[ row * cols() + column ]; }
    
    const elemType& operator()( int row, int column ) const
        { return _matrix[ row * cols() + column ]; }
    
    int rows() const { return _rows; }
    int cols() const { return _cols; }

    bool same_size( const Matrix &m ) const
        { return rows() == m.rows() && cols() == m.cols(); }
    
    bool comfortable( const Matrix &m ) const
        { return ( cols() == m.rows() ); }
    ostream& print( ostream& ) const;

protected:
    int _rows;
    int _cols;
    elemType *_matrix;
};

template <typename elemType>
inline ostream&
operator<<( ostream& os, const Matrix<elemType> &m )
    { return m.print( os ); }

// Matrix.h文件结束


template <typename elemType>
Matrix< elemType >
operator+( const Matrix<elemType> &m1, const Matrix<elemType> &m2 )
{
    // 确定m1和m2的大小相同
    Matrix<elemType> result( m1 );
    result += m2;
    return result;
}

template <typename elemType>
Matrix<elemType>
operator*( const Matrix<elemType> &m1, const Matrix<elemType> &m2 )
{
    // m1的行数(row)必须等于m2的列数(column)
    Matrix<elemType> result( m1.rows(), m2.cols() );
    for ( int ix = 0; ix < m1.rows(); ix++ ){
        for ( int jx = 0; jx <m1.cols(); jx++ ){
            result( ix, jx ) = 0;
            for ( int kx = 0; kx < m1.cols(); kx++ )
                result( ix, jx ) += m1( ix, kx ) * m2( kx, jx );
        }
    }
    return result;
}

template <typename elemType>
void Matrix<elemType>::operator+=( const Matrix &m ){
    // 确定m1和m2的大小相同
    int matrix_size = cols() * rows();
    for ( int ix = 0; ix < matrix_size; ++ix )
        ( *( _matrix + ix )) += ( *( m._matrix + ix ));
}

template <typename elemType>
ostream& Matrix<elemType>::print( ostream &os ) const {
    int col = cols();
    int matrix_size = col * rows();
    for ( int ix = 0; ix < matrix_size; ++ix ){
        if ( ix % col == 0 ) os << endl;
        os << ( *( _matrix + ix )) << ' ';
    }
    os << endl;
    return os;
}

// 主程序
# include <fstream>
int main()
{
    ofstream log( "C:\\My Documents\\log.txt" );
    if ( ! log )
        { cerr << "can't open log file!\n"; return; }
    
    Matrix<float> identity( 4, 4 );
    log << "identity: " << identity << endl;
    float ar[16]={ 1., 0., 0., 0., 0., 1., 0., 0.,
                   0., 0., 1., 0., 0., 0., 0., 1. };
    
    for ( int i = 0, k = 0; i < 4; ++i )
        for ( int j = 0; j < 4; ++j )
            identity( i, j ) = ar[ k++ ];
    log << "identity after set: " << identity << endl;

    Matrix<float> m( identity );
    log << "m: memberwise initialized: " << m << endl;

    Matrix<float> m2( 8, 12 );
    log << "m2: 8x12: " << m2 << endl;

    m2 = m ;
    log << "m2 after memberwise assigned to m: "
        << m2 << endl;
    
    float ar2[16]={ 1.3, 0.4, 2.6, 8.2, 6.2, 1.7, 1.3, 8.3, 
                    4.2, 7.4, 2.7, 1.9, 6.3, 8.1, 5.6, 6.6 };
    
    Matrix<float> m3( 4, 4 );
    for ( int ix = 0, kx = 0; ix < 4; ++ix )
        for ( int j = 0; j < 4; ++j )
            m3( ix, j ) = ar2[ kx++ ];

    log << "m3: assigned random values: " << m3 << endl;

    Matrix<float> m4 = m3 * identity; log << m4 << endl;
    Matrix<float> m5 = m3 + m4; log << m5 << endl;

    m3 += m4; log << m3 << endl;
}

第七章 异常处理

练习 7.1

/*
练习 7.1
以下函数完全没有检查可能的数据错误以及可能的执行失败。请找出此函数中所有可能发生错误的地
方。本题并不考虑出现异常(exception)。
    int *alloc_and_init( string file_name )
    {
        ifstream infile( file_name );
        int elem_cnt;
        infile >> elem_cnt;
        int *pi = allocate_array( elem_cnt );

        int elem;
        int index = 0;
        while( infile >> elem )
            pi[ index++ ] = elem;

        sort_array( pi, elem_cnt );
        register_data( pi );

        return pi;
    }
*/

1、ifstream constructor接收的参数类型是 const char*而非 string,利用string的member
function c_str()转换为C-style:
    ifstream infile( file_name.cstr() );
2、检查文件是否成功打开:
    if ( ! infile )
3、检查指针是否指向实际存在的对象:
    if ( ! pi )

ifstream infile( file_name.cstr() );
if ( ! infile )
int elem_cnt;
infile >> elem_cnt;
if ( ! infile )
int *pi = allocate_array( elem_cnt );
if ( ! pi )

练习 7.2

/*
练习 7.2
下列函数被上题的alloc_and_ini()调用,执行失败时会发生异常:
    allocate_array()   发生异常 noMem
    sort_array()       发生异常 int
    register()         发生异常 string
请安置一个或多个try块,以及相应的catch子句,以便能适当地处理这些异常。相应的catch子句中
只需要将错误打印出来即可。
*/

#include <string>
#include <fstream>
#include <iostream>
using namespace std;

int *alloc_and_init( string file_name )
{
    ifstream infile( file_name.c_str() );
    if ( ! infile ) return 0;

    int elem_cnt;
    infile >> elem_cnt;
    if ( ! infile ) return 0;

    try {
       int *pi = allocate_array( elem_cnt );   // (1)
       int elem;
       int index = 0;
       while ( infile >> elem && index < elem_cnt )
               pi[ index++ ] = elem;
        
        sort_array( pi, elem_cnt );            // (2)
        register_data( pi );                   // (3)
    }
    catch( const noMem &memFail ) {            // 异常情况(1)
        cerr << "alloc_and_init(): allocate_array failure!\n"
             << memFail.what() << endl;
        return 0;
    }
    catch( int &sortFail ) {                   // 异常情况(2)
        cerr << "alloc_and_init(): sort_array failure!\n"
             << "thrown integer value: " << sortFail << endl;
        return 0;
    }
    catch( string &registerFail ) {            // 异常情况(3)
        cerr << "alloc_and_init(): register_data failure!\n"
             << "thrown string value: "
             << registerFail << endl;
        return 0;
    }
    return pi;  // 如果没有任何异常被抛出,就会执行到这里......
}

练习 7.3

/*
练习 7.3
为练习5.2的Stack类体系加入两个异常类型,处理“想从空stack中取出元素”和“想为满stack添加
元素”两种错误。请显示修改后的pop()和push()。
*/

#include <string>
using namespace std;

template<typename elemType>
void pop( elemType &elem )
{
    if ( empty() )
        throw PopOnEmpty();
    elem = _stack[ --_pop ];
    _stack.pop_back();
}

template<typename elemType>
void push( const elemType &elem )
{
    if ( ! full() ){
        _stack.push_back( elem );
        ++_top;
        return;
    }
    throw PushOnFull();
}

class StackException : public logic_error {
public:
    StackException( const char *what ) : _what( what ){}
    const char *what() const { return _what.c_str(); }
protected:
    string _what;
};

class PopOnEmpty : public StackException {
public:
    PopOnEmpty() : StackException( "Pop on Empty Stack" ) {}
};

class PushOnFull : public StackException {
public:
    PushOnFull() : StackException( "Push on Full Stack" ) {}
};

// 定义后,以下任何一个catch句子都能处理PushOnFull的异常:
catch( const PushOnFull &pof )
    { log( pof.what() ); return; }

catch( const StackException &stke )
    { log( stke.what() ); return; }

catch( const logic_error &lge )
    { log( lge.what() ); return; }

catch( const exception &ex )
    { log( ex.what() ); return; }
  • 14
    点赞
  • 49
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

猎猫骑巨兽

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值