<Essential C++> Learning

来源:互联网 发布:真维斯官方旗舰店淘宝 编辑:程序博客网 时间:2024/05/18 02:12

1. Chapter 1: Basic C++ Programming

1.1 Pass by value and pass by reference

#include <iostream> #include <vector>using namespace std;    void display_ref(const vector<int> &); void display_ptr(const vector<int> *); int main() {      const int arr[5] = { 1, 1, 2, 3, 5 };    const vector<int> fabnc(arr,arr+5);     cout << "By reference: " ;    display_ref(fabnc);      cout << "By pointer: " ;    display_ptr(&fabnc); }void display_ref(const vector<int> &vec) {     int i;     for ( i=0 ; i<vec.size() ; i++ )     {         cout << vec[i] << ' ';     }     cout << endl ; }void display_ptr(const vector<int> *pv) {     int i;     for ( i=0 ; i<pv->size() ; i++ )     {         cout << (*pv)[i] << ' ';     }     cout << endl ; }

2. Chapter 2: Procedural Programming

2.1 Exercise 2.2

   The formula for the Pentagonal numeric sequence is Pn=n*(3n-1)/2. This yields the sequence 1, 5, 12, 22, 35, and so on. Define a function to fill a vector of elements passed in to the function calculated to some user-specified position. Be sure to verify that the position specified is valid. Write a second function that, given a vector, displays its elements. It should take a second parameter identifying the type of numeric series the vector represents. Write a main() function to exercise these functions.

#include <vector> #include <string> #include <iostream> using namespace std; bool calc_vec(int, vector<int> &); void display_vec(vector<int> &, const string &, ostream &os = cout);        //ostream object must be passed by reference int main() {     vector<int> pent;    const string series_name = "Pentagonal Numeric Series";         char go_on = 'y';      int size;    while(go_on == 'y' || go_on == 'Y')     {         cout << "Please input the series size:";         cin >> size;        if ( calc_vec(size,pent ) == true )          {             display_vec(pent, series_name);         }         cout << "Go on?(y/n)\n" << endl ;          cin >> go_on ;      } }  bool calc_vec(int size, vector<int> &array)  {     if ( size <= 0 || size > 1000 )     {         cerr << "Array size is not correct!\n";         return false ;     }      int i ;    for ( i = array.size() ; i < size ; ++i)     {        array.push_back( (i+1)*(3*(i+1)-1)/2 );     }     return true; }  void display_vec(vector<int> &array, const string &series_name, ostream &os) {      os << series_name << ':' << endl ;     for (int i=0 ; i < array.size() ; ++i )     {         os << array[i] << ' ' ;     }     os << endl ; } 

3. Chapter 3: Generic Programming

3.1 Exercise 3.1

   Write a program to read a text file. Store each word in a map. The key value of the map is the count of the number of times the word appears in the text. Define a word exclusion set containing words such as a, an, or, the, and, and but. Before entering a word in the map, make sure it is not present in the word exclusion set. Display the list of words and their associated count when the reading of the text is complete. As an extension, before displaying the text, allow the user to query the text for the presence of a word.

3.1.1 Version 0

#include <iostream> #include <fstream>#include <map> #include <set> #include <iterator>#include <string> using namespace std;  int main() {     ifstream in_file("text.txt") ;      if( ! in_file )     {         cerr << "Cannot open input file for reading!\n" ;           return -1 ;     }      istream_iterator< string > is( in_file ) ;      istream_iterator< string > ieof ;      map< string, int > word_count ;      string exclusion_word[6] = ("a", "an", "the", "and", "or", "but") ;     set< string > word_exclusion( exclusion_word, exclusion_word+6 ) ;     while( is != ieof )     {         if( word_exclusion.count(*is) )          {              ++ is ;             //cout << *is << endl ;             continue ;          }         else         {              ++ is ;              ++ word_count[*is] ;         }     }     map< string, int >::iterator map_iterator = word_count.begin() ;     for( ; map_iterator != word_count.end(); ++map_iterator )     {         cout << map_iterator -> first << ":" << "\t\t\t"             << map_iterator -> second << endl ;       } }

3.1.2 Version 1

#include <iostream> #include <fstream>#include <map> #include <set> #include <iterator>#include <string> using namespace std; int main() {     ifstream in_file("text.txt") ;      if( ! in_file )     {         cerr << "Cannot open input file for reading!\n" ;           return -1 ;     }      map< string, int > word_count ;      string exclusion_word[6] = {"a", "an", "the", "and", "or", "but"} ;     set< string > word_exclusion ;      word_exclusion.insert( exclusion_word, exclusion_word+6 ) ;     string word ;     while( in_file >> word )     {         if( word_exclusion.count(word) )          {   //            cout << word << endl ;             continue ;          }         else         {              ++ word_count[word] ;         }     }     map< string, int >::iterator map_iterator = word_count.begin() ;     for( ; map_iterator != word_count.end(); ++map_iterator )     {         cout << map_iterator -> first << "\t\t\t"             << map_iterator -> second << endl ;       } }

3.2 Exercise 3.2

   Read in a text file, it can be the same one as in Exercise 3.1, storing it in a vector. Sort the vector by the length of the string. Define a function object to pass to sort(); it should accept two strings and return true if the first string is shorter than the second. Print the sorted vector.

//note: const usage. #include <iostream> #include <fstream> #include <vector> #include <string> #include <iterator> using namespace std ; class LessThan {     public:         bool operator() (const string &s1, const string &s2)         {             return (s1.size() < s2.size()) ? true : false ;          } } ;   template <typename type> void display(const vector<type> &vec, ostream &os=cout, int len=8) {     typename vector<type>::const_iterator                   //typename is needed in g++, but in VC and intel compiler does not.         it = vec.begin() ,          end_iterator = vec.end() ;   //  typename      vector<type>::const_iterator it = vec.begin() ;//  typename      vector<type>::const_iterator   end_iterator = vec.end() ;            int count = 1 ;     while( it != end_iterator )     {           os  << *it++              << ( (count++%len) ? " " : "\n" );              //Note: shift takes precedence over ternary conditional expression.     }     os << endl ; }int main() {     ifstream in_file("text.txt") ;      if( ! in_file )     {         cerr << "Cannot open input file for reading!\n" ;          return -1 ;      }       vector<string> text ;     string word ;     while( in_file >> word)     {          text.push_back(word) ;      }     sort(text.begin(), text.end(), LessThan()) ;      display(text) ;  }

3.3 Exercise 3.4

   Write a program to read a sequence of integer numbers from standard input using an istream_iterator. Write the odd numbers into one file using an ostream_iterator. Each value should be separated by a space. Write the even numbers into a second file, also using an ostream_iterator. Each of these values should be placed on a separate line.

3.3.1 Version 0

//mine#include <iostream> #include <fstream> #include <iterator> using namespace std ; int main() {     cout << "Please input a series of integers:\n" ;      istream_iterator<int> is_it( cin ), ieof ;     ofstream ofs_odd("odd.txt") ;      if( ! ofs_odd )  cerr << "Cannot open odd.txt for writing!\n" ;     ofstream ofs_even("even.txt") ;       if( ! ofs_even ) cerr << "Cannot open even.txt for writing!\n" ;     ostream_iterator<int> os_odd(ofs_odd, " ") ;      ostream_iterator<int> os_even(ofs_even, " ") ;      while( is_it != ieof)     {         if(*is_it % 2) *os_odd++ = *is_it++ ;          else            *os_even++ = *is_it++ ;      } }

3.3.2 Version 1

// Lippman's solution#include <iterator> #include <vector> #include <iostream> #include <fstream> #include <algorithm> 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;    copy( in, eos, back_inserter( input ));    vector<int>::iterator division =         partition( input.begin(), input.end(), even_elem() );       ofstream even_file( "even_file" ),              odd_file( "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 ); }

3.4 generic_programming_example

#include <iostream>#include <vector> #include <functional> using namespace std;  template <typename InputIterator, typename OutputIterator,          typename ElemType, typename Comp> OutputIterator filter( InputIterator first, InputIterator last,         OutputIterator at, const ElemType &val, Comp pred ) {     while (( first =              find_if( first, last,                       bind2nd( pred, val ))) != last )     {              // just to see what is going on ...              cout << "found value: " << *first << endl;              // assign value, then advance both iterators              *at++ = *first++;     }     return at; } int main() {    const int elem_size = 8;    int ia[ elem_size ] = { 12, 8, 43, 0, 6, 21, 3, 7 };    vector<int> ivec( ia, ia+elem_size );    // containers to hold the results of our filter()    int ia2[ elem_size ];    vector<int> ivec2( elem_size );    cout << "filtering integer array for values less than 8\n";    cout << "Pointer to store area before filtering:" << ia2 << "\n";    cout << "Pointer to the tail of store area :" << filter( ia, ia+elem_size, ia2, elem_size, less<int>() ) << "\n";     //filter( ia, ia+elem_size, ia2, elem_size, less<int>() );   cout << "Pointer to store area after filtering:" << ia2 << "\n";    cout << "filtering integer vector for values greater than 8\n";    filter( ivec.begin(), ivec.end(), ivec2.begin(),            elem_size, greater<int>() ); }

3.5 generic_programming_exercise

//Note: //line 13: const //line 21: not1, (not2) //line 24: const, pay attention! Stack is released after the call, so you can not use the variant in that function. //          Use const to initialize the value returned by sub_vec to vec, a beter way is to passing parameter by value. #include <iostream> #include <vector> #include <functional> using namespace std ; template <typename input_iterator_type, typename elem_type, typename function_object_type> vector<int>sub_vec(input_iterator_type first, input_iterator_type last, const elem_type &value, function_object_type function) {     vector<int> local_vec( first, last ) ;       sort( local_vec.begin(), local_vec.end(), function ) ;           vector<int>::iterator iter =          find_if( local_vec.begin(),                   local_vec.end(),                  not1( bind2nd( function, value ) )                ) ;      local_vec.erase( iter, local_vec.end() ) ;      return local_vec ;  }void display_vec(const vector<int> &vec) {     int i=0;     for( i=0; i<vec.size(); ++i )     {         cout << vec[i] << ' ' ;     }     cout << endl ;  } //  ALSO//void display_vec(vector<int> vec) //{ //    int i=0; //    for( i=0; i<vec.size(); ++i ) //    { //        cout << vec[i] << ' ' ; //    } //    cout << endl ;  //} int main() {    const int elem_size = 8;    int ia[ elem_size ] = { 12, 8, 43, 0, 6, 21, 3, 7 };    vector<int> ivec( ia, ia+elem_size );    // containers to hold the results of our sub_vec()    int ia2[ elem_size ];    vector<int> ivec2( elem_size );    cout << "filtering integer array for values less than 8\n";    display_vec  (                      sub_vec( ia, ia+elem_size, elem_size, less<int>() )                  ) ;    cout << "filtering integer vector for values greater than 8\n";    display_vec  (                      sub_vec( ivec.begin(), ivec.end(), elem_size, greater<int>() )                  ) ; }

3.6 Iostream iterator

3.6.1 iostream_iterator

#include <iostream> #include <iterator> #include <algorithm> #include <vector> #include <string> using namespace std; int main() {    istream_iterator< string > is( cin );    istream_iterator< string > eof;              //use ctrl+z in windows and ctrl+d in linux.    vector< string > text;    copy( is, eof, back_inserter( text ));    sort( text.begin(), text.end() );    ostream_iterator<string> os( cout, " " );    copy( text.begin(), text.end(), os ); }

3.6.2 iostream_iterator_file

#include <iostream> #include <fstream> #include <iterator> #include <algorithm> #include <vector> #include <string> using namespace std; int main() {    ifstream in_file( "in.txt" );    ofstream out_file( "out.txt" );    if ( ! in_file || ! out_file )    {         cerr << "!!unable to open the necessary files.\n";         return -1;    }    istream_iterator< string > is( in_file );    istream_iterator< string > eof;    vector< string > text;    copy( is, eof, back_inserter( text ));    sort( text.begin(), text.end() );    ostream_iterator<string> os( out_file, " " );    copy( text.begin(), text.end(), os );}

4. Chapter 4: Object-Based Programming


4.1 Example


4.1.1 triangular


Triangular.cpp

#include <algorithm> #include <iostream> #include "Triangular.h" using namespace std ;  vector<int> Triangular::_elems ; Triangular::Triangular( int len, int beg_pos )     : _length( len > 0 ? len : 1 ),       _beg_pos( beg_pos > 0 ? beg_pos : 1 ) {    _next = _beg_pos-1;    int elem_cnt = _beg_pos + _length;    if ( _elems.size() < elem_cnt )         gen_elements( elem_cnt ); } bool Triangular:: is_elem( int value ) {    if ( ! _elems.size() ||         _elems[ _elems.size()-1 ] < value )             gen_elems_to_value( value );    vector<int>::iterator found_it;    vector<int>::iterator end_it = _elems.end();    found_it = find( _elems.begin(), end_it, value );    return found_it != end_it; }  void Triangular:: gen_elements( int length ) {     if ( length < 0 || length > _max_elems ){          // issue error message and return     }     if ( _elems.size() < length )     {          int ix = _elems.size() ? _elems.size()+1 : 1;          for ( ; ix <= length-1; ++ix )                _elems.push_back( ix*(ix+1)/2 );     } } //void Triangular::gen_elements( int length ) //{ //    for( int i=1; i<= length; ++i )//    { //        _elems.push_back( i*(i+1)/2 ) ;  //    } //} void Triangular:: gen_elems_to_value( int value ) {    int ix = _elems.size();    if ( ! ix )    {         _elems.push_back( 1 );         ix = 1;    }    while ( _elems[ ix-1 ] < value &&            ix < _max_elems )    {       // cout << "elems to value: " << ix*(ix+1)/2 << endl;       _elems.push_back( ix*(ix+1)/2 );       ++ix;    }    if ( ix == _max_elems )        cerr << "Triangular Sequence: oops: value too large "             << value << " --  exceeds max size of "             << _max_elems << endl; } 
Triangular.h
#ifndef TRIANGULAR_H #define TRIANGULAR_H #include <vector>using namespace std; class Triangular  { public:        Triangular(int len, int beg_pos ) ;      static bool is_elem( int value );           //Static means this function does not depend on whether the class is instantiated to an object or not.     static void gen_elements( int length );     static void gen_elems_to_value( int value ); //   static void display( int len, int beg_pos, ostream &os = cout );     // ... private:     int _length ;      int _beg_pos ;      int _next ;     static const int   _max_elems = 1024;       //Not allowed in VC.     static vector<int> _elems;     // ... }; #endif

4.1.2 triangular_iterator

Triangular_iterator.cpp▽
#include "Triangular_iterator.h" #include <algorithm>  vector<int> Triangular::_series ; Triangular::Triangular( int len, int start_position ) {     _length = len>=0 ? len : 1 ;     _start_position = start_position>=0 ? start_position : 1 ;       gen_series() ;  }  void Triangular::gen_series() {     //if( length<= 0 || length > _max_length )     //{     //    cerr << "Invalid length during generating series!\n" ;      //}     //if( length > _length )    //{     //    for( ; _length<=length; _length++)     //    {     //        _series[_length-1] =     for( int i=_start_position; i<_start_position+_length; i++)     {          _series.push_back( i*(i+1)/2 ) ;      } }
Triangular_iterator.h
#ifndef TRIANGULAR_ITERATOR_H #define TRIANGULAR_ITERATOR_H  #include <vector> using namespace std ; class Triangular_iterator {     public:           Triangular_iterator(const int &rhs) : _index( rhs ) {}            //Triangular_iterator tri_it = xxx ; This will call the constructor with one parameter, that is what's rhs means.         int operator *() const ;         bool operator ==( const Triangular_iterator& ) const ;          bool operator !=( const Triangular_iterator& ) const ;          Triangular_iterator& operator++() ;          Triangular_iterator operator++( int ) ;              private:          int _index ;  } ;  class Triangular {     public:         typedef Triangular_iterator iterator ;         friend class Triangular_iterator ;         Triangular(){ _length = 1 ; _start_position = 1 ; _series.push_back(1) ; }         Triangular( int len=1, int start_position=1 ) ;          void gen_series() ;         int length() { return _length ; }        int begin() { return 0 ; }          int end() { return _length-1 ; }                 private:         static vector<int> _series ;           static const int _max_length = 100 ;         int _length ;          int _start_position ;   } ;  //Inline function should lie in the header file. inline bool Triangular_iterator::operator ==( const Triangular_iterator &rhs ) const {     return _index == rhs._index ;  }  inline bool Triangular_iterator::operator !=( const Triangular_iterator &rhs ) const  {     return _index != rhs._index ;  }  //inline bool Triangular_iterator::operator !=( const Triangular_iterator &rhs ) const  //{ //    return !(*this==rhs) ;  //}inline int Triangular_iterator::operator *() const {     return Triangular::_series[_index] ;  }  inline Triangular_iterator& Triangular_iterator::operator ++() {     ++_index ;      return *this ;  }  inline Triangular_iterator Triangular_iterator::operator ++( int ) {     Triangular_iterator tmp = *this ;      ++_index ;      return tmp ;  }  #endif

4.2 Exercise 4.4

   A user profile consists of a login, the actual user name, the number of times logged on, the number of guesses made, the number of correct guesses, the current level ?one of beginner, intermediate, advanced, or guru and the percentage correct (this latter may be computed or stored). Provide a UserProfile class. Support input and output, equality and inequality. The constructors should allow for a default user level and default login name of "guest." How might you guarantee that each guest login for a particular session is unique? 
Copyright @ Lippman

main.cpp▽

#include "UserProfile.h" #include <iostream>using namespace std ;  int main() {    UserProfile anon;    cout << anon; // test out output operator    UserProfile anon_too; // to see if we get unique id    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; // test out input operator    cout << anon; }

UserProfile.cpp▽

#include "UserProfile.h"#include <iostream> using namespace std ; ostream& operator<<( ostream &os, const UserProfile &rhs ) { // output of the form: 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; } // overkill ... but it allows a demonstration ... 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; } istream& operator>>( istream &is, UserProfile &rhs ) {   // yes, this assumes the input is valid ...     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; }

UserProfile.h▽

#ifndef USER_PROFILE_H #define USER_PROFILE_H #include <cstdlib> #include <string> #include <map>using namespace std ; class UserProfile { public:     enum uLevel { Beginner, Intermediate, Advanced, Guru };     UserProfile( string login, uLevel = Beginner );     UserProfile();     // default memberwise initialization and copy sufficient     // no explicit copy constructor or copy assignment operator     // no destructor necessary ...     bool operator==( const UserProfile& );     bool operator!=( const UserProfile &rhs );     // read access functions     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;     // write access functions     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 ){} inline UserProfile::UserProfile()     : _login( "guest" ), _user_level( Beginner ),       _times_logged( 1 ), _guesses( 0 ), _correct_guesses( 0 ) {    static int id = 0;    char buffer[ 16 ];    // _itoa() is a Standard C library function    // turns an integer into an ascii representation       _itoa( id++, buffer, 10 );    // add a unique id during session to guest login    _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 ]; } inline void UserProfile::reset_level( const string &level ){      map<string,uLevel>::iterator it;      if ( _level_map.empty() )           init_level_map();      // confirm level is a recognized user level ...      _user_level =          (( it = _level_map.find( level )) != _level_map.end() )                ? it->second : Beginner; } ostream& operator<<( ostream &os, const UserProfile &rhs ) ;istream& operator>>( istream &is, UserProfile &rhs ) ;  #endif  //USER_PROFILE_H

4.3 Exercise 4.5

   Implement a 4x4 Matrix class supporting at least the following general interface: addition and multiplication of two Matrix objects, a print() member function, a compound += operator, and subscripting supported through a pair of overloaded function call operators, as follows:
float& operator()( int row, int column ); float  operator()( int row, int column ) const; 
   Provide a default constructor taking an optional 16 data values and a constructor taking an array of 16 elements. You do not need a copy constructor, copy assignment operator, or destructor for this class (these are required in Chapter 6 when we reimplement the Matrix class to support arbitrary rows and columns).
main.cpp
#include <iostream> #include "matrix.h" using namespace std ; 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.cpp
#include <iostream> #include "matrix.h"using namespace std ;           //necessary! ostream& operator <<( ostream &os, const matrix &mat ) {     for( int i=0; i<4 ; ++i )         for( int j=0; j<4; ++j )              os << ( (j==0) ? " \n" : " " ) << mat(i,j) ;              //Ternary conditional expression has a lower precedence, so bracket is needed.      return os ;  }  //matrix operator +( const matrix &m1, const matrix &m2 )  //{ //    matrix result ;  //    for( int i=0; i<4; ++i ) //        for( int j=0; j<4; ++j ) //            result(i,j) = m1(i,j) + m2(i,j) ;             //Note: call elemType& operator() ( int row, int column ) { return _matrix[row][column] ; }//    return result ;  //}  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 i=0; i<4; ++i)         for( int j=0; j<4; ++j)         {             result(i,j) = 0 ;       //!            for( int k=0; k<4; ++k) result(i,j)+=m1(i,k)*m2(k,j) ;      //Note: result(i,j) calls elemType& operator() ( int row, int column ) { return _matrix[row][column] ; }         }     return result ;  }  void matrix::operator +=( const matrix &rhs ) {    for( int i=0; i<4; ++i)         for( int j=0; j<4; ++j)             _matrix[i][j] += rhs(i,j) ;  }
matrix.h
#ifndef MATRIX_H #define MATRIX_H #include <iostream> using namespace std ;   typedef float elemType ;   class matrix {         friend matrix operator +( const matrix&, const matrix& ) ;          friend matrix operator *( const matrix&, const matrix& ) ;      public:         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. ) ;      //default constructor         matrix( const elemType *arr) ;         //void print( matrix & ) const ;         void operator +=( const matrix &rhs ) ;     //It's best to return matrix& in case of a+=a+=a, whiche equals to a+=(a+=a)(if a is initialized to 2, than a = 8 after that.).        elemType& operator() ( int row, int column ) { return _matrix[row][column] ; }           elemType operator() ( int row, int column ) const { return _matrix[row][column] ; }               private:          elemType _matrix[4][4] ;};   ostream& operator <<( ostream &, const matrix& ) ;  //inline elemType& matrix::operator ()( int row, int column ) //{ //    return _matrix[row][column] ;  //} ////inline elemType matrix::operator ()( int row, int column ) const  //{ //    return _matrix[row][column] ;  //}  //inline matrix::matrix( const elemType *arr) //{ //    for( int i=0; i<4; i++) //        for( int j=0; j<4; j++)  //            _matrix[i][j] = arr[i*4+j] ; //*(arr+i*4+j) ;  //} inline matrix::matrix( const elemType *arr) {     int arr_idx = 0 ;     for( int i=0; i<4; ++i)         for( int j=0; j<4; ++j)              _matrix[i][j] = arr[arr_idx++] ; } inline matrix::matrix(  elemType a00, elemType a01, elemType a02, elemType a03,                          elemType a10, elemType a11, elemType a12, elemType a13,                         elemType a20, elemType a21, elemType a22, elemType a23,                         elemType a30, elemType a31, elemType a32, elemType a33 )  {     _matrix[0][0]=a00;_matrix[0][1]=a01;_matrix[0][2]=a02;_matrix[0][3]=a03;    _matrix[1][0]=a10;_matrix[1][1]=a11;_matrix[1][2]=a12;_matrix[1][3]=a13;    _matrix[2][0]=a20;_matrix[2][1]=a21;_matrix[2][2]=a22;_matrix[2][3]=a23;    _matrix[3][0]=a30;_matrix[3][1]=a31;_matrix[3][2]=a32;_matrix[3][3]=a33;}              #endif

5. Chapter 5: Object-Oriented Programming


5.1 Example 5.2: A tour of OOP


main.cpp▽
#include <iostream> #include "tour_of_oop.h" using namespace std ;  void print( const LibMat &mat ) {    cout << "in global print(): about to print mat.print()\n";    // this resolves to a print() member function    //      based on the actual object mat refers to ...    mat.print(); } int main() {     cout << "\n" << "Creating an AudioBook object to print()\n";     AudioBook ab( "Man Without Qualities",                   "Robert Musil", "Kenneth Meyer" );     print( ab );          //magazine mgz("Reader") ;      //print( mgz ) ; }
tour_of_oop.h▽
#ifndef TOUR_OF_OOP_H #define TOUR_OF_OOP_H#include <iostream> using namespace std ; class LibMat { public:    LibMat(){ cout << "LibMat::LibMat() default constructor!\n"; }    virtual ~LibMat(){ cout << "LibMat::~LibMat() destructor!\n"; }    virtual void print() const          { cout << "LibMat::print() -- I am a LibMat object!\n"; } };  class Book : public LibMat { public:    Book( const string &title, const string &author )       : _title( title ), _author( author ){       cout << "Book::Book( " << _title            << ", " << _author << " )  constructor\n";    }    virtual ~Book(){       cout << "Book::~Book() destructor!\n";    }    virtual void print() const {       cout << "Book::print() -- I am a Book object!\n"            << "My title is: "  << _title  << '\n'            << "My author is: " << _author << endl;    }    const string& title()  const { return _title;  }    const string& author() const { return _author; } protected:    string _title;    string _author; };  class AudioBook : public Book { public:    AudioBook( const string &title,              const string &author, const string &narrator )       : Book( title, author ),         _narrator( narrator )    {       cout << "AudioBook::AudioBook( " << _title           << ", " << _author           << ", " << _narrator           << " )  constructor\n";    }    ~AudioBook()                                         // why not virtual ?   {       cout << "AudioBook::~AudioBook() destructor!\n";    }    virtual void print() const {       cout << "AudioBook::print() -- I am an AudioBook object!\n"           // note the direct access of the inherited           // data members _title and _author           << "My title is: "    << _title << '\n'           << "My author is: "   << _author << '\n'           << "My narrator is: " << _narrator << endl;    }    const string& narrator() const { return _narrator; } protected:    string _narrator; }; class magazine : public LibMat {     public:         magazine() { cout << "\nmagazine constructor!\n" ; }         magazine(const string &title) { cout << "magazine constructor!\n" ; _title = title ; }        virtual ~magazine() { cout << "magazine destructor!\n" ; }         virtual void print() const { cout << "\nmagazine:" << _title << endl ; }              protected:         string _title ;  }; #endif

5.2 Exercise 5.1

   Implement a two-level stack hierarchy. The base class is a pure abstract Stack class that minimally supports the following interface: pop(), push(), size(), empty(), full(), peek(), and print(). The two concrete derived classes are LIFO_Stack and Peekback_Stack. The Peekback_Stack allows the user to retrieve the value of any element in the stack without modifying the stack itself.

main.cpp▽

#include "stack.h" ostream& operator<<( ostream &os, const stack &rhs ) {     rhs.print(os) ;      return os ;  } void peek( stack &st, int index )               // using reference to take advantage of polymorphism! {    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;    cout << "Pls input some words(Ctrl+d after completion):\n" ;    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; }

stack.cpp

#include "stack.h"void lifo_stack::print( ostream &os ) const {     vector<type>::const_reverse_iterator rit = _lifo_stack.rbegin() ,                                              end_rit = _lifo_stack.rend() ;      while(rit!=end_rit)     {         os << *rit++ << endl ;      } } void peekback_stack::print( ostream &os ) const {     vector<type>::const_reverse_iterator rit = _peekback_stack.rbegin() ,                                             end_rit = _peekback_stack.rend() ;      while(rit!=end_rit)     {         os << *rit++ << endl ;      } }

stack.h

#ifndef STACK_H #define STACK_H  #include <string> #include <iostream> #include <vector>using namespace std ;  typedef string type ; class stack {     public:         stack() {} ;          virtual ~stack() {}             // !        virtual bool pop( type &val ) = 0 ;           virtual bool push( const type &val ) = 0 ;      // const        virtual int top() const = 0 ;                   // const         virtual int size() const = 0 ;          virtual bool empty() const = 0 ;         virtual bool full() const = 0 ;          virtual bool peek(int &pos, type &val ) = 0 ;          virtual void print( ostream &os = cout ) const = 0 ;      protected:         static const int _capacity = 100 ; } ;  class lifo_stack : public stack {     public:         lifo_stack() { _top = 0 ; }          bool pop( type &val )          {             if( _top == 0 ) return false ;              val = _lifo_stack[--_top] ;              _lifo_stack.pop_back() ;             return true ;         }        bool push( const type &val )          {              if( _top == _capacity ) return false ;              _lifo_stack.push_back(val) ;              _top ++ ;              return true ;         }         int top() const { return _top ; }        int size() const { return _lifo_stack.size() ; }         bool empty() const { return _top == 0 ; }               // or !_top        bool full() const { return _top == _capacity ; }         bool peek( int &pos, type &val ) { return false ; }         void print( ostream &os = cout ) const ;     private:         int _top ;          vector<type> _lifo_stack ; } ;  class peekback_stack : public stack {     public:         peekback_stack() { _top = 0 ; }          bool pop( type &val )          {             if( _top == 0 ) return false ;              val = _peekback_stack[--_top] ;              _peekback_stack.pop_back() ;             return true ;         }        bool push( const type &val )          {               if( _top == _capacity ) return false ;              _peekback_stack.push_back(val) ;              _top ++ ;               return true ;         }         int top() const { return _top ; }        int size() const { return _peekback_stack.size() ; }         bool empty() const { return _top == 0 ; }         bool full() const { return _top == _capacity ; }         bool peek( int &pos, type &val )         {             if(empty())                  return false ;             if( pos<=0 && pos>_top )                  return false ;             val = _peekback_stack[pos] ;              return true ;          }        void print( ostream &os = cout ) const ;     private:         int _top ;          vector<type> _peekback_stack ;} ;  #endif

5.3 Exercise 5.2

Reimplement the class hierarchy of Exercise 5.1 so that the base Stack class implements the shared, type-independent members.
main.cpp
#include "stack.h" ostream& operator<<( ostream &os, const stack &rhs ) {     rhs.print(os) ;      return os ;  } void peek( stack &st, int index )               // using reference to take advantage of polymorphism! {    cout  << endl;    string t;    if ( st.peek( index, t ))         cout << "peek: " << t;    else cout << "peek failed!";    cout << endl; } int main() {    stack st;    string str;    cout << "Pls input some words(Ctrl+d after completion):\n" ;    while ( cin >> str && ! st.full() )            st.push( str );    cout << '\n' << "About to call peek() with 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; }
stack.cpp
#include "stack.h"void stack::print( ostream &os ) const {     vector<type>::const_reverse_iterator rit = _stack.rbegin() ,                                              end_rit = _stack.rend() ;      while(rit!=end_rit)     {         os << *rit++ << endl ;      } }
stack.h
#ifndef STACK_H #define STACK_H  #include <string> #include <iostream> #include <vector>using namespace std ;  typedef string type ; class stack {     public:         stack() { _top = 0 ; }          bool pop( type &val )          {             if( _top == 0 ) return false ;              val = _stack[--_top] ;              _stack.pop_back() ;             return true ;         }        bool push( const type &val )          {              if( _top == _capacity ) return false ;              _stack.push_back(val) ;              _top ++ ;              return true ;         }         int top() const { return _top ; }        int size() const { return _stack.size() ; }         bool empty() const { return _top == 0 ; }               // or !_top        bool full() const { return _top == _capacity ; }         virtual bool peek( int &pos, type &val ) { return false ; }         void print( ostream &os = cout ) const ;     protected:         int _top ;          vector<type> _stack ;         static const int _capacity = 100 ; } ;  class peekback_stack : public stack {     public:         peekback_stack():stack() { }          bool peek( int &pos, type &val )         {             if(empty())                  return false ;             if( pos<=0 && pos>_top )                  return false ;             val = _stack[pos] ;              return true ;          }} ;  #endif

6. Chapter 6: Programming with Templates


6.1 Binary Tree


  • "binary tree" example is very good for pointer, parameter-pass exercise. 
  • Assert the pointer before using it.  
main.cpp
#include "binary_tree.h" #include <iostream> #include <string> using namespace std; int main() {     BinaryTree<string> bt;     bt.insert( "Piglet" );     bt.insert( "Eeyore" );     bt.insert( "Roo" );     bt.insert( "Tigger" );     bt.insert( "Chris" );     bt.insert( "Pooh" );     bt.insert( "Kanga" );     cout << "Preorder traversal: \n";     bt.preorder();     bt.remove( "Piglet" );     cout << "\n\nPreorder traversal after Piglet removal: \n";     bt.preorder();     bt.remove( "Eeyore" );     cout << "\n\nPreorder traversal after Eeyore removal: \n";     bt.preorder();     BinaryTree<int> bti ;      cout << "\nInput some integers, I'll sort them.\n" ;      int ipt ;     while(cin >> ipt) bti.insert(ipt) ;     if(!bti.empty())     {         cout << "\nThey are sorted: " ;          bti.inorder() ;     }    else cout << "\nThe binary tree is empty!\n" ;     return 0; }
binary_tree.h
#ifndef BINARY_TREE_H #define BINARY_TREE_H  #include <iostream> #include <string>using namespace std ;  template <typename elemType> class BinaryTree ;  //<elemType> ;   template <typename valType> class BTnode ;  //<valType>  template <typename valType> class BTnode  {      friend class BinaryTree<valType> ;     public:         BTnode() { _cnt = 0; _lchild = 0; _rchild = 0; }         BTnode(const valType &val):_val(val) { _cnt = 1; _lchild = 0; _rchild = 0; }            //const to align parameter list        void insert_value(const valType &val) ;         void preorder(ostream &os=cout) const ;         void inorder(ostream &os=cout) const ;         void remove_value( const valType &val, BTnode *& _this) ;         static void lchild_leaf(BTnode *lchild, BTnode *subtree) ;     private:         valType _val ;           int _cnt ;         BTnode *_lchild ;          BTnode *_rchild ;  } ;  template <typename elemType> class BinaryTree  {     public:         BinaryTree():_root(0) { }         bool empty() { return !_root ; }        void insert( const elemType &val ) ;          void remove( const elemType &val ) ;         void preorder( ostream &os=cout ) const ;         void inorder( ostream &os=cout ) const ;     private:         BTnode<elemType> *_root ;  } ;  template <typename elemType> inline void BinaryTree<elemType>:: insert( const elemType &val ) {     if(!_root)  _root = new BTnode<elemType>(val) ;      else _root -> insert_value( val ) ;  } template <typename elemType> inline void BinaryTree<elemType>:: preorder ( ostream &os ) const{     if(!_root) os << "The binary tree is empty!\n" ;      else     {         _root -> preorder(os) ;          os << endl ;     } } template <typename elemType> inline void BinaryTree<elemType>:: inorder ( ostream &os ) const{     if(!_root) os << "The binary tree is empty!\n" ;      else     {         _root -> inorder(os) ;          os << endl ;     } }  template <typename elemType> inline void BinaryTree<elemType>:: remove( const elemType &val ) {     if(!_root)     {         cout << "The binary tree is empty!\n";           return ;      }     //if(_root->_val == val)    //{     //    BTnode<elemType> *tmp = _root ;     //    if(!_root->_lchild) _root = _root->_rchild ;      //    else if(!_root->_rchild) _root = _root->_lchild ;      //    else BTnode<elemType>::lchild_leaf(_root->_lchild, _root->_rchild) ;      //    delete tmp ;     //}     //else _root -> remove_value( val ) ;      _root -> remove_value( val, _root ) ;  }  template <typename valType> inline void BTnode<valType>:: lchild_leaf(BTnode *lchild, BTnode *subtree) {     //BTnode *tmp = subtree ;                     //There is no need to define tmp!    //while(tmp->_lchild) tmp = tmp->_lchild ;      //tmp->_lchild = lchild ;      while(subtree->_lchild) subtree = subtree->_lchild ;      subtree->_lchild = lchild ; } template <typename valType> void BTnode<valType>:: insert_value(const valType &val) {     if(val == _val )      {          _cnt ++ ;          return ;      }    if(val < _val)     {         if(!_lchild) _lchild = new BTnode(val);         else _lchild->insert_value(val) ;      }     else      {         if(!_rchild) _rchild = new BTnode(val);          else _rchild->insert_value(val) ;      } }  template <typename valType> void BTnode<valType>:: preorder (ostream &os) const {     if(this != 0)     {         cout << "\t" << _val << '(' << _cnt << ')';          _lchild->preorder(os) ;          _rchild->preorder(os) ;      }} template <typename valType> void BTnode<valType>:: inorder (ostream &os) const {     if(this != 0)     {         _lchild->preorder(os) ;          cout << "\t" << _val << '(' << _cnt << ')' ;          _rchild->preorder(os) ;      }} template <typename valType> void BTnode<valType>:: remove_value(const valType &val, BTnode *& _this) {     if(_val == val)     {         //cout << "this pointer:" << this << "\t_this:" << _this << endl ;         BTnode<valType> *tmp = _this ;         if(!_lchild) _this = _this->_rchild ;          else if(!_rchild) _this = _this->_lchild ;          else          {             _this = _this->_rchild ;             BTnode<valType>::lchild_leaf(_lchild, _rchild) ;         }        delete tmp ;     }     else if(val < _val)     {         if( ! _lchild ) return ;          else _lchild -> remove_value(val, _lchild) ;      }    else      {         if( ! _rchild ) return ;          else _rchild -> remove_value(val, _rchild) ;       }}  //************ You cannot make assignment to the this pointer! ****////template <typename elemType> //inline void BinaryTree<elemType>:: //remove( const elemType &val ) //{ //    if(!_root) //    { //        cout << "The binary tree is empty!\n";   //        return ;  //    } //    //if(_root->_val == val)//    //{ //    //    BTnode<elemType> *tmp = _root ; //    //    if(!_root->_lchild) _root = _root->_rchild ;  //    //    else if(!_root->_rchild) _root = _root->_lchild ;  //    //    else BTnode<elemType>::lchild_leaf(_root->_lchild, _root->_rchild) ;  //    //    delete tmp ; //    //} //    //else _root -> remove_value( val ) ;  //    _root -> remove_value( val ) ;  //} // //template <typename valType> //inline void BTnode<valType>:: //remove_value(const valType &val) //{ //    if(_val == val) //    { //        BTnode<valType> *tmp = this ; //        if(!_lchild) this = this->_rchild ;  //        else if(!_rchild) this = this->_lchild ;  //        else BTnode<valType>::lchild_leaf(_lchild, _rchild) ;//        delete tmp ; //    } //    else if(val < _val) //    { //        if( ! _lchild ) return ;  //        else _lchild -> remove_value(val) ;  //    }//    else  //    { //        if( ! _rchild ) return ;  //        else _rchild -> remove_value(val) ;   //    }//} #endif
undefined_referenced_error_in_template_programming

http://stackoverflow.com/questions/8752837/undefined-reference-to-template-class-constructor
This is a common question in C++ programming. There are two valid answers to this. There are advantages and disadvantages to both answers and your choice will depend on context. The common answer is to put all the implementation in the header file, but there's another approach will will be suitable in some cases. The choice is yours.The code in a template is merely a 'pattern' known to the compiler. The compiler won't compile the constructors cola<float>::cola(...) and cola<string>::cola(...) until it is forced to do so. And we must ensure that this compilation happens for the constructors at least once in the entire compilation process, or we will get the 'undefined reference' error. (This applies to the other methods of cola<T> also.)Understanding the problemThe problem is caused by the fact that main.cpp and cola.cpp will be compiled separately first. In main.cpp, the compiler will implicitly instantiate the template classes cola<float> and cola<string> because those particular instantiations are used in main.cpp. The bad news is that the implementations of those member functions are not in main.cpp, nor in any header file included in main.cpp, and therefore the compiler can't include complete versions of those functions in main.o. When compiling cola.cpp, the compiler won't compile those instantiations either, because there are no implicit or explicit instantiations of cola<float> or cola<string>. Remember, when compiling cola.cpp, the compiler has no clue which instantiations will be needed; and we can't expect it to compile for every type in order to ensure this problem never happens! (cola<int>, cola<char>, cola<ostream>, cola< cola<int> > ... and so on ...)The two answers are:?Tell the compiler, at the end of cola.cpp, which particular template classes will be required, forcing it to compile cola<float> and cola<string>.?Put the implementation of the member functions in a header file that will be included every time any other 'translation unit' (such as main.cpp) uses the template class.Answer 1: Explicitly instantiate the template, and its member definitionsAt the end of cola.cpp, you should add lines explicitly instantiating all the relevant templates, such astemplate class cola<float>;template class cola<string>;and you add the following two lines at the end of nodo_colaypila.cpp:template class nodo_colaypila<float>;template class nodo_colaypila<std :: string>;This will ensure that, when the compiler is compiling cola.cpp that it will explicitly compile all the code for the cola<float> and cola<string> classes. Similarly, nodo_colaypila.cpp contains the implementations of the nodo_colaypila<...> classes.In this approach, you should ensure that all the of the implementation is placed into one .cpp file (i.e. one translation unit) and that the explicit instantation is placed after the definition of all the functions (i.e. at the end of the file).Answer 2: Copy the code into the relevant header fileThe common answer is to move all the code from the implementation files cola.cpp and nodo_colaypila.cpp into cola.h and nodo_colaypila.h. In the long run, this is more flexible as it means you can use extra instantiations (e.g. cola<char>) without any more work. But it could mean the same functions are compiled many times, once in each translation unit. This is not a big problem, as the linker will correctly ignore the duplicate implementations. But it might slow down the compilation a little.SummaryThe default answer, used by the STL for example and in most of the code that any of us will write, is to put all the implementations in the header files. But in a more private project, you will have more knowledge and control of which particular template classes will be instantiated. In fact, this 'bug' might be seen as a feature, as it stops users of your code from accidentally using instantiations you have not tested for or planned for ("I know this works for cola<float> and cola<string>, if you want to use something else, tell me first and will can verify it works before enabling it.").Finally, there are three other minor typos in the code in your question:?You are missing an #endif at the end of nodo_colaypila.h?in cola.h nodo_colaypila<T>* ult, pri; should be nodo_colaypila<T> *ult, *pri; - both are pointers.?nodo_colaypila.cpp: The default parameter should be in the header file nodo_colaypila.h, not in this implementation file.
http://stackoverflow.com/questions/10632251/undefined-reference-to-template-functionThe implementation of a non-specialized template must be visible to a translation unit that uses it.The compiler must be able to see the implementation in order to generate code for all specializations in your code.This can be achieved in two ways:1) Move the implementation inside the header.2) If you want to keep it separate, move it into a different header which you include in your original header:util.hnamespace Util{    template<class T>    QString convert2QString(T type , int digits=0);}#include "util_impl.h"util_impl.hnamespace Util{    template<class T>        QString convert2QString(T type, int digits=0)        {            using std::string;            string temp = (boost::format("%1") % type).str();            return QString::fromStdString(temp);        }}

6.2 const_expressions_and_default_paras

Copyright @ Lippman
/************************************************** * Essential C++ -- Stanley Lippman * Addison-Wesley  * ISBN 0-201-48518-4 * homepage: www.objectwrite.com * email: slippman@objectwrite.com *************************************************/#include <string>#include <vector>#include <utility>#include <iostream>using namespace std;template <int len, int beg_pos> class num_sequence;template <int len, int beg_pos>ostream& operator<<( ostream &os, const num_sequence<len,beg_pos> &ns );template <int len, int beg_pos>class num_sequence {public:    virtual ~num_sequence(){}; int                 elem( int pos ) const;    const char*         what_am_i() const;static  int         max_elems(){ return _max_elems; }ostream&            print( ostream &os = cout ) const; protected:    virtual void        gen_elems( int pos ) const = 0;bool                check_integrity( int pos, int size ) const;num_sequence( vector<int> *pe ) : _pelems( pe ){}// static const int _max_elems = 1024; // ok, but vc++ doesn't acceptenum { _max_elems = 1024 };vector<int>       *_pelems;};template <int len, int beg_pos>ostream& operator<<( ostream &os,  const num_sequence<len,beg_pos> &ns ){      return ns.print( os );}template <int len, int beg_pos>int num_sequence<len,beg_pos>::elem( int pos ) const {    if ( ! check_integrity( pos, _pelems->size() )) return 0;return (*_pelems)[ pos-1 ];}#include <typeinfo>template <int length, int beg_pos>const char* num_sequence<length, beg_pos>::what_am_i() const {    return typeid( *this ).name();}template <int length, int beg_pos>bool num_sequence<length, beg_pos>::check_integrity( int pos, int size ) const{if ( pos <= 0 || pos > max_elems() ){ cerr << "!! invalid position: " << pos  << " Cannot honor request\n"; return false;}if ( pos > size ) gen_elems( pos );return true;}template <int length, int beg_pos>ostream& num_sequence<length, beg_pos>::print( ostream &os ) const{int elem_pos = beg_pos-1;int end_pos = elem_pos + length;    if ( ! check_integrity( end_pos, _pelems->size() )) return os;     os << "( "    << beg_pos << " , "    << length << " ) ";   while ( elem_pos < end_pos )     os << (*_pelems)[ elem_pos++ ] << ' ';return os;}template <int length, int beg_pos=1>class Fibonacci : public num_sequence<length, beg_pos> {public:   Fibonacci() : num_sequence<length,beg_pos>( &_elems ){}          //note: This is constructor's initial listprotected:   virtual void       gen_elems( int pos ) const;           //note: const   static vector<int> _elems;};template <int length, int beg_pos>vector<int> Fibonacci<length,beg_pos>::_elems;template <int length, int beg_pos>void Fibonacci<length,beg_pos>::gen_elems( int pos ) const{   if ( pos <= 0 || pos > max_elems() ) return;    if ( _elems.empty() )       { _elems.push_back( 1 ); _elems.push_back( 1 ); }    if ( _elems.size() < pos ){    int ix = _elems.size();int n_2 = _elems[ ix-2 ], n_1 = _elems[ ix-1 ];int elem;for ( ; ix < pos; ++ix ){    elem = n_2 + n_1; // cout << "gen_elems: " << elem << endl;_elems.push_back( elem );n_2 = n_1; n_1 = elem;} }}  int main(){/*fib1: ( 1 , 8 ) 1 1 2 3 5 8 13 21fib2: ( 8 , 8 ) 21 34 55 89 144 233 377 610fib3: ( 8 , 12 ) 21 34 55 89 144 233 377 610 987 1597 2584 4181*/Fibonacci<8>  fib1;    Fibonacci<8,8> fib2;    Fibonacci<12,8> fib3;cout << "fib1: " << fib1 << '\n'     << "fib2: " << fib2 << '\n' << "fib3: " << fib3 << endl;return 0; // quiets vc++}

6.3 Exercise 6.2

   Reimplement the Matrix class of Exercise 4.3 as a template. In addition, extend it to support arbitrary row and column size using heap memory. Allocate the memory in the constructor and deallocate it in the destructor.
main.cpp
#include <iostream> #include "matrix.h"using namespace std ; int main() {    matrix<float> identity( 4, 4 );    cout << "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++ ];    cout <<  "identity after set: " << identity << endl;    matrix<float> m( identity );    cout << "m: memberwise initialized: " << m << endl;    matrix<float> m2( 8, 12 );    cout << "m2: 8x12: " <<  m2  << endl;    m2 = m;    cout << "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++ ];             //a good method   cout << "m3: assigned random values: " << m3 << endl;    matrix<float> m4 = m3 * identity; cout << m4 << endl;    matrix<float> m5 = m3 + m4; cout << m5 << endl;    m3 += m4; cout << m3 << endl; }
matrix.h
#ifndef MATRIX_H #define MATRIX_H #include <iostream> using namespace std ;   template <typename elemType> class matrix ;  template <typename elemType> matrix<elemType> operator+( const matrix<elemType> &m1, const matrix<elemType> &m2 ) ; template <typename elemType> matrix<elemType> operator*( const matrix<elemType> &m1, const matrix<elemType> &m2 ) ; template <typename elemType> class matrix {     //friend matrix<elemType> operator+( const matrix<elemType> &m1, const matrix<elemType> &m2 ) ;         // for g++ compiler reason    //friend matrix<elemType> operator*( const matrix<elemType> &m1, const matrix<elemType> &m2 ) ;    public:         matrix():_pmatrix(0),_row(0),_column(0) { }         matrix( int row, int column )           :_row(row),_column(column)                // Make sure that objects are initialized before they're used.        {              int elem_cnt = row*column ;             _pmatrix = new elemType[elem_cnt] ;              //for(int i=0;i<elem_cnt;i++) _pmatrix[i] = 0 ;              for(int i=0;i<elem_cnt;i++) _pmatrix[i] = elemType() ;      //note        }        matrix( const matrix & ) ;         ~matrix() { delete [] _pmatrix ; }         matrix& operator=( const matrix & ) ;       //Return matrix& for chain assignment consideration.         matrix& operator+=( const matrix & ) ;      //also         elemType& operator()( int row, int column ) { return _pmatrix[row*_column+column] ; }               // non-const version; note: a const reference object cannot call this function!        const elemType& operator()( int row, int column ) const { return _pmatrix[row*_column+column] ; };  // const version        void print( ostream &os = cout, char delimeter = ' ' ) const ;                  // const is necessary, a const reference object cannot call a non-const function!         //private:                              // for g++ compiler reason        elemType *_pmatrix ;          int _row ;          int _column ; } ;  template <typename elemType> matrix<elemType>::matrix( const matrix &rhs )     :_row(rhs._row),_column(rhs._column){     int elem_cnt = _row*_column ;    _pmatrix = new elemType[elem_cnt] ;      for(int i=0;i<elem_cnt;i++) _pmatrix[i] = rhs._pmatrix[i] ;  } template <typename elemType> matrix<elemType>& matrix<elemType>:: operator=(const matrix &rhs) {     if( this != &rhs )          // avoid assignment to self     {         _row=rhs._row ;          _column=rhs._column ;          int elem_cnt = _row*_column ;        elemType *tmp = _pmatrix ;      //for exception-safe consideration        _pmatrix = new elemType[elem_cnt] ;          for(int i=0;i<elem_cnt;i++) _pmatrix[i] = rhs._pmatrix[i] ;          delete [] tmp ;      }     return *this ;     //if(_row!=rhs._row || _column!=rhs._column)     //{     //    cout << "\nDimension doesn't match!\n" ;       //    return;      //}     //for(int i=0;i<_row;i++)     //    for(int j=0;j<_column;j++)      //    {     //        int k = i*_column + j ;      //        _pmatrix[k] = rhs._pmatrix[k] ;      //    } }  template <typename elemType> matrix<elemType>& matrix<elemType>:: operator +=( const matrix &rhs ) {      if( _row!=rhs._row || _column!=rhs._column )     {         cout << "\nDimensions don't match!\n" ;          return *this;           // return doesn't work    }     int elem_cnt = _row*_column ;      for(int i=0;i<elem_cnt;i++) _pmatrix[i] += rhs._pmatrix[i] ;      return *this ;  }  template <typename elemType> void matrix<elemType>:: print( ostream &os, char delimeter) const {     int elem_cnt = _row*_column ;      for(int i=0;i<elem_cnt;i++)         os << ( (i%_column)?delimeter:'\n' ) << ' ' << _pmatrix[i] ;     os << endl ;  }template <typename elemType> matrix<elemType> operator+( const matrix<elemType> &m1, const matrix<elemType> &m2 ){     //if( m1._row!=m2._row || m1._column!=m2._column )     //{     //    cout << "\nDimensions don't match!\n" ;      //    return ;      //}     //matrix<elemType> result( m1._row, m1._column ) ;     //int elem_cnt = _row*_column ;      //for(int i=0;i<elem_cnt;i++) result._pmatrix[i] = m1._pmatrix[i]+m2._pmatrix[i] ;      //return result ;      matrix<elemType> result( m1 ) ;     // a smarter way     result += m2 ;     return result ;  } template <typename elemType> matrix<elemType> operator*( const matrix<elemType> &m1, const matrix<elemType> &m2 ){     if( m1._column != m2._row )     {         cout << "\nDimensions don't match!\n" ;          return m1;          // how to handle this? just use it for now    }     matrix<elemType> result( m1._row, m2._column ) ;     for(int i=0;i<result._row;i++)          for(int j=0;j<result._column;j++)         {             result(i,j) = 0 ;       // why not elemType() ?            for(int k=0;k<m1._column;k++) result(i,j) += m1(i,k)*m2(k,j) ;          }     return result ;  } template <typename elemType> ostream& operator<<( ostream &os, const matrix<elemType> &mat ) {     mat.print(os) ;     return os ; } #endif

0 0