inline int abs( int obj ) { // возвращает абсолютное значение iobj return( iobj < 0 ? -iobj : iobj ); } inline int min( int p1, int p2 ) { // возвращает меньшую из двух величин return( pi < p2 ? pi : p2 ); } int gcd( int vl, int v2 ) { // возвращает наибольший общий делитель while ( v2 ) { int temp = v2; v2 = vl % v2; vl = temp; } return vl; |
#include int main() { // прочитать значения из стандартного ввода cout << "Введите первое значение: "; int i; cin >> i; if ( !cin ) { cerr << "!? Ошибка ввода - аварийный выход!\n"; return -1; } cout << "Введите второе значение: "; int j; cin >> j; if ( !cin ) { cerr << "!? Ошибка ввода - аварийный выход!\n"; return -2; } cout << "\nmin: " << min( i, j ) << endl; i = abs( i ); j = abs( j ); cout << "НОД: " << gcd( i, j ) << endl; return 0;
| |
int abs( int ); int min( int, int ); |
// определение функции находится в файле gcd.С int gcd( int, int ); inline int abs(int i) { return( i<0 ? -i : i ); } inline int min(int vl.int v2) { return( vl |
#include #include const lineLength =12; // количество элементов в строке void putValues( vector { cout << "( " << vec.size() << " )< "; for ( int i = 0; i < vec.size(); ++1 ) { if ( i % lineLength == 0 && i ) cout << "\n\t"; // строка заполнена cout << vec[ i ]; // разделитель, печатаемый после каждого элемента, // кроме последнего if ( 1 % lineLength != lineLength-1 && i != vec.size()-1 ) cout << ", "; } cout << " >\n";
| |
void putValues( vector int main() { int i, j[ 2 ]; // присвоить i и j некоторые значения vector vecl[0] = i; putValues( vecl ); vector // добавим элементы к vec2 for ( int ix = 0; ix < sizeof( j ) / sizeof( j[0] ); ++ix ) // vec2[ix] == j [ix] vec2.push_back( j[ix] ); putValues( vec2 ); return 0;
| |
count_if( vec.begin(), vec.end(), |
count_if( vec.begin(), vec.end(), |
template < class InputIterator, class Type > Type accumulate( InputIterator first, InputIterator last, Type init ); template < class InputIterator, class Type, class BinaryOperation > Type accumulate( InputIterator first, InputIterator last, |
#include #include #include #include /* * выход: * accumulate() * работает с последовательностью {1,2,3,4} * результат для сложения по умолчанию: 10 * результат для объекта-функции plus */ int main() { int ia[] = { 1, 2, 3, 4 }; list int ia_result = accumulate(&ia[0], &ia[4], 0); int ilist_res = accumulate( ilist.begin(), ilist.end(), 0, plus cout << "accumulate()\n\t" << "работает с последовательностью {1,2,3,4}\n\t" << "результат для сложения по умолчанию: " << ia_result << "\n\t" << "результат для объекта-функции plus << ilist_res << endl; return 0;
| |
template < class InputIterator, class OutputIterator > OutputIterator adjacent_difference( InputIterator first, InputIterator last, OutputIterator result ); template < class InputIterator, class OutputIterator > class BinaryOperation > OutputIterator adjacent_difference( InputIterator first, InputIterator last, |
#include #include #include #include #include int main() { int ia[] = { 1, 1, 2, 3, 5, 8 }; list list adjacent_difference(ilist.begin(), ilist.end(), ilist_result.begin() ); // на выходе печатается: // 1 0 1 1 2 3 copy( ilist_result.begin(), ilist_result.end(), ostream_iterator cout << endl; adjacent_difference(ilist.begin(), ilist.end(), ilist_result.begin(), times // на выходе печатается: // 1 1 2 6 15 40 copy( ilist_result.begin(), ilist_result.end(), ostream_iterator cout << endl;
| |
template < class ForwardIterator > ForwardIterator adjacent_find( ForwardIterator first, ForwardIterator last ); template < class ForwardIterator, class BinaryPredicate > ForwardIterator adjacent_find( ForwardIterator first, |
#include #include #include #include class TwiceOver { public: bool operator() ( int val1, int val2 ) { return val1 == val2/2 ? true : false; } }; int main() { int ia[] = { 1, 4, 4, 8 }; vector< int, allocator > vec( ia, ia+4 ); int *piter; vector< int, allocator >::iterator iter; // piter указывает на ia[1] piter = adjacent_find( ia, ia+4 ); assert( *piter == ia[ 1 ] ); // iter указывает на vec[2] iter = adjacent_find( vec.begin(), vec.end(), TwiceOver() ); assert( *iter == vec[ 2 ] ); // пришли сюда: все хорошо cout << "ok: adjacent-find() завершился успешно!\n"; return 0;
| |
template < class ForwardIterator, class Type > bool binary_search( ForwardIterator first, ForwardIterator last, const Type &value ); template < class ForwardIterator, class Type > bool binary_search( ForwardIterator first, ForwardIterator last, const Type &value, |
#include #include #include int main() { int ia[] = {29,23,20,22,17,15,26,51,19,12,35,40}; vector< int, allocator > vec( ia, ia+12 ); sort( &ia[0], &ia[12] ); bool found_it = binary_search( &ia[0], &ia[12], 18 ); assert( found_it == false ); vector< int > vec( ia, ia+12 ); sort( vec.begin(), vec.end(), greater found_it = binary_search( vec.begin(), vec.end(), 26, greater assert( found_it == true );
| |
template < class BidirectionalIterator1, class BidirectionalIterator2 > BidirectionalIterator2 copy_backward( BidirectionalIterator1 first, BidirectionalIterator1 last1, |
#include #include #include #include class print_elements { public: void operator()( string elem ) { cout << elem << ( _line_cnt++%8 ? " " : "\n\t" ); } static void reset_line_cnt() { _line_cnt = 1; } private: static int _line_cnt; }; int print_elements::_line_cnt = 1; /* печатается: исходный список строк: The light untonsured hair grained and hued like pale oak после copy_backward( begin+1, end-3, end ): The light untonsured hair light untonsured hair grained and hued */ int main() { string sa[] = { "The", "light", "untonsured", "hair", "grained", "and", "hued", "like", "pale", "oak" }; vector< string, allocator > svec( sa, sa+10 ); cout << "исходный список строк:\n\t"; for_each( svec.begin(), svec.end(), print_elements() ); cout << "\n\n"; copy_backward( svec.begin()+1, svec.end()-3, svec.end() ); print_elements::reset_line_cnt(); cout << "после copy_backward( begin+1, end-3, end ):\n"; for_each( svec.begin(), svec.end(), print_elements() ); cout << "\n";
| |
template < class InputIterator, class OutputIterator > OutputIterator copy( InputIterator first1, InputIterator last, |
int ia[] = {0, 1, 2, 3, 4, 5 }; // сдвинуть элементы влево на один, получится {1,2,3,4,5,5} |
#include #include #include #include /* печатается: 0 1 1 3 5 8 13 сдвиг массива влево на 1: 1 1 3 5 8 13 13 сдвиг вектора влево на 2: 1 3 5 8 13 8 13 */ int main() { int ia[] = { 0, 1, 1, 3, 5, 8, 13 }; vector< int, allocator > vec( ia, ia+7 ); ostream_iterator< int > ofile( cout, " " ); cout << "исходная последовательность элементов:\n"; copy( vec.begin(), vec.end(), ofile ); cout << '\n'; // сдвиг влево на один элемент copy( ia+1, ia+7, ia ); cout << "сдвиг массива влево на 1:\n"; copy( ia, ia+7, ofile ); cout << '\n'; // сдвиг влево на два элемента copy( vec.begin()+2, vec.end(), vec.begin() ); cout << "сдвиг вектора влево на 2:\n"; copy( vec.begin(), vec.end(), ofile ); cout << '\n';
| |
template < class InputIterator, class Predicate > iterator_traits count_if( InputIterator first,
| |
#include #include #include class Even { public: bool operator()( int val ) { return val%2 ? false : true; } }; int main() { int ia[] = {0,1,1,2,3,5,8,13,21,34}; list< int,allocator > ilist( ia, ia+10 ); /* * не поддерживается в текущей реализации ***************************************************** typedef iterator_traits distance_type; distance_type ia_count, list_count; // счетчик четных элементов: 4 ia_count = count_if( &ia[0], &ia[10], Even() ); list_count = count_if( ilist.begin(), ilist_end(), bind2nd(less ****************************************************** */ int ia_count = 0; count_if( &ia[0], &ia[10], Even(), ia_count ); // печатается: // count_if(): есть 4 четных элемент(а). cout << "count_if(): есть " << ia_count << " четных элемент(а).\n"; int list_count = 0; count_if( ilist.begin(), ilist.end(), bind2nd(less // печатается: // count_if(): есть 7 элемент(ов), меньших 10. cout << "count_if(): есть " << list_count << " элемент(ов), меньших 10.\n";
| |
template < class InputIterator, class Type > iterator_traits count( InputIterator first,
| |
#include #include #include #include #include #include #include /*********************************************************************** * прочитанный текст: Alice Emma has long flowing red hair. Her Daddy says when the wind blows through her hair, it looks almost alive, like a fiery bird in flight. A beautiful fiery bird, he tells her, magical but untamed. "Daddy, shush, there is no such thing," she tells him, at the same time wanting him to tell her more. Shyly, she asks, "I mean, Daddy, is there?" ************************************************************************ * программа выводит: * count(): fiery встречается 2 раз(а) ************************************************************************ */ int main() { ifstream infile( "alice_emma" ); assert ( infile != 0 ); list typedef list istream_iterator< string, diff_type > instream( infile ), eos; copy( instream, eos, back_inserter( textlines )); string search_item( "fiery" ); /********************************************************************* * примечание: ниже показан интерфейс count(), принятый в * стандартной библиотеке. В текущей реализации библиотеки * от RogueWave поддерживается более ранняя версия, в которой * типа distance_type еще не было, так что count() * возвращала результат в последнем аргументе * * вот как должен выглядеть вызов: * * typedef iterator_traits * distance_type dis_type; * * dis_type elem_count; * elem_count = count( textlines.begin(), textlines.end(), * search_item ); *********************************************************************** int elem_count = 0; list ibegin = textlines.begin(), iend = textlines.end(); // устаревшая форма count() count( ibegin, iend, search_item, elem_count ); cout << "count(): " << search_item << " встречается " << elem_count << " раз(а)\n";
| |
template< class ForwardIterator, class Type > pair< ForwardIterator, ForwardIterator > equal_range( ForwardIterator first, ForwardIterator last, const Type &value ); template< class ForwardIterator, class Type, class Compare > pair< ForwardIterator, ForwardIterator > equal_range( ForwardIterator first, ForwardIterator last, const Type &value, |
#include #include #include #include /* печатается: последовательность элементов массива после сортировки: 12 15 17 19 20 22 23 26 29 35 40 51 результат equal_range при поиске значения 23: *ia_iter.first: 23 *ia_iter.second: 26 результат equal_range при поиске отсутствующего значения 21: *ia_iter.first: 22 *ia_iter.second: 22 последовательность элементов вектора после сортировки: 51 40 35 29 26 23 22 20 19 17 15 12 результат equal_range при поиске значения 26: *ivec_iter.first: 26 *ivec_iter.second: 23 результат equal_range при поиске отсутствующего значения 21: *ivec_iter.first: 20 *ivec_iter.second: 20 */ int main() { int ia[] = { 29,23,20,22,17,15,26,51,19,12,35,40 }; vector< int, allocator > ivec( ia, ia+12 ); ostream_iterator< int > ofile( cout, " " ); sort( &ia[0], &ia[12] ); cout << "последовательность элементов массива после сортировки:\n"; copy( ia, ia+12, ofile ); cout << "\n\n"; pair< int*,int* > ia_iter; ia_iter = equal_range( &ia[0], &ia[12], 23 ); cout << "результат equal_range при поиске значения 23:\n\t" << "*ia_iter.first: " << *ia_iter.first << "\t" << "*ia_iter.second: " << *ia_iter.second << "\n\n"; ia_iter = equal_range( &ia[0], &ia[12], 21 ); cout << "результат equal_range при поиске " << "отсутствующего значения 21:\n\t" << "*ia_iter.first: " << *ia_iter.first << "\t" << "*ia_iter.second: " << *ia_iter.second << "\n\n"; sort( ivec.begin(), ivec.end(), greater cout << "последовательность элементов вектора после сортировки:\n"; copy( ivec.begin(), ivec.end(), ofile ); cout << "\n\n"; typedef vector< int, allocator >::iterator iter_ivec; pair< iter_ivec, iter_ivec > ivec_iter; ivec_iter = equal_range( ivec.begin(), ivec.end(), 26, greater cout << "результат equal_range при поиске значения 26:\n\t" << "*ivec_iter.first: " << *ivec_iter.first << "\t" << "*ivec_iter.second: " << *ivec_iter.second << "\n\n"; ivec_iter = equal_range( ivec.begin(), ivec.end(), 21, greater cout << "результат equal_range при поиске отсутствующего значения 21:\n\t" << "*ivec_iter.first: " << *ivec_iter.first << "\t" << "*ivec_iter.second: " << *ivec_iter.second << "\n\n";
| |
template< class InputIterator1, class InputIterator2 > bool equal( InputIterator1 first1, InputIterator1 last, InputIterator2 first2 ); template< class InputIterator1, class InputIterator2, class BinaryPredicate > bool equal( InputIterator1 first1, InputIterator1 last, |
if ( vec1.size() == vec2.size() && |
#include #include #include class equal_and_odd{ public: bool operator()( int val1, int val2 ) { return ( val1 == val2 && ( val1 == 0 || val1 % 2 )) ? true : false; } }; int main() { int ia[] = { 0,1,1,2,3,5,8,13 }; int ia2[] = { 0,1,1,2,3,5,8,13,21,34 }; bool res; // true: обе последовательности совпадают до длины ia // печатается: int ia[7] равно int ia2[9]? Да. res = equal( &ia[0], &ia[7], &ia2[0] ); cout << "int ia[7] равно int ia2[9]? " << ( res ? "Да" : "Нет" ) << ".\n"; list< int, allocator > ilist( ia, ia+7 ); list< int, allocator > ilist2( ia2, ia2+9 ); // печатается: список ilist равен ilist2? Да. res = equal( ilist.begin(), ilist.end(), ilist2.begin() ); cout << "список ilist равен ilist2? " << ( res ? "Да" : "Нет" ) << ".\n"; // false: 0, 2, 8 не являются равными и нечетными // печатается: список ilist equal_and_odd() ilist2? Нет. res = equal( ilist.begin(), ilist.end(), ilist2.begin(), equal_and_odd() ); cout << "список ilist equal_and_odd() ilist2? " << ( res ? "Да" : "Нет" ) << ".\n"; return 0;
| |
template< class ForwardIterator, class Size, class Type > void fill_n( ForwardIterator first, |
#include #include #include #include class print_elements { public: void operator()( string elem ) { cout << elem << ( _line_cnt++%8 ? " " : "\n\t" ); } static void reset_line_cnt() { _line_cnt = 1; } private: static int _line_cnt; }; int print_elements::_line_cnt = 1; /* печатается: исходная последовательность элементов массива: 0 1 1 2 3 5 8 массив после fill_n( ia+2, 3, 9 ): 0 1 9 9 9 5 8 исходная последовательность строк: Stephen closed his eyes to hear his boots crush crackling wrack and shells последовательность после применения fill_n(): Stephen closed his xxxxx xxxxx xxxxx xxxxx xxxxx xxxxx crackling wrack and shells */ int main() { int value = 9; int count = 3; int ia[] = { 0, 1, 1, 2, 3, 5, 8 }; ostream_iterator< int > iofile( cout, " " ); cout << "исходная последовательность элементов массива:\n"; copy( ia, ia+7, iofile ); cout << "\n\n"; fill_n( ia+2, count, value ); cout << "массив после fill_n( ia+2, 3, 9 ):\n"; copy( ia, ia+7, iofile ); cout << "\n\n"; string replacement( "xxxxx" ); string sa[] = { "Stephen", "closed", "his", "eyes", "to", "hear", "his", "boots", "crush", "crackling", "wrack", "and", "shells" }; vector< string, allocator > svec( sa, sa+13 ); cout << "исходная последовательность строк:\n\t"; for_each( svec.begin(), svec.end(), print_elements() ); cout << "\n\n"; fill_n( svec.begin()+3, count*2, replacement ); print_elements::reset_line_cnt(); cout << "последовательность после применения fill_n():\n\t"; for_each( svec.begin(), svec.end(), print_elements() ); cout << "\n";
| |
template< class ForwardIterator, class Type > void fill( ForwardIterator first, |
#include #include #include #include /* печатается: исходная последовательность элементов массива: 0 1 1 2 3 5 8 массив после fill(ia+1,ia+6): 0 9 9 9 9 9 8 исходная последовательность элементов списка: c eiffel java ada perl список после fill(++ibegin,--iend): c c++ c++ c++ perl */ int main() { const int value = 9; int ia[] = { 0, 1, 1, 2, 3, 5, 8 }; ostream_iterator< int > ofile( cout, " " ); cout << "исходная последовательность элементов массива:\n"; copy( ia, ia+7, ofile ); cout << "\n\n"; fill( ia+1, ia+6, value ); cout << "массив после fill(ia+1,ia+6):\n"; copy( ia, ia+7, ofile ); cout << "\n\n"; string the_lang( "c++" ); string langs[5] = { "c", "eiffel", "java", "ada", "perl" }; list< string, allocator > il( langs, langs+5 ); ostream_iterator< string > sofile( cout, " " ); cout << "исходная последовательность элементов списка:\n"; copy( il.begin(), il.end(), sofile ); cout << "\n\n"; typedef list iterator ibegin = il.begin(), iend = il.end(); fill( ++ibegin, --iend, the_lang ); cout << "список после fill(++ibegin,--iend):\n"; copy( il.begin(), il.end(), sofile ); cout << "\n\n";
| |
template< class ForwardIterator1, class ForwardIterator2 > ForwardIterator1 find_end( ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2, ForwardIterator2 last2 ); template< class ForwardIterator1, class ForwardIterator2, class BinaryPredicate > ForwardIterator1 find_end( ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2, ForwardIterator2 last2, |
#include #include #include #include int main() { int array[ 17 ] = { 7,3,3,7,6,5,8,7,2,1,3,7,6,3,8,4,3 }; int subarray[ 3 ] = { 3, 7, 6 }; int *found_it; // find найти последнее вхождение последовательности 3,7,6 // в массив и вернуть адрес первого ее элемента ... found_it = find_end( &array[0], &array[17], &subarray[0], &subarray[3] ); assert( found_it == &array[10] ); vector< int, allocator > ivec( array, array+17 ); vector< int, allocator > subvec( subarray, subarray+3 ); vector< int, allocator >::iterator found_it2; found_it2 = find_end( ivec.begin(), ivec.end(), subvec.begin(), subvec.end(), equal_to assert( found_it2 == ivec.begin()+10 ); cout << "ok: find_end правильно вернула начало " << "последнего вхождения последовательности: 3,7,6!\n";
| |
template< class ForwardIterator1, class ForwardIterator2 > ForwardIterator1 find_first_of( ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2, ForwardIterator2 last2 ); template< class ForwardIterator1, class ForwardIterator2, class BinaryPredicate > ForwardIterator1 find_first_of( ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2, ForwardIterator2 last2, |
#include #include #include #include int main() { string s_array[] = { "Ee", "eE", "ee", "Oo", "oo", "ee" }; // возвращает первое вхождение "ee" -- &s_array[2] string to_find[] = { "oo", "gg", "ee" }; string *found_it = find_first_of( s_array, s_array+6, to_find, to_find+3 ); // печатается: // найдено: ee // &s_array[2]: 0x7fff2dac // &found_it: 0x7fff2dac if ( found_it != &s_array[6] ) cout << "найдено: " << *found_it << "\n\t" << "&s_array[2]:\t" << &s_array[2] << "\n\t" << "&found_it:\t" << found_it << "\n\n"; vector< string, allocator > svec( s_array, s_array+6); vector< string, allocator > svec_find( to_find, to_find+2 ); // возвращает вхождение "oo" -- svec.end()-2 vector< string, allocator >::iterator found_it2; found_it2 = find_first_of( svec.begin(), svec.end(), svec_find.begin(), svec_find.end(), equal_to // печатает: // тоже найдено: oo // &svec.end()-2: 0x100067b0 // &found_it2: 0x100067b0 if ( found_it2 != svec.end() ) cout << "тоже найдено: " << *found_it2 << "\n\t" << "&svec.end()-2:\t" << svec.end()-2 << "\n\t" << "&found_it2:\t" << found_it2 << "\n";
| |
template< class InputIterator, class Predicate > InputIterator find_if( InputIterator first, |
#include #include #include #include #include // альтернатива оператору равенства // возвращает true, если строка содержится в объекте-члене FriendSet class OurFriends { // наши друзья public: bool operator()( const string& str ) { return ( friendset.count( str )); } static void FriendSet( const string *fs, int count ) { copy( fs, fs+count, inserter( friendset, friendset.end() )); } private: static set< string, less }; set< string, less int main() { string Pooh_friends[] = { "Пятачок", "Тигра", "Иа-Иа" }; string more_friends[] = { "Квазимодо", "Чип", "Пятачок" }; list // заполнить список друзей Пуха OurFriends::FriendSet( Pooh_friends, 3 ); list our_mutual_friend = find_if( lf.begin(), lf.end(), OurFriends()); // печатается: // Представьте-ка, наш друг Пятачок - также друг Пуха. if ( our_mutual_friend != lf.end() ) cout << "Представьте-ка, наш друг " << *our_mutual_friend << " также друг Пуха.\n"; return 0;
| |
template< class InputIterator, class T > InputIterator find( InputIterator first, |
#include #include #include #include int main() { int array[ 17 ] = { 7,3,3,7,6,5,8,7,2,1,3,8,7,3,8,4,3 }; int elem = array[ 9 ]; int *found_it; found_it = find( &array[0], &array[17], elem ); // печатается: поиск первого вхождения 1 найдено! cout << "поиск первого вхождения " << elem << "\t" << ( found_it ? "найдено!\n" : "не найдено!\n" ); string beethoven[] = { "Sonata31", "Sonata32", "Quartet14", "Quartet15", "Archduke", "Symphony7" }; string s_elem( beethoven[ 1 ] ); list< string, allocator > slist( beethoven, beethoven+6 ); list< string, allocator >::iterator iter; iter = find( slist.begin(), slist.end(), s_elem ); // печатается: поиск первого вхождения Sonata32 найдено! cout << "поиск первого вхождения " << s_elem << "\t" << ( found_it ? "найдено!\n" : "не найдено!\n" );
| |
template< class InputIterator, class Function > Function for_each( InputIterator first, |
#include #include #include template void print_elements( Type elem ) { cout << elem << " "; } int main() { vector< int, allocator > ivec; for ( int ix = 0; ix < 10; ix++ ) ivec.push_back( ix ); void (*pfi)( int ) = print_elements; for_each( ivec.begin(), ivec.end(), pfi ); return 0;
| |
template< class OutputIterator, class Size, class Generator > void |
#include #include #include class even_by_twos { public: even_by_twos( int seed = 0 ) : _seed( seed ){} int operator()() { return _seed += 2; } private: int _seed; }; template void print_elements( Type elem ) { cout << elem << " "; } int main() { list< int, allocator > ilist( 10 ); void (*pfi)( int ) = print_elements; generate_n( ilist.begin(), ilist.size(), even_by_twos() ); // печатается: // generate_n с even_by_twos(): // 2 4 6 8 10 12 14 16 18 20 cout << "generate_n с even_by_twos():\n"; for_each( ilist.begin(), ilist.end(), pfi ); cout << "\n"; generate_n( ilist.begin(), ilist.size(), even_by_twos( 100 ) ); // печатается: // generate_n с even_by_twos( 100 ): // 102 104 106 108 110 112 114 116 118 120 cout << "generate_n с even_by_twos( 100 ):\n"; for_each( ilist.begin(), ilist.end(), pfi );
| |
template< class ForwardIterator, class Generator > void generate( ForwardIterator first, |
#include #include #include int odd_by_twos() { static int seed = -1; return seed += 2; } template void print_elements( Type elem ) { cout << elem << " "; } int main() { list< int, allocator > ilist( 10 ); void (*pfi)( int ) = print_elements; generate( ilist.begin(), ilist.end(), odd_by_twos ); // печатается: // элементы в списке, первый вызов: // 1 3 5 7 9 11 13 15 17 19 cout << "элементы в списке, первый вызов:\n"; for_each( ilist.begin(), ilist.end(), pfi ); generate( ilist.begin(), ilist.end(), odd_by_twos ); // печатается: // элементы в списке, второй вызов: // 21 23 25 27 29 31 33 35 37 39 cout << "\n\nэлементы в списке, второй вызов:\n"; for_each( ilist.begin(), ilist.end(), pfi ); return 0;
| |
template< class InputIterator1, class InputIterator2 > bool includes( InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2 ); template< class InputIterator1, class InputIterator2, class Compare > bool includes( InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, |
#include #include #include int main() { int ia1[] = { 13, 1, 21, 2, 0, 34, 5, 1, 8, 3, 21, 34 }; int ia2[] = { 21, 2, 8, 3, 5, 1 }; // алгоритму includes следует передавать отсортированные контейнеры sort( ia1, ia1+12 ); sort( ia2, ia2+6 ); // печатает: каждый элемент ia2 входит в ia1? Да bool res = includes( ia1, ia1+12, ia2, ia2+6 ); cout << "каждый элемент ia2 входит в ia1? " << (res ? "Да" : "Нет") << endl; vector< int, allocator > ivect1( ia1, ia1+12 ); vector< int, allocator > ivect2( ia2, ia2+6 ); // отсортирован в порядке убывания sort( ivect1.begin(), ivect1.end(), greater sort( ivect2.begin(), ivect2.end(), greater res = includes( ivect1.begin(), ivect1.end(), ivect2.begin(), ivect2.end(), greater // печатает: каждый элемент ivect2 входит в ivect1? Да cout << "каждый элемент ivect2 входит в ivect1? " << (res ? "Да" : "Нет") << endl;
| |
template< class InputIterator1, class InputIterator2 class Type > Type inner_product( InputIterator1 first1, InputIterator1 last, InputIterator2 first2, Type init ); template< class InputIterator1, class InputIterator2 class Type, class BinaryOperation1, class BinaryOperation2 > Type inner_product( InputIterator1 first1, InputIterator1 last, InputIterator2 first2, Type init, |
#include #include #include int main() { int ia[] = { 2, 3, 5, 8 }; int ia2[] = { 1, 2, 3, 4 }; // перемножить пары элементов из обоих массивов, // сложить и добавить начальное значение: 0 int res = inner_product( &ia[0], &ia[4], &ia2[0], 0 ); // печатает: скалярное произведение массивов: 55 cout << "скалярное произведение массивов: " << res << endl; vector vector // сложить пары элементов из обоих векторов, // вычесть из начального значения: 0 res = inner_product( vec.begin(), vec.end(), vec2.begin(), 0, minus // печатает: скалярное произведение векторов: -28 cout << "скалярное произведение векторов: " << res << endl; return 0;
| |
template< class BidirectionalIterator > void inplace_merge( BidirectionalIterator first, BidirectionalIterator middle, BidirectionalIterator last ); template< class BidirectionalIterator, class Compare > void inplace_merge( BidirectionalIterator first, BidirectionalIterator middle, |
#include #include #include template void print_elements( Type elem ) { cout << elem << " "; } /* * печатает: ia разбит на два отсортированных подмассива: 12 15 17 20 23 26 29 35 40 51 10 16 21 41 44 54 62 65 71 74 ia inplace_merge: 10 12 15 16 17 20 21 23 26 29 35 40 41 44 51 54 62 65 71 74 ivec разбит на два отсортированных подвектора: 51 40 35 29 26 23 20 17 15 12 74 71 65 62 54 44 41 21 16 10 ivec inplace_merge: 74 71 65 62 54 51 44 41 40 35 29 26 23 21 20 17 16 15 12 10 */ int main() { int ia[] = { 29,23,20,17,15,26,51,12,35,40, 74,16,54,21,44,62,10,41,65,71 }; vector< int, allocator > ivec( ia, ia+20 ); void (*pfi)( int ) = print_elements; // отсортировать обе подпоследовательности sort( &ia[0], &ia[10] ); sort( &ia[10], &ia[20] ); cout << "ia разбит на два отсортированных подмассива: \n"; for_each( ia, ia+20, pfi ); cout << "\n\n"; inplace_merge( ia, ia+10, ia+20 ); cout << "ia inplace_merge:\n"; for_each( ia, ia+20, pfi ); cout << "\n\n"; sort( ivec.begin(), ivec.begin()+10, greater sort( ivec.begin()+10, ivec.end(), greater cout << "ivec разбит на два отсортированных подвектора: \n"; for_each( ivec.begin(), ivec.end(), pfi ); cout << "\n\n"; inplace_merge( ivec.begin(), ivec.begin()+10, ivec.end(), greater cout << "ivec inplace_merge:\n"; for_each( ivec.begin(), ivec.end(), pfi ); cout << endl;
| |
template< class ForwardIterator1, class ForwardIterator2 > void |
#include #include #include int main() { int ia[] = { 5, 4, 3, 2, 1, 0 }; list< int,allocator > ilist( ia, ia+6 ); typedef list< int, allocator >::iterator iterator; iterator iter1 = ilist.begin(),iter2, iter_end = ilist.end(); // отсортировать список "пузырьком" ... for ( ; iter1 != iter_end; ++iter1 ) for ( iter2 = iter1; iter2 != iter_end; ++iter2 ) if ( *iter2 < *iter1 ) iter_swap( iter1, iter2 ); // печатается: // ilist после сортировки "пузырьком" с помощью iter_swap(): // { 0 1 2 3 4 5 } cout << "ilist после сортировки "пузырьком" с помощью iter_swap(): { "; for ( iter1 = ilist.begin(); iter1 != iter_end; ++iter1 ) cout << *iter1 << " "; cout << "}\n"; return 0;
| |
template< class InputIterator1, class InputIterator2 > bool lexicographical_compare( InputIterator1 first1, InputIterator1 last1, InputIterator1 first2, InputIterator2 last2 ); template< class InputIterator1, class InputIterator2, class Compare > bool lexicographical_compare( InputIterator1 first1, InputIterator1 last1, InputIterator1 first2, InputIterator2 last2, |
string arr1[] = { "Piglet", "Pooh", "Tigger" }; |
#include #include #include #include #include аааааааааа class size_compare { public: аааааааааа bool operator()( const string &a, const string &b ) { аааааааааа аааа return a.length() <= b.length(); аааааааааа } }; аааааааааа int main() { аааааааааа string arr1[] = { "Piglet", "Pooh", "Tigger" }; аааааааааа string arr2[] = { "Piglet", "Pooch", "Eeyore" }; ааааааааааааааааа аааааааааа bool res; ааааааааааааааааа аааааааааа // эр тЄюЁюь ¤ыхьхэЄх яюыєўрхь false аааааааааа // Pooch ьхэ№°х Pooh аааааааааа // эр ЄЁхЄ№хь ¤ыхьхэЄх Єюцх яюыєўшыш сv false аааааааааа res = lexicographical_compare( arr1, arr1+3, ааааааааааааааааааааааааааааааааааа arr2, arr2+3 ); аааааааааа assert( res == false ); ааааааааааааааааа аааааааааа // яюыєўрхь true: фышэр ърцфюую ¤ыхьхэЄр ilist2 аааааааааа // ьхэ№°х ышсю Ёртэр фышэх ёююЄтхЄёЄтхээюую аааааааааа // ¤ыхьхэЄр ilist1 аааааааааа list< string, allocator > ilist1( arr1, arr1+3 ); аааааааааа list< string, allocator > ilist2( arr2, arr2+3 ); ааааааааааааааааа аааааааааа res = lexicographical_compare( аааааааааа аааааааа ilist1.begin(), ilist1.end(), аааааааааа аааааааа ilist2.begin(), ilist2.end(), size_compare() ); ааааааааааааааааа аааааааааа assert( res == true ); аааааааааа аааааааааа cout << "ok: lexicographical_compare чртхЁ°шыё єёях°эю!\n"; |
template< class ForwardIterator, class Type > ForwardIterator lower_bound( ForwardIterator first, ForwardIterator last, const Type &value ); template< class ForwardIterator, class Type, class Compare > ForwardIterator lower_bound( ForwardIterator first, ForwardIterator last, const Type &value, |
#include #include #include int main() { int ia[] = {29,23,20,22,17,15,26,51,19,12,35,40}; sort( &ia[0], &ia[12] ); int search_value = 18; int *ptr = lower_bound( ia, ia+12, search_value ); // печатается: // Первый элемент, перед которым можно вставить 18, - это 19 // Предыдущее значение равно 17 cout << "Первый элемент, перед которым можно вставить " << search_value << ", – это " << *ptr << endl << "Предыдущее значение равно " << *(ptr-1) << endl; vector< int, allocator > ivec( ia, ia+12 ); // отсортировать в порядке возрастания ... sort( ivec.begin(), ivec.end(), greater search_value = 26; vector< int, allocator >::iterator iter; // необходимо указать, как именно // осуществлялась сортировка ... iter = lower_bound( ivec.begin(), ivec.end(), search_value, greater // печатается: // Первый элемент, перед которым можно вставить 26, - это 26 // Предыдущее значение равно 29 cout << "Первый элемент, перед которым можно вставить " << search_value << ", - это " << *iter << endl << "Предыдущее значение равно " << *(iter-1) << endl; return 0;
| |
template< class RandomAccessIterator > void make_heap( RandomAccessIterator first, RandomAccessIterator last ); template< class RandomAccessIterator, class Compare > void make_heap( RandomAccessIterator first, |
template< class ForwardIterator > ForwardIterator max_element( ForwardIterator first, ForwardIterator last ); template< class ForwardIterator, class Compare > ForwardIterator max_element( ForwardIterator first, |
template< class Type > const Type& max( const Type &aval, const Type &bval ); template< class Type, class Compare > const Type& |
template< class InputIterator1, class InputIterator2, class OutputIterator > OutputIterator merge( InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, OutputIterator result ); template< class InputIterator1, class InputIterator2, class OutputIterator, class Compare > OutputIterator merge( InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, |
#include #include #include #include #include template void print_elements( Type elem ) { cout << elem << " "; } void (*pfi)( int ) = print_elements; int main() { int ia[] = {29,23,20,22,17,15,26,51,19,12,35,40}; int ia2[] = {74,16,39,54,21,44,62,10,27,41,65,71}; vector< int, allocator > vec1( ia, ia +12 ), vec2( ia2, ia2+12 ); int ia_result[24]; vector< int, allocator > vec_result(vec1.size()+vec2.size()); sort( ia, ia +12 ); sort( ia2, ia2+12 ); // печатается: // 10 12 15 16 17 19 20 21 22 23 26 27 29 35 // 39 40 41 44 51 54 62 65 71 74 merge( ia, ia+12, ia2, ia2+12, ia_result ); for_each( ia_result, ia_result+24, pfi ); cout << "\n\n"; sort( vec1.begin(), vec1.end(), greater sort( vec2.begin(), vec2.end(), greater merge( vec1.begin(), vec1.end(), vec2.begin(), vec2.end(), vec_result.begin(), greater // печатается: 74 71 65 62 54 51 44 41 40 39 35 29 27 26 23 22 // 21 20 19 17 16 15 12 10 for_each( vec_result.begin(), vec_result.end(), pfi ); cout << "\n\n";
| |
template< class ForwardIterator > ForwardIterator min_element( ForwardIterator first, ForwardIterator last ); template< class ForwardIterator, class Compare > ForwardIterator min_element( ForwardIterator first, |
// иллюстрирует max(), min(), max_element(), min_element() #include #include #include int main() { int ia[] = { 7, 5, 2, 4, 3 }; const vector< int, allocator > ivec( ia, ia+5 ); int mval = max( max( max( max(ivec[4],ivec[3]), ivec[2]),ivec[1]),ivec[0]); // вывод: результат вложенных вызовов max() равен: 7 cout << "результат вложенных вызовов max() равен: " << mval << endl; mval = min( min( min( min(ivec[4],ivec[3]), ivec[2]),ivec[1]),ivec[0]); // вывод: результат вложенных вызовов min() равен: 2 cout << "результат вложенных вызовов min() равен: " << mval << endl; vector< int, allocator >::const_iterator iter; iter = max_element( ivec.begin(), ivec.end() ); // вывод: результат вложенных вызовов max_element() также равен: 7 cout << "результат вложенных вызовов max_element() также равен: " << *iter << endl; iter = min_element( ivec.begin(), ivec.end() ); // вывод: результат вложенных вызовов min_element() также равен: 2 cout << "результат вложенных вызовов min_element() также равен: " << *iter << endl;
| |
template< class Type > const Type& min( const Type &aval, const Type &bval ); template< class Type, class Compare > const Type& |
template< class InputIterator1, class InputIterator2 > pair mismatch( InputIterator1 first, InputIterator1 last, InputIterator2 first2 ); template< class InputIterator1, class InputIterator2, class BinaryPredicate > pair mismatch( InputIterator1 first, InputIterator1 last,
| |
#include #include #include #include class equal_and_odd{ public: bool operator()( int ival1, int ival2 ) { // оба значения равны друг другу? // оба равны нулю? оба нечетны? return ( ival1 == ival2 && ( ival1 == 0 || ival1%2 )); } }; int main() { int ia[] = { 0,1,1,2,3,5,8,13 }; int ia2[] = { 0,1,1,2,4,6,10 }; pair // печатается: первая пара неодинаковых: ia: 3 и ia2: 4 cout << "первая пара неодинаковых: ia: " << *pair_ia.first << " и ia2: " << *pair_ia.second << endl; list list typedef list pair mismatch( ilist.begin(), ilist.end(), ilist2.begin(), equal_and_odd() ); // печатается: первая пара неодинаковых: либо не равны, либо не нечетны: // ilist: 2 и ilist2: 2 cout << "первая пара неодинаковых: либо не равны, " << "либо не нечетны: \n\tilist: " << *pair_ilist.first << " и ilist2: " << *pair_ilist.second << endl;
| |
template < class BidirectionalIterator > bool next_permutation( BidirectionalIterator first, BidirectionalIterator last ); template < class BidirectionalIterator, class Compare > bool next_permutation( BidirectionalIterator first, |
#include #include #include void print_char( char elem ) { cout << elem ; } void (*ppc)( char ) = print_char; /* печатается: ilmsu ilmus ilsmu ilsum ilums ilusm imlsu imlus imslu imsul imuls imusl islmu islum ismlu ismul isulm isuml iulms iulsm iumls iumsl iuslm iusml limsu limus lismu lisum liums liusm lmisu lmius lmsiu lmsui lmuis lmusi lsimu lsium lsmiu lsmui lsuim lsumi luims luism lumis lumsi lusim lusmi milsu milus mislu misul miuls miusl mlisu mlius mlsiu mlsui mluis mlusi msilu msiul msliu mslui msuil msuli muils muisl mulis mulsi musil musli silmu silum simlu simul siulm siuml slimu slium slmiu slmui sluim slumi smilu smiul smliu smlui smuil smuli suilm suiml sulim sulmi sumil sumli uilms uilsm uimls uimsl uislm uisml ulims ulism ulmis ulmsi ulsim ulsmi umils umisl umlis umlsi umsil umsli usilm usiml uslim uslmi usmil usmli */ int main() { vector // последовательность символов: musil vec[0] = 'm'; vec[1] = 'u'; vec[2] = 's'; vec[3] = 'i'; vec[4] = 'l'; int cnt = 2; sort( vec.begin(), vec.end() ); for_each( vec.begin(), vec.end(), ppc ); cout << "\t"; // генерируются все перестановки строки "musil" while( next_permutation( vec.begin(), vec.end())) { for_each( vec.begin(), vec.end(), ppc ); cout << "\t"; if ( ! ( cnt++ % 8 )) { cout << "\n"; cnt = 1; } } cout << "\n\n"; return 0;
| |
template < class RandomAccessIterator > void nth_element( RandomAccessIterator first, RandomAccessIterator nth, RandomAccessIterator last ); template < class RandomAccessIterator, class Compare > void nth_element( RandomAccessIterator first, RandomAccessIterator nth, |
#include #include #include /* печатается: исходный вектор: 29 23 20 22 17 15 26 51 19 12 35 40 вектор, отсортированный относительно элемента 26 12 15 17 19 20 22 23 26 51 29 35 40 вектор, отсортированный по убыванию относительно элемента 23 40 35 29 51 26 23 22 20 19 17 15 12 */ int main() { int ia[] = {29,23,20,22,17,15,26,51,19,12,35,40}; vector< int,allocator > vec( ia, ia+12 ); ostream_iterator cout << "исходный вектор: "; copy( vec.begin(), vec.end(), out ); cout << endl; cout << "вектор, отсортированный относительно элемента " << *( vec.begin()+6 ) << endl; nth_element( vec.begin(), vec.begin()+6, vec.end() ); copy( vec.begin(), vec.end(), out ); cout << endl; cout << " вектор, отсортированный по убыванию " << "относительно элемента " << *( vec.begin()+6 ) << endl; nth_element( vec.begin(), vec.begin()+6, vec.end(), greater copy( vec.begin(), vec.end(), out ); cout << endl;
| |
template < class InputIterator, class RandomAccessIterator > RandomAccessIterator partial_sort_copy( InputIterator first, InputIterator last, RandomAccessIterator result_first, RandomAccessIterator result_last ); template < class InputIterator, class RandomAccessIterator, class Compare > RandomAccessIterator partial_sort_copy( InputIterator first, InputIterator last, RandomAccessIterator result_first, RandomAccessIterator result_last, |
int ia[] = {29,23,20,22,17,15,26,51,19,12,35,40}; |
partial_sort_copy( &ia[0], &ia[7], &ia[12], |
#include #include #include /* * печатается: исходный вектор: 69 23 80 42 17 15 26 51 19 12 35 8 результат применения partial_sort() к вектору: семь элементов 8 12 15 17 19 23 26 80 69 51 42 35 результат применения partial_sort_copy() к первым семи элементам вектора в порядке убывания 26 23 19 17 15 12 8 */ int main() { int ia[] = { 69,23,80,42,17,15,26,51,19,12,35,8 }; vector< int,allocator > vec( ia, ia+12 ); ostream_iterator cout << "исходный вектор: "; copy( vec.begin(), vec.end(), out ); cout << endl; cout << "результат применения partial_sort() к вектору: " << "семь элементов \n"; partial_sort( vec.begin(), vec.begin()+7, vec.end() ); copy( vec.begin(), vec.end(), out ); cout << endl; vector< int, allocator > res(7); cout << " результат применения partial_sort_copy() к первым семи \n\t" << "элементам вектора в порядке убывания \n"; partial_sort_copy( vec.begin(), vec.begin()+7, res.begin(), res.end(), greater copy( res.begin(), res.end(), out ); cout << endl;
| |
template < class RandomAccessIterator > void partial_sort( RandomAccessIterator first, RandomAccessIterator middle, RandomAccessIterator last ); template < class RandomAccessIterator, class Compare > void partial_sort( RandomAccessIterator first, RandomAccessIterator middle, |
template < class InputIterator, class OutputIterator > OutputIterator partial_sum( InputIterator first, InputIterator last, OutputIterator result ); template < class InputIterator, class OutputIterator, class BinaryOperation > OutputIterator partial_sum( InputIterator first, InputIterator last, |
#include #include #include /* * печатается: элементы: 1 3 4 5 7 8 9 частичная сумма элементов: 1 4 8 13 20 28 37 частичная сумма элементов с использованием times 1 3 12 60 420 3360 30240 */ int main() { const int ia_size = 7; int ia[ ia_size ] = { 1, 3, 4, 5, 7, 8, 9 }; int ia_res[ ia_size ]; ostream_iterator< int > outfile( cout, " " ); vector< int, allocator > vec( ia, ia+ia_size ); vector< int, allocator > vec_res( vec.size() ); cout << "элементы: "; copy( ia, ia+ia_size, outfile ); cout << endl; cout << "частичная сумма элементов:\n"; partial_sum( ia, ia+ia_size, ia_res ); copy( ia_res, ia_res+ia_size, outfile ); cout << endl; cout << "частичная сумма элементов с использованием times partial_sum( vec.begin(), vec.end(), vec_res.begin(), times copy( vec_res.begin(), vec_res.end(), outfile ); cout << endl;
| |
template < class BidirectionalIterator, class UnaryPredicate > BidirectionalIterator partition( BidirectionalIterator first, |
#include #include #include class even_elem { public: bool operator()( int elem ) { return elem%2 ? false : true; } }; /* * печатается: исходная последовательность: 29 23 20 22 17 15 26 51 19 12 35 40 разбиение, основанное на четности элементов: 40 12 20 22 26 15 17 51 19 23 35 29 разбиение, основанное на сравнении с 25: 12 23 20 22 17 15 19 51 26 29 35 40 */ int main() { const int ia_size = 12; int ia[ia_size] = { 29,23,20,22,17,15,26,51,19,12,35,40 }; vector< int, allocator > vec( ia, ia+ia_size ); ostream_iterator< int > outfile( cout, " " ); cout << "исходная последовательность: \n"; copy( vec.begin(), vec.end(), outfile ); cout << endl; cout << "разбиение, основанное на четности элементов:\n"; partition( &ia[0], &ia[ia_size], even_elem() ); copy( ia, ia+ia_size, outfile ); cout << endl; cout << "разбиение, основанное на сравнении с 25:\n"; partition( vec.begin(), vec.end(), bind2nd(less copy( vec.begin(), vec.end(), outfile ); cout << endl;
| |
template< class RandomAccessIterator > void pop_heap( RandomAccessIterator first, RandomAccessIterator last ); template< class RandomAccessIterator, class Compare > void pop_heap( RandomAccessIterator first, |
template < class BidirectionalIterator > bool prev_permutation( BidirectionalIterator first, BidirectionalIterator last ); template < class BidirectionalIterator, class Compare > bool prev_permutation( BidirectionalIterator first, |
#include #include #include // печатается: n d a n a d d n a d a n a n d a d n int main() { vector< char, allocator > vec( 3 ); ostream_iterator< char > out_stream( cout, " " ); vec[0] = 'n'; vec[1] = 'd'; vec[2] = 'a'; copy( vec.begin(), vec.end(), out_stream ); cout << "\t"; // сгенерировать все перестановки "dan" while( prev_permutation( vec.begin(), vec.end() )) { copy( vec.begin(), vec.end(), out_stream ); cout << "\t"; } cout << "\n\n";
| |
template< class RandomAccessIterator > void push_heap( RandomAccessIterator first, RandomAccessIterator last ); template< class RandomAccessIterator, class Compare > void push_heap( RandomAccessIterator first, |
template < class RandomAccessIterator > void random_shuffle( RandomAccessIterator first, RandomAccessIterator last ); template < class RandomAccessIterator, class RandomNumberGenerator > void random_shuffle( RandomAccessIterator first, RandomAccessIterator last, |
#include #include #include int main() { vector< int, allocator > vec; for ( int ix = 0; ix < 20; ix++ ) vec.push_back( ix ); random_shuffle( vec.begin(), vec.end() ); // печатает: // random_shuffle для последовательности 1 .. 20: // 6 11 9 2 18 12 17 7 0 15 4 8 10 5 1 19 13 3 14 16 cout << "random_shuffle для последовательности 1 .. 20:\n"; copy( vec.begin(), vec.end(), ostream_iterator< int >( cout," " ));
| |
template< class InputIterator, class OutputIterator, class Predicate > OutputIterator remove_copy_if( InputIterator first, InputIterator last, |
#include #include #include /* печатается: исходная последовательность: 0 1 1 2 3 5 8 13 21 34 последовательность после применения remove_if < 10: 13 21 34 последовательность после применения remove_copy_if четное: 1 1 3 5 13 21 */ class EvenValue { public: bool operator()( int value ) { return value % 2 ? false : true; } }; int main() { int ia[] = { 0, 1, 1, 2, 3, 5, 8, 13, 21, 34 }; vector< int, allocator >::iterator iter; vector< int, allocator > vec( ia, ia+10 ); ostream_iterator< int > ofile( cout, " " ); cout << "исходная последовательность:\n"; copy( vec.begin(), vec.end(), ofile ); cout << '\n'; iter = remove_if( vec.begin(), vec.end(), bind2nd(less vec.erase( iter, vec.end() ); cout << "последовательность после применения remove_if < 10:\n"; copy( vec.begin(), vec.end(), ofile ); cout << '\n'; vector< int, allocator > vec_res( 10 ); iter = remove_copy_if( ia, ia+10, vec_res.begin(), EvenValue() ); cout << "последовательность после применения remove_copy_if четное:\n"; copy( vec_res.begin(), iter, ofile ); cout << '\n';
| |
template< class InputIterator, class OutputIterator, class Type > OutputIterator remove_copy( InputIterator first, InputIterator last, |
#include #include #include #include /* печатается: исходный вектор: 0 1 0 2 0 3 0 4 0 5 вектор после remove до erase(): 1 2 3 4 5 3 0 4 0 5 вектор после erase(): 1 2 3 4 5 массив после remove_copy() 1 2 3 4 5 */ int main() { int value = 0; int ia[] = { 0, 1, 0, 2, 0, 3, 0, 4, 0, 5 }; vector< int, allocator > vec( ia, ia+10 ); ostream_iterator< int > ofile( cout," "); vector< int, allocator >::iterator vec_iter; cout << "исходный вектор:\n"; copy( vec.begin(), vec.end(), ofile ); cout << '\n'; vec_iter = remove( vec.begin(), vec.end(), value ); cout << "вектор после remove до erase():\n"; copy( vec.begin(), vec.end(), ofile ); cout << '\n'; // удалить из контейнера неподходящие элементы vec.erase( vec_iter, vec.end() ); cout << "вектор после erase():\n"; copy( vec.begin(), vec.end(), ofile ); cout << '\n'; int ia2[5]; vector< int, allocator > vec2( ia, ia+10 ); remove_copy( vec2.begin(), vec2.end(), ia2, value ); cout << "массив после remove_copy():\n"; copy( ia2, ia2+5, ofile ); cout << endl;
| |
template< class ForwardIterator, class Predicate > ForwardIterator remove_if( ForwardIterator first, |
template< class ForwardIterator, class Type > ForwardIterator remove( ForwardIterator first, |
template< class ForwardIterator, class OutputIterator, class Predicate, class Type > OutputIterator replace_copy_if( ForwardIterator first, ForwardIterator last, class OutputIterator result, |
#include #include #include /* исходная последовательность: 0 1 1 2 3 5 8 13 21 34 последовательность после применения replace_if < 10 с заменой на 0: 0 0 0 0 0 0 0 13 21 34 последовательность после применения replace_if четное с заменой на 0: 0 1 1 0 3 5 0 13 21 0 */ class EvenValue { public: bool operator()( int value ) { return value % 2 ? false : true; } }; int main() { int new_value = 0; int ia[] = { 0, 1, 1, 2, 3, 5, 8, 13, 21, 34 }; vector< int, allocator > vec( ia, ia+10 ); ostream_iterator< int > ofile( cout, " " ); cout << "исходная последовательность:\n"; copy( ia, ia+10, ofile ); cout << '\n'; replace_if( &ia[0], &ia[10], bind2nd(less cout << "последовательность после применения replace_if < 10 " << "с заменой на 0:\n"; copy( ia, ia+10, ofile ); cout << '\n'; replace_if( vec.begin(), vec.end(), EvenValue(), new_value ); cout << "последовательность после применения replace_if четное" << "с заменой на 0:\n"; copy( vec.begin(), vec.end(), ofile ); cout << '\n';
| |
template< class InputIterator, class InputIterator, class Type > OutputIterator replace_copy( InputIterator first, InputIterator last, class OutputIterator result, |
#include #include #include /* печатается: исходная последовательность: Christopher Robin Mr. Winnie the Pooh Piglet Tigger Eeyore последовательность после применения replace(): Christopher Robin Pooh Piglet Tigger Eeyore */ int main() { string oldval( "Mr. Winnie the Pooh" ); string newval( "Pooh" ); ostream_iterator< string > ofile( cout, " " ); string sa[] = { "Christopher Robin", "Mr. Winnie the Pooh", "Piglet", "Tigger", "Eeyore" }; vector< string, allocator > vec( sa, sa+5 ); cout << "исходная последовательность:\n"; copy( vec.begin(), vec.end(), ofile ); cout << '\n'; replace( vec.begin(), vec.end(), oldval, newval ); cout << "последовательность после применения replace():\n"; copy( vec.begin(), vec.end(), ofile ); cout << '\n'; vector< string, allocator > vec2; replace_copy( vec.begin(), vec.end(), inserter( vec2, vec2.begin() ), newval, oldval ); cout << "последовательность после применения replace_copy():\n"; copy( vec.begin(), vec.end(), ofile ); cout << '\n';
| |
template< class ForwardIterator, class Predicate, class Type > void replace_if( ForwardIterator first, ForwardIterator last, |
template< class ForwardIterator, class Type > void replace( ForwardIterator first, ForwardIterator last, |
template< class BidirectionalIterator, class OutputIterator > OutputIterator reverse_copy( BidirectionalIterator first, |
#include #include #include #include /* печатается: Исходная последовательность строк: Signature of all things I am here to read seaspawn and seawrack that rusty boot Последовательность строк после применения reverse(): boot rusty that seawrack and seaspawn read to here am I things all of Signature */ class print_elements { public: void operator()( string elem ) { cout << elem << ( _line_cnt++%8 ? " " : "\n\t" ); } static void reset_line_cnt() { _line_cnt = 1; } private: static int _line_cnt; }; int print_elements::_line_cnt = 1; int main() { string sa[] = { "Signature", "of", "all", "things", "I", "am", "here", "to", "read", "seaspawn", "and", "seawrack", "that", "rusty", "boot" }; list< string, allocator > slist( sa, sa+15 ); cout << "Исходная последовательность строк:\n\t"; for_each( slist.begin(), slist.end(), print_elements() ); cout << "\n\n"; reverse( slist.begin(), slist.end() ); print_elements::reset_line_cnt(); cout << "Последовательность строк после применения reverse():\n\t"; for_each( slist.begin(), slist.end(), print_elements() ); cout << "\n"; list< string, allocator > slist_copy( slist.size() ); reverse_copy( slist.begin(), slist.end(), slist_copy.begin() );
| |
template< class BidirectionalIterator > void reverse( BidirectionalIterator first, |
template< class ForwardIterator, class OutputIterator > OutputIterator rotate_copy( ForwardIterator first, ForwardIterator middle, |
#include #include #include /* печатается: исходная последовательность: 1 3 5 7 9 0 2 4 6 8 10 вращение вокруг среднего элемента(0) :: 0 2 4 6 8 10 1 3 5 7 9 вращение вокруг предпоследнего элемента(8) :: 8 10 1 3 5 7 9 0 2 4 6 rotate_copy вокруг среднего элемента :: 7 9 0 2 4 6 8 10 1 3 5 */ int main() { int ia[] = { 1, 3, 5, 7, 9, 0, 2, 4, 6, 8, 10 }; vector< int, allocator > vec( ia, ia+11 ); ostream_iterator< int > ofile( cout, " " ); cout << "исходная последовательность:\n"; copy( vec.begin(), vec.end(), ofile ); cout << '\n'; rotate( &ia[0], &ia[5], &ia[11] ); cout << "вращение вокруг среднего элемента(0) ::\n"; copy( ia, ia+11, ofile ); cout << '\n'; rotate( vec.begin(), vec.end()-2, vec.end() ); cout << "вращение вокруг предпоследнего элемента(8) ::\n"; copy( vec.begin(), vec.end(), ofile ); cout << '\n'; vector< int, allocator > vec_res( vec.size() ); rotate_copy( vec.begin(), vec.begin()+vec.size()/2, vec.end(), vec_res.begin() ); cout << "rotate_copy вокруг среднего элемента ::\n"; copy( vec_res.begin(), vec_res.end(), ofile ); cout << '\n';
| |
template< class ForwardIterator > void rotate( ForwardIterator first, |
template< class ForwardIterator, class Size, class Type > ForwardIterator search_n( ForwardIterator first, ForwardIterator last, Size count, const Type &value ); template< class ForwardIterator, class Size, class Type, class BinaryPredicate > ForwardIterator search_n( ForwardIterator first, ForwardIterator last, |
#include #include #include /* печатается: Ожидаем найти два вхождения 'o': o o Ожидаем найти подстроку 'mou': m o u */ int main() { ostream_iterator< char > ofile( cout, " " ); const char blank = ' '; const char oh = 'o'; char str[ 26 ] = "oh my a mouse ate a moose"; char *found_str = search_n( str, str+25, 2, oh ); cout << "Ожидаем найти два вхождения 'o': "; copy( found_str, found_str+2, ofile ); cout << '\n'; vector< char, allocator > vec( str, str+25 ); // найти первую последовательность из трех символов, // ни один из которых не равен пробелу: mou of mouse vector< char, allocator >::iterator iter; iter = search_n( vec.begin(), vec.end(), 3, blank, not_equal_to< char >() ); cout << "Ожидаем найти подстроку 'mou': "; copy( iter, iter+3, ofile ); cout << '\n';
| |
template< class ForwardIterator1, class ForwardIterator2 > ForwardIterator search( ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2, ForwardIterator2 last2 ); template< class ForwardIterator1, class ForwardIterator2, class BinaryPredicate > ForwardIterator search( ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2, ForwardIterator2 last2, |
#include #include #include /* печатается: Ожидаем найти подстроку 'ate': a t e Ожидаем найти подстроку 'vat': v a t */ int main() { ostream_iterator< char > ofile( cout, " " ); char str[ 25 ] = "a fine and private place"; char substr[] = "ate"; char *found_str = search(str,str+25,substr,substr+3); cout << "Ожидаем найти подстроку 'ate': "; copy( found_str, found_str+3, ofile ); cout << '\n'; vector< char, allocator > vec( str, str+24 ); vector< char, allocator > subvec(3); subvec[0]='v'; subvec[1]='a'; subvec[2]='t'; vector< char, allocator >::iterator iter; iter = search( vec.begin(), vec.end(), subvec.begin(), subvec.end(), equal_to< char >() ); cout << "Ожидаем найти подстроку 'vat': "; copy( iter, iter+3, ofile ); cout << '\n';
| |
template< class InputIterator1, class InputIterator2, class OutputIterator > OutputIterator set_difference( InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, OutputIterator result ); template< class InputIterator1, class InputIterator2, class OutputIterator, class Compare > OutputIterator set_difference( InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, |
template< class InputIterator1, class InputIterator2, class OutputIterator > OutputIterator set_intersection( InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, OutputIterator result ); template< class InputIterator1, class InputIterator2, class OutputIterator, class Compare > OutputIterator set_intersection( InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, |
template< class InputIterator1, class InputIterator2, class OutputIterator > OutputIterator set_symmetric_difference( InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, OutputIterator result ); template< class InputIterator1, class InputIterator2, class OutputIterator, class Compare > OutputIterator set_symmetric_difference( InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, |
template< class InputIterator1, class InputIterator2, class OutputIterator > OutputIterator set_union(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, OutputIterator result ); template< class InputIterator1, class InputIterator2, class OutputIterator, class Compare > OutputIterator set_union(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, |
#include #include #include #include /* печатается: элементы множества #1: Иа-Иа Пух Пятачок Тигра элементы множества #2: Бука Пух Слонопотам элементы set_union(): Бука Иа-Иа Пух Пятачок Слонопотам Тигра элементы set_intersection(): Пух элементы set_difference(): Иа-Иа Пятачок Тигра элементы_symmetric_difference(): Бука Иа-Иа Пятачок Слонопотам Тигра */ int main() { string str1[] = { "Пух", "Пятачок", "Тигра", "Иа-Иа" }; string str2[] = { "Пух", "Слонопотам", "Бука" }; ostream_iterator< string > ofile( cout, " " ); set set cout << "элементы множества #1:\n\t"; copy( set1.begin(), set1.end(), ofile ); cout << "\n\n"; cout << "элементы множества #2:\n\t"; copy( set2.begin(), set2.end(), ofile ); cout << "\n\n"; set set_union( set1.begin(), set1.end(), set2.begin(), set2.end(), inserter( res, res.begin() )); cout << "элементы set_union():\n\t"; copy( res.begin(), res.end(), ofile ); cout << "\n\n"; res.clear(); set_intersection( set1.begin(), set1.end(), set2.begin(), set2.end(), inserter( res, res.begin() )); cout << "элементы set_intersection():\n\t"; copy( res.begin(), res.end(), ofile ); cout << "\n\n"; res.clear(); set_difference( set1.begin(), set1.end(), set2.begin(), set2.end(), inserter( res, res.begin() )); cout << "элементы set_difference():\n\t"; copy( res.begin(), res.end(), ofile ); cout << "\n\n"; res.clear(); set_symmetric_difference( set1.begin(), set1.end(), set2.begin(), set2.end(), inserter( res, res.begin() )); cout << "элементы set_symmetric_difference():\n\t"; copy( res.begin(), res.end(), ofile ); cout << "\n\n";
| |
template< class RandomAccessIterator > void sort_heap( RandomAccessIterator first, RandomAccessIterator last ); template< class RandomAccessIterator, class Compare > void sort_heap( RandomAccessIterator first, |
#include #include #include template void print_elements( Type elem ) { cout << elem << " "; } int main() { int ia[] = { 29,23,20,22,17,15,26,51,19,12,35,40 }; vector< int, allocator > vec( ia, ia+12 ); // печатается: 51 35 40 23 29 20 26 22 19 12 17 15 make_heap( &ia[0], &ia[12] ); void (*pfi)( int ) = print_elements; for_each( ia, ia+12, pfi ); cout << "\n\n"; // печатается: 12 17 15 19 23 20 26 51 22 29 35 40 // минимальный хип: в корне наименьший элемент make_heap( vec.begin(), vec.end(), greater for_each( vec.begin(), vec.end(), pfi ); cout << "\n\n"; // печатается: 12 15 17 19 20 22 23 26 29 35 40 51 sort_heap( ia, ia+12 ); for_each( ia, ia+12, pfi ); cout << "\n\n"; // добавим новый наименьший элемент vec.push_back( 8 ); // печатается: 8 17 12 19 23 15 26 51 22 29 35 40 20 // новый наименьший элемент должен оказаться в корне push_heap( vec.begin(), vec.end(), greater for_each( vec.begin(), vec.end(), pfi ); cout << "\n\n"; // печатается: 12 17 15 19 23 20 26 51 22 29 35 40 8 // наименьший элемент должен быть заменен на следующий по порядку pop_heap( vec.begin(), vec.end(), greater for_each( vec.begin(), vec.end(), pfi ); cout << "\n\n";
| |
template< class RandomAccessIterator > void sort( RandomAccessIterator first, RandomAccessIterator last ); template< class RandomAccessIterator, class Compare > void sort( RandomAccessIterator first, |
template< class BidirectionalIterator, class Predicate > BidirectionalIterator stable_partition( BidirectionalIterator first, BidirectionalIterator last, |
#include #include #include /* печатается: исходная последовательность: 29 23 20 22 17 15 26 51 19 12 35 40 устойчивое разбиение по четным элементам: 20 22 26 12 40 29 23 17 15 51 19 устойчивое разбиение по элементам, меньшим 25: 23 20 22 17 15 19 12 29 26 51 35 40 */ class even_elem { public: bool operator()( int elem ) { return elem%2 ? false : true; } }; int main() { int ia[] = { 29,23,20,22,17,15,26,51,19,12,35,40 }; vector< int, allocator > vec( ia, ia+12 ); ostream_iterator< int > ofile( cout, " " ); cout << "исходная последовательность:\n"; copy( vec.begin(), vec.end(), ofile ); cout << '\n'; stable_partition( &ia[0], &ia[12], even_elem() ); cout << "устойчивое разбиение по четным элементам:\n"; copy( ia, ia+11, ofile ); cout << '\n'; stable_partition( vec.begin(), vec.end(), bind2nd(less cout << "устойчивое разбиение по элементам, меньшим 25:\n"; copy( vec.begin(), vec.end(), ofile ); cout << '\n';
| |
template< class RandomAccessIterator > void stable_sort( RandomAccessIterator first, RandomAccessIterator last ); template< class RandomAccessIterator, class Compare > void stable_sort( RandomAccessIterator first, |
#include #include #include /* печатается: исходная последовательность: 29 23 20 22 12 17 15 26 51 19 12 23 35 40 устойчивая сортировка - по умолчанию в порядке возрастания: 12 12 15 17 19 20 22 23 23 26 29 35 40 51 устойчивая сортировка: в порядке убывания: 51 40 35 29 26 23 23 22 20 19 17 15 12 12 */ int main() { int ia[] = { 29,23,20,22,12,17,15,26,51,19,12,23,35,40 }; vector< int, allocator > vec( ia, ia+14 ); ostream_iterator< int > ofile( cout, " " ); cout << "исходная последовательность:\n"; copy( vec.begin(), vec.end(), ofile ); cout << '\n'; stable_sort( &ia[0], &ia[14] ); cout << "устойчивая сортировка - по умолчанию " << "в порядке возрастания:\n"; copy( ia, ia+14, ofile ); cout << '\n'; stable_sort( vec.begin(), vec.end(), greater cout << "устойчивая сортировка: в порядке убывания:\n"; copy( vec.begin(), vec.end(), ofile ); cout << '\n';
| |
template< class ForwardIterator1, class ForwardIterator2 > ForwardIterator2 swap_ranges( ForwardIterator1 first1, ForwardIterator1 last, |
#include #include #include /* печатается: исходная последовательность элементов первого контейнера: 0 1 2 3 4 5 6 7 8 9 исходная последовательность элементов второго контейнера: 5 6 7 8 9 массив после перестановки двух половин: 5 6 7 8 9 0 1 2 3 4 первый контейнер после перестановки двух векторов: 5 6 7 8 9 5 6 7 8 9 второй контейнер после перестановки двух векторов: 0 1 2 3 4 */ int main() { int ia[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; int ia2[] = { 5, 6, 7, 8, 9 }; vector< int, allocator > vec( ia, ia+10 ); vector< int, allocator > vec2( ia2, ia2+5 ); ostream_iterator< int > ofile( cout, " " ); cout << "исходная последовательность элементов первого контейнера:\n"; copy( vec.begin(), vec.end(), ofile ); cout << '\n'; cout << "исходная последовательность элементов второго контейнера:\n"; copy( vec2.begin(), vec2.end(), ofile ); cout << '\n'; // перестановка внутри одного контейнера swap_ranges( &ia[0], &ia[5], &ia[5] ); cout << "массив после перестановки двух половин:\n"; copy( ia, ia+10, ofile ); cout << '\n'; // перестановка разных контейнеров vector< int, allocator >::iterator last = find( vec.begin(), vec.end(), 5 ); swap_ranges( vec.begin(), last, vec2.begin() ); cout << "первый контейнер после перестановки двух векторов:\n"; copy( vec.begin(), vec.end(), ofile ); cout << '\n'; cout << "второй контейнер после перестановки двух векторов:\n"; copy( vec2.begin(), vec2.end(), ofile ); cout << '\n';
| |
template< class Type > void |
#include #include #include /* печатается: исходная последовательность: 3 4 5 0 1 2 после применения swap() в процедуре пузырьковой сортировки: 0 1 2 3 4 5 */ int main() { int ia[] = { 3, 4, 5, 0, 1, 2 }; vector< int, allocator > vec( ia, ia+6 ); for ( int ix = 0; ix < 6; ++ix ) for ( int iy = ix; iy < 6; ++iy ) { if ( vec[iy] < vec[ ix ] ) swap( vec[iy], vec[ix] ); } ostream_iterator< int > ofile( cout, " " ); cout << "исходная последовательность:\n"; copy( ia, ia+6, ofile ); cout << '\n'; cout << "после применения swap() в процедуре " << "пузырьковой сортировки:\n"; copy( vec.begin(), vec.end(), ofile ); cout << '\n';
| |
template< class InputIterator, class OutputIterator, class UnaryOperation > OutputIterator transform( InputIterator first, InputIterator last, OutputIterator result, UnaryOperation op ); template< class InputIterator1, class InputIterator2, class OutputIterator, class BinaryOperation > OutputIterator transform( InputIterator1 first1, InputIterator1 last, InputIterator2 first2, OutputIterator result, |
#include #include #include #include /* * печатается: исходный массив: 3 5 8 13 21 преобразование элементов путем удваивания: 6 10 16 26 42 преобразование элементов путем взятия разности: 3 5 8 13 21 */ int double_val( int val ) { return val + val; } int difference( int val1, int val2 ) { return abs( val1 - val2 ); } int main() { int ia[] = { 3, 5, 8, 13, 21 }; vector ostream_iterator cout << "исходный массив: "; copy( ia, ia+5, outfile ); cout << endl; cout << "преобразование элементов путем удваивания: "; transform( ia, ia+5, vec.begin(), double_val ); copy( vec.begin(), vec.end(), outfile ); cout << endl; cout << "преобразование элементов путем взятия разности: "; transform( ia, ia+5, vec.begin(), outfile, difference ); cout << endl;
| |
template< class InputIterator, class OutputIterator > OutputIterator unique_copy( InputIterator first, InputIterator last, OutputIterator result ); template< class InputIterator, class OutputIterator, class BinaryPredicate > OutputIterator unique_copy( InputIterator first, InputIterator last, |
#include #include #include #include #include template void print_elements( Type elem ) { cout << elem << " "; } void (*pfi)( int ) = print_elements; void (*pfs)( string ) = print_elements; int main() { int ia[] = { 0, 1, 0, 2, 0, 3, 0, 4, 0, 5 }; vector vector // последовательность не изменяется: нули не стоят рядом // печатается: 0 1 0 2 0 3 0 4 0 5 vec_iter = unique( vec.begin(), vec.end() ); for_each( vec.begin(), vec.end(), pfi ); cout << "\n\n"; // отсортировать вектор, затем применить unique: модифицируется // печатается: 0 1 2 3 4 5 2 3 4 5 sort( vec.begin(), vec.end() ); vec_iter = unique( vec.begin(), vec.end() ); for_each( vec.begin(), vec.end(), pfi ); cout << "\n\n"; // удалить из контейнера ненужные элементы // печатается: 0 1 2 3 4 5 vec.erase( vec_iter, vec.end() ); for_each( vec.begin(), vec.end(), pfi ); cout << "\n\n"; string sa[] = { "enough", "is", "enough", "enough", "is", "good" }; vector vector vector sort( svec.begin(), svec.end() ); svec_iter = unique_copy( svec.begin(), svec.end(), vec_result.begin() ); // печатается: enough good is for_each( vec_result.begin(), svec_iter, pfs ); cout << "\n\n";
| |
template< class ForwardIterator > ForwardIterator unique( ForwardIterator first, ForwardIterator last ); template< class ForwardIterator, class BinaryPredicate > ForwardIterator unique( ForwardIterator first, |
template< class ForwardIterator, class Type > ForwardIterator upper_bound( ForwardIterator first, ForwardIterator last, const Type &value ); template< class ForwardIterator, class Type, class Compare > ForwardIterator upper_bound( ForwardIterator first, ForwardIterator last, const Type &value, |
#include #include #include #include template void print_elements( Type elem ) { cout << elem << " "; } void (*pfi)( int ) = print_elements; int main() { int ia[] = {29,23,20,22,17,15,26,51,19,12,35,40}; vector sort(ia,ia+12); int *iter = upper_bound(ia,ia+12,19); assert( *iter == 20 ); sort( vec.begin(), vec.end(), greater vector iter_vec = upper_bound( vec.begin(), vec.end(), 27, greater assert( *iter_vec == 26 ); // печатается: 51 40 35 29 27 26 23 22 20 19 17 15 12 vec.insert( iter_vec, 27 ); for_each( vec.begin(), vec.end(), pfi ); cout << "\n\n";
| |
adjacent_find(), binary_search(), count(),count_if(), equal_range(), find(), find_end(), find_first_of(), find_if(), lower_bound(), |
set_union(), set_intersection(), set_difference(), |
inplace_merge(), merge(), nth_element(), partial_sort(), partial_sort_copy(), partition(), random_shuffle(), reverse(), reverse_copy(), rotate(), rotate_copy(), sort(), stable_sort(), |
equal(), includes(), lexicographical_compare(), max(), max_element(), |
copy(), copy_backwards(), iter_swap(), remove(), remove_copy(), remove_if(),remove_if_copy(), replace(), replace_copy(), replace_if(), replace_copy_if(), swap(), swap_range(), unique(), |
![]() |
![]() |


| class BinaryQuery : public Query { public: const Query *lop() { return _lop; } const Query *rop() { return _rop; } protected: BinaryQuery( Query *lop, Query *rop ) : _lop( lop ), _rop( rop ) {} Query *_lop; Query *_rop; |
| // увы! эти определения классов некорректны class OrQuery : public BinaryQuery { public: virtual void eval(); }; class AndQuery : public BinaryQuery { public: virtual void eval(); |
// ошибка: отсутствует конструктор класса AndQuery AndQuery proust( new NameQuery( "marcel" ), |
// правильно: эти определения классов корректны class OrQuery : public BinaryQuery { public: OrQuery( Query *lop, Query *rop ) : BinaryQuery( lop, rop ) {} virtual void eval(); }; class AndQuery : public BinaryQuery { public: AndQuery( Query *lop, Query *rop ) : BinaryQuery( lop, rop ) {} virtual void eval(); |
template class Screen { public: Screen() : _height( hi ), _width( wid ), _cursor ( 0 ), _screen( hi * wid, '#' ) { } // ... private: string _screen; string::size_type _cursor; short _height; short _width; }; typedef Screen<24,80> termScreen; termScreen hp2621;
| |
template // ошибка: аргумент шаблона нельзя вычислить во время компиляции
| |
template template int size_val = 1024; const int c_size_val = 1024; Buf< 1024 > buf0; // правильно Buf< c_size_val > buf1; // правильно Buf< sizeof(size_val) > buf2; // правильно: sizeof(int) BufPtr< &size_val > bp0; // правильно // ошибка: нельзя вычислить во время компиляции
| |
template |
extern void foo( char * ); extern void bar( void * ); typedef void (*PFV)( void * ); const unsigned int x = 1024; template unsigned int size, PFV handler> class Array { ... }; Array Array Array Array Array |
template class BufPtr { ... }; // ошибка: 0 имеет тип int // неявное преобразование в нулевой указатель не применяется |
template < class Type > class Stack { }; void f1( Stack< char > ); // (a) class Exercise { // ... Stack< double > &rsd; // (b) Stack< int > si; // (c) }; int main() { Stack< char > *sc; // (d) f1( *sc ); // (e) int iObj = sizeof( Stack< string > ); // (f) |
template < int *ptr > class Ptr ( ... }; template < class Type, int size > class Fixed_Array { ... }; |
(a) const int size = 1024; |
(b) int arr[10]; Ptr< arr > bp2; |
(d) const int hi = 40; const int wi = 80; |
(e) const int size_val = 1024; |
(f) unsigned int fasize = 255; |
(g) const double db = 3.1415; |
extern void ff( int ); extern void ff( long, int = 0 ); int main() { ff( 2L ); // соответствует ff( long, 0 ); ff( 0, 0 ); // соответствует ff( long, int ); ff( 0 ); // соответствует ff( int ); ff( 3.14 ); // ошибка: неоднозначность |
namespace primerLib { void compute(); void compute( const void * ); } using primerLib::compute; void compute( int ); void compute( double, double = 3.4 ); void compute( char*, char* = 0 ); int main() { compute( 0 ); return 0; |
plus // вызывается string::operator+() sres = stringAdd( sval1, sval2 );
| |
minus ires = intSub( ival1, ival2 );
| |
multiplies cres = complexMultiplies( cval1, cval2 );
| |
divides ires = intDivides( ival1, ival2 );
| |
modulus Ires = IntModulus( Ival1, Ival2 );
| |
negate ires = intNegate( ires );
| |
| Символ операции | Значение | Использование | |||
| * | Умножение | expr * expr | |||
| / | Деление | expr / expr | |||
| % | Остаток от деления | expr % expr | |||
| + | Сложение | expr + expr | |||
| - | Вычитание | expr – expr |
| int ivall = 21 / 6; |
| 3.14 % 3; // ошибка: операнд типа double 21 % 6; // правильно: 3 21 % 7; // правильно: 0 21 % -5; // машинно-зависимо: -1 или 1 int iva1 = 1024; double dval = 3.14159; iva1 % 12; // правильно: |
| #include int main() { char byte_value = 32; int ival = 8; // переполнение памяти, отведенной под byte_value byte_value = ival * byte_value; cout << "byte_value: " <
| |
double dvall = 10.0, dva12 = 3.0; int ivall = 10, iva12 = 3; dvall / dva12; |
int iva1; float fval; double dval; // fva1 и iva1 преобразуются к double перед сложением |
char cvat; int iva1; float fva1; // iva1 и cval преобразуются к float перед сложением |
char cval; bool found; enum mumble { ml, m2, m3 } mval; unsigned long ulong; |
char cval; long lval; // cval и 1024 преобразуются в long перед сложением |
#include "Matrix.h" Matrix* trouble( Matrix *pm ) { Matrix res; // какие-то действия // результат присвоим res return &res; // плохо! } int main() { Matrix m1; // ... Matrix *mainResult = trouble( &m1 ); // ... |
int index; int upperBound; char selectVal; // ... error( "Array out of bounds: ", index, upperBound ); error( "Division by zero" ); |
(a) int calc( int, int ); int calc( const int, const int ); (b) int get(); double get(); (c) int *reset( int * ); double *reset( double * ): (d) extern "C" int compute( int *, int ); |
(a) void reset( int * ); void (*pf)( void * ) = reset; (b) int calc( int, int ); int (*pf1)( int, int ) = calc; (c) extern "C" int compute( int *, int ); int (*pf3)( int*, int ) = compute; |
// ----- SortLib.h ----- void quickSort( double *, double * ); void bubbleSort( double *, double * ); void mergeSort( double *, double * ); |
// ----- SortLib.C ----- void swap( double *dl, double *d2 ) { /* ... */ } // только эти функции используют swap() void quickSort( double *d1, double *d2 ) { /* ... */ } void bubbleSort( double *d1, double *d2 ) { /* ... */ } void mergeSort( double *d1, double *d2 ) { /* ... */ } |
// ----- SortLib.C ----- namespace { void swap( double *dl, double *d2 ) { /* ... */ } } |
void quickSort( double *d1, double *d2 ) { // ... double* elem = d1; // ... // ссылка на член безымянного пространства имен swap() swap( d1, elem ); // ... |
// SortLib.C // swap() невидима для других файлов программы static void swap( double *d1, double *d2 ) { /* ... */ } |
namespace cplusplus_primer { namespace MatrixLib { class matrix { /*...*/ }; matrix operator* ( const matrix &, const matrix & ); // ... } |
#include #include int main() { string in_string; // вывести литерал на терминал пользователя cout << "Введите свое имя, пожалуйста: "; // прочитать ответ пользователя в in_string cin >> in_string; if ( in_string.empty() ) // вывести сообщение об ошибке на терминал пользователя cerr << "ошибка: введенная строка пуста!\n"; else cout << "Привет, " << in_string << "!\n";
| |
#include #include #include #include int main() { string ifile; cout << "Введите имя файла для сортировки: "; cin >> ifile; // сконструировать объект класса ifstream для ввода из файла ifstream infile( ifile.c_str() ); if ( ! infile ) { cerr << "ошибка: не могу открыть входной файл: " << ifile << endl; return -1; } string ofile = ifile + ".sort"; // сконструировать объект класса ofstream для вывода в файл ofstream outfile( ofile.c_str() ); if ( ! outfile) { cerr << "ошибка: не могу открыть выходной файл: " << ofile << endl; return -2; } string buffer; vector< string, allocator > text; int cnt = 1; while ( infile >> buffer ) { text.push_back( buffer ); cout << buffer << (cnt++ % 8 ? " " : "\n" ); } sort( text.begin(), text.end() ); // выводим отсортированное множество слов в файл vector< string >::iterator iter = text.begin(); for ( cnt = 1; iter != text.end(); ++iter, ++cnt ) outfile << *iter << (cnt % 8 ? " " : "\n" ); return 0; |
#include string program_name( "our_program" ); string version( 0.01 ); // ... string mumble( int *array, int size ) { if ( ! array ) { ostringstream out_message; out_message << "ошибка: " << program_name << "--" << version << ": " << __FILE__ << ": " << __LINE__ << " -- указатель равен 0; " << " а должен адресовать массив.\n"; // возвращаем строку, в которой находится сообщение return out_message.str(); } // ... |
class File { // ... unsigned int modified : 1; // битовое поле |
typedef unsigned int Bit; class File { public: Bit mode: 2; Bit modified: 1; Bit prot_owner: 3; Bit prot_group: 3; Bit prot_world: 3; // ... |
void File::write() { modified = 1; // ... } void File::close() { if ( modified ) // ... сохранить содержимое |
enum { READ = 01, WRITE = 02 }; // режимы открытия файла int main() { File myFile; myFile.mode |= READ; if ( myFile.mode & READ ) cout << "myFile.mode is set to READ\n"; |
inline int File::isRead() { return mode & READ; } inline int File::isWrite() { return mode & WRITE; } |
template class Screen { // ... }; // частичная специализация шаблона класса Screen template class Screen {public: Screen(); // ... private: string _screen; string::size_type _cursor; short _height; // для экранов с 80 колонками используются специальные алгоритмы
| |
// конструктор для частичной специализации Screen template Screen ::Screen() : _height( hi ), _cursor( 0 ),_screen( hi * 80, bk ) |
void doit_and_bedone( vector< Query* > *pvec ) { vector it = pvec->begin(), end_it = pvec->end(); for ( ; it != end_it; ++it ) { Query *pq = *it; cout << "обрабатывается " << *pq << endl; pq->eval(); pq->display(); delete pq; }
| |
class Query { public: // объявляется чисто виртуальная функция virtual ostream& print( ostream&=cout ) const = 0; // ... |
// В классе Query объявлены одна или несколько виртуальных функций, // поэтому программист не может создавать независимые объекты // класса Query // правильно: подобъект Query в составе NameQuery Query *pq = new NameQuery( "Nostromo" ); // ошибка: оператор new создает объект класса Query |
istream& |
// возвращаемое значение - указатель на строковый вектор vector retrieve_text() { string file_name; cout << "please enter file name: "; cin >> file_name; // откроем файл для ввода ... ifstream 1nfile( file_name.c_str(), ios::in ); if ( ! infile ) { cerr << "oops! unable to open file " << file_name << " -- bailing out!\n"; exit( -1 ); } else cout << '\n'; vector new vector string textime; typedef pair stats maxline; int linenum = 0; while ( getline( infile, textline, '\n' )) { cout << "line read: " << textline << '\n'; if ( maxline.first < textline.size() ) { maxline.first = textline.size() ; maxline.second = linenum; } 1ines_of_text->push_back( textline ); linenum++; } return lines_of_text;
| |
#include "String.h" int main() { String flower; // что-нибудь записать в переменную flower if ( flower == "lily" ) // правильно // ... else if ( "tulip" == flower ) // ошибка // ... |
class Text { public: Text( const char * = 0 ); Text( const Text & ); // набор перегруженных операторов равенства bool operator==( const char * ) const; bool operator==( const String & ) const; bool operator==( const Text & ) const; // ... |
bool operator==( const String &, const String & ); |
bool operator==( const char *, const String & ); |
// ошибка: должен быть членом класса |
bool operator==( const String &str1, const String &str2 ) { if ( str1.size() != str2.size() ) return false; return strcmp( str1.c_str(), str2.c_str() ) ? false : true ; } inline bool operator==( const String &str, const char *s ) { return strcmp( str.c_str(), s ) ? false : true ; |
int student_count; double salary; bool on_loan; strins street_address; |
// ошибки компиляции: значения слева не являются l-значениями // ошибка: литерал - не l-значение 0 = 1; // ошибка: арифметическое выражение - не l-значение |
// файл module0.C |
// файл module1.C |
void mumble() { 3.14159; "melancholia"; upperBound; |
salary + raise ivec[ size/2 ] * delta |
int ival = 1024; |
#include class Screen { string _screen; // string( _height * _width ) string::size_type _cursor; // текущее положение на экране short _height; // число строк short _width; // число колонок
| |
class Screen { /* * _ screen адресует строку размером _height * _width * _cursor указывает текущую позицию на экране * _height и _width - соответственно число строк и колонок */ string _screen; string::size_type _cursor; short _height, _width; |
class StackScreen { int topStack; void (*handler)(); // указатель на функцию vector
| |
class First { int memi = 0; // ошибка double memd = 0.0; // ошибка |
class Account { public: Account(); explicit Account( const char*, double=0.0 ); Account( const Account& ); ~Account(); // ... private: char *_name; unsigned int _acct_nmbr; double _balance; }; inline Account::~Account() { delete [] _name; return_acct_number( _acct_nnmbr ); |
inline Account::~Account() { // необходимо delete [] _name; return_acct_number( _acct_nnmbr ); // необязательно _name = 0; _balance = 0.0; _acct_nmbr = 0; |
class Point3d { public: // ... private: float x, y, z; |
{ // начало критического участка программы #ifdef PROFILE Timer t; #endif // критический участок // t уничтожается автоматически // отображается затраченное время ... |
(1) #include "Account.h" (2) Account global( "James Joyce" ); (3) int main() (4) { (5) Account local( "Anna Livia Plurabelle", 10000 ); (6) Account &loc_ref = global; (7) Account *pact = 0; (8) (9) { (10) Account local_too( "Stephen Hero" ); (11) pact = new Account( "Stephen Dedalus" ); (12) } (13) (14) delete pact; |
// необязательно: неявно выполняется компилятором |
#include #include "Account.h" Account global( "James Joyce" ); int main() { Account local( "Anna Livia Plurabelle", 10000 ); Account &loc_ref = global; auto_ptr { Account local_too( "Stephen Hero" ); } // объект auto_ptr уничтожается здесь |
inline Query:: ~Query(){ delete _solution; } inline NotQuery:: ~NotQuery(){ delete _op; } inline OrQuery:: ~OrQuery(){ delete _lop; delete _rop; } inline AndQuery:: |
class Object { public: virtual ~Object(); virtual string isA(); protected: string _isA; private: Object( string s ) : _isA( s ) {} |
class ConcreteBase { public: explicit ConcreteBase( int ); virtual ostream& print( ostream& ); virtual ~Base(); static int object_count(); protected: int _id; static int _object_count; |
(a) class C1 : public ConcreteBase { public: C1( int val ) : _id( _object_count++ ) {} // ... |
(b) class C2 : public C1 { public: C2( int val ) : ConcreteBase( val ), C1( val ) {} // ... |
(c) class C3 : public C2 { public: C3( int val ) : C2( val ), _object_count( val ) {} // ... |
(d) class C4 : public ConcreteBase { public: C4( int val ) : ConcreteBase ( _id+val ){} // ... |
int ival = 0; // создаем объект типа int и инициализируем его 0 |
// необходимо ли это? if ( pi != 0 ) |
void f() { int i; string str = "dwarves"; int *pi = &i; short *ps = 0; double *pd = new doub1e(33); delete str; // плохо: str не является динамическим объектом delete pi; // плохо: pi ссылается на локальный объект delete ps; // безопасно delete pd; // безопасно |
// создание единственного объекта типа int // с начальным значением 1024 int *pi = new int( 1024 ); // создание массива из 1024 элементов // элементы не инициализируются int *pia = new int[ 1024 ]; // создание двумерного массива из 4x1024 элементов |
for (int index = 0; index < 1024; ++index ) |
const char *noerr = "success"; // ... const char *err189 = "Error: a function declaration must " |
#include const char *errorTxt; if (errorFound) errorTxt = errl89; else errorTxt = noerr; int dimension = strlen( errorTxt ) + 1; char *strl = new char[ dimension ]; // копируем текст ошибки в strl |
// обычная для С++ идиома, // иногда удивляющая начинающих программистов |
int getDim(); // создание двумерного массива int (*pia3)[ 1024 ] = new int[ getDim() ][ 1024 ]; // правильно // ошибка: второе измерение задано не константой |
// освобождение единичного объекта delete pint; // освобождение массива |
(a) int ival = 1024; (b) int *pi = &ival; (c) int *pi2 = new int(1024); |
int *pi = new int(10); int *pia = new int[10]; while ( *pi < 10 ) { pia[*pi] = *pi; *pi = *pi + 1; } delete pi; |
// ошибка: для двух перегруженных функций указана директива extern "C" extern "C" void print( const char* ); |
class SmallInt ( /* ... */ ); class BigNum ( /* ... */ ); // написанная на C функция может быть вызвана как из программы, // написанной на C, так и из программы, написанной на C++. // функции C++ обрабатывают параметры, являющиеся классами extern "C" double calc( double ); extern SmallInt calc( const SmallInt& ); |
Smallint si = 8; int main() { calc( 34 ); // вызывается C-функция calc( double ) calc( si ); // вызывается функция C++ calc( const SmallInt & ) // ... return 0; |
// директива связывания в форме простой инструкции extern "C" void exit(int); // директива связывания в форме составной инструкции extern "C" { int printf( const char* ... ); int scanf( const char* ... ); } // директива связывания в форме составной инструкции extern "C" { #include
| |
int main() { // ошибка: директива связывания не может появиться // внутри тела функции extern "C" double sqrt( double ); double getValue(); //правильно double result = sqrt ( getValue() ); //... return 0; |
extern "C" double sqrt( double ); int main() { double getValue(); //правильно double result = sqrt ( getValue() ); //... return 0; |
// функция calc() может быть вызвана из программы на C |
// ---- myMath.h ---- extern "C" double calc( double ); // ---- myMath.C ---- // объявление calc() в myMath.h #include "myMath.h" // определение функции extern "C" calc() // функция calc() может быть вызвана из программы на C |
const char *str = "hello"; void *malloc( int ); char *strcpy( char *, const char * ); int printf( const char *, ... ); int exit( int ); int strlen( const char * ); int main() { /* программа на языке С */ char* s = malloc( strlen(str)+l ); strcpy( s, str ); printf( "%s, world\n", s ); exit( 0 ); |
typedef double wages; typedef vector typedef vec_int test_scores; typedef bool in_attendance;
| |
// double hourly, weekly; wages hourly, weekly; // vector vec_int vecl( 10 ); // vector const int c1ass_size = 34; test_scores test0( c1ass_size ); // vector< bool > attendance; vector< in_attendance > attendance( c1ass_size ); // int *table[ 10 ];
| |
#include
| |
#define BOOKSTORE_H /* содержимое файла bookstore.h */ |
int main() { #ifdef DEBUG cout << "Начало выполнения main()\n"; #endif string word; vector while ( cin >> word ) { #ifdef DEBUG cout << "Прочитано слово: " << word << "\n"; #endif text.push_back(word); } // ... |
int main() |
int main() |
#idfef __cplusplus // компиляция С++ программы extern "C"; // extern "C" объясняется в главе 7 #endif |
if ( element_count == 0 ) |
typedef string::size_type size_type; size_type startPos = name.find( 'L' ) size_type endPos = name.find_1ast_of( 'b' ); name.erase( name.begin()+startPos, |
string string_object( "Missisippi" ); string::size_type pos = string_object.find( "isi" ); |
string new_string ( "AnnaBelle Lee" ); string_object += ' '; // добавим пробел // найдем начальную и конечную позицию в new_string pos = new_string.find( 'B' ); string::size_type posEnd = new_string.find( ' ' ); string_object.insert( string_object.size(), // позиция вставки new_string, pos, // начало подстроки в new_string posEnd // конец подстроки new_string |
string sl( "Mississippi" ); |
string s3; // скопируем первые 4 символа s1 |
// добавим пробел |
// добавим 4 первых символа s2 |
string beauty; // присвоим beauty значение "belle" |
// присвоим beauty значение "belle" |
string current_project( "C++ Primer, 3rd Edition" ); |
int elem_count( const string &word, char elem ) { int occurs = 0; // не надо больше проверять ix for ( int ix=0; ix < word.size(); ++-ix ) if ( word[ ix ] == elem ) ++occurs; return occurs; |
void mumble( const string &st, int index ) { // возможна ошибка char ch = st[ index ]; // ... |
void mumble( const string &st, int index ) { try { char ch = st.at( index ); // ... } catch ( std::out_of_range ){...} // ... |
string cobol_program_crash( "abend" ); |
string sentence( " An ADT provides both interface and implementation." ); string::size_type position = sentence.find_1ast_of( 'A' ); string::size_type length = 3; // заменяем ADT на Abstract Data Type |
string new_str( "Abstract Data Type" ); |
#include typedef string::size_type size_type; // найдем позицию трех букв size_type posA = new_str.find( 'A' ); size_type posD = new_str.find( 'D' ); size_type posT = new_str.find( 'T' ); // нашли: заменим T на "Type" sentence.replace( position+2, 1, new_str, posT, 4 ); // нашли: заменим D на "Data " sentence.replace( position+1, 1, new_str, posD, 5 ); // нашли: заменим A на "Abstract " |
string hmm( "Some celebrate Java as the successor to C++." ); string:: size_type position = hmm.find( 'J' ); // заменим Java на xxxx |
const char *lang = "EiffelAda95JavaModula3"; int index[] = { 0, 6, 11, 15, 22 }; string ahhem( "C++ is the language for today's power programmers." ); |
string sentence( "An ADT provides both interface and implementation." ); // указывает на 'A' в ADT string: iterator start = sentence. begin()+3; // заменяем ADT на Abstract Data Type |
string quote1( "When lilacs last in the dooryard bloom'd" ); |
string generate_salutation( string generic1, string lastname, string generic2, string::size_type pos, |
string lastName( "AnnaP" ); string greetings = |
#include int main() { char ch; int tab_cnt = 0, nl_cnt = 0, space_cnt = 0, period_cnt = 0, comma_cnt = 0; while ( cin.get(ch)) { switch( ch ) { case ' ': space_cnt++; break; case '\t': tab_cnt++; break; case '\n': nl_cnt++; break; case '.': period_cnt++; break; case ',': comma_cnt++; break; } cout.put(ch); } cout << "\nнаша статистика:\n\t" << "пробелов: " << space_cnt << '\t' << "символов новой строки: " << nl_cnt << '\t' << "табуляций: " << tab_cnt << "\n\t" << "точек: " << period_cnt << '\t' << "запятых: " << comma_cnt << endl;
| |
#include int main() { int ch; // альтернатива: // while ( ch = cin.get() && ch != EOF ) while (( ch = cin.get()) != EOF ) cout.put( ch ); return 0; |
#include int main() { const int max_line = 1024; char line[ max_line ]; while ( cin.get( line, max_line )) { // читается не больше max_line - 1 символов, // чтобы оставить место для нуля int get_count = cin.gcount(); cout << "фактически прочитано символов: " << get_count << endl; // что-то сделать со строкой // если встретился символ новой строки, // удалить его, прежде чем приступать к чтению следующей if ( get_count < max_line-1 ) cin.ignore(); } |
#include int main() { const int lineSize = 1024; int lcnt = 0; // сколько строк прочитано int max = -1; // длина самой длинной строки char inBuf[ lineSize ]; // читается до конца строки, но не более 1024 символов while (cin.getline( inBuf, lineSize )) { // сколько символов фактически прочитано int readin = cin.gcount(); // статистика: счетчик строк, самая длинная строка ++lcnt; if ( readin > max ) max = readin; cout << "Строка #" << lcnt << "\tПрочитано символов: " << readin << endl; cout.write( inBuf, readin).put('\n').put('\n'); } cout << "Всего прочитано строк: " << lcnt << endl; cout << "Самая длинная строка: " << max << endl; |
// возвращает символ в поток putback( char class ); // устанавливает "указатель на следующий символ потока istream на один символ назад unget(); // возвращает следующий символ (или EOF), // но не извлекает его из потока |
char ch, next, lookahead; while ( cin.get( ch )) { switch (ch) { case '/': // это комментарий? посмотрим с помощью peek() // если да, пропустить остаток строки next = cin.peek(); if ( next == '/' ) cin.ignore( lineSize, '\n' ); break; case '>': // проверка на лексему >>= next = cin.peek(); if ( next == '>' ) { lookahead = cin.get(); next = cin.peek(); if ( next != '=' ) cin.putback( lookahead ); } // ... |
void NameQuery:: display_partial_solution( ostream &os ) { os << _name << " is found in " << (_solution ? _solution->size() : 0) << " lines of text\n"; |
NameQuery nq( "Frost" ); // вызывается NameQuery::eval() nq.eval(); // вызывается Query::display() |
void NameQuery:: match_count() { if ( ! _solution ) // вызывается Query::_vec2set() _solution = _vec2set( &_loc ); return _solution->size(); |
class Diffident { public: // ... protected: int _mumble; // ... }; class Shy : public Diffident { public: // ... protected: // имя Diffident::_mumble скрыто string _mumble; // ... |
void Shy:: turn_eyes_down() { // ... _mumble = "excuse me"; // правильно // ошибка: int Diffident::_mumble скрыто _mumble = -1; |
void Shy:: turn_eyes_down() { // ... _mumble = "excuse me"; // правильно // правильно: имя члена базового класса квалифицировано Diffident::_mumble = -1; |
class Diffident { public: void mumble( int softness ); // ... }; class Shy : public Diffident { public: // скрывает видимость функции-члена Diffident::_mumble, // а не перегружает ее void mumble( string whatYaSay ); void print( int soft, string words ); // ... |
Shy simon; // правильно: Shy::mumble( string ) simon.mumble( "pardon me" ); // ошибка: ожидался первый аргумент типа string // Diffident::mumble( int ) невидима |
class Diffident { public: void turn_aside( ); // ... }; class Shy : public Diffident { public: // скрывает видимость // Diffident::turn_aside() void turn_aside(); // ... |
class Shy : public Diffident { public: // один из способов реализовать множество перегруженных // членов базового и производного классов void mumble( string whatYaSay ); void mumble( int softness ) { Diffident::mumble( softness ); } // ... |
class Shy : public Diffident { public: // в стандартном C++ using-объявление // создает множество перегруженных // членов базового и производного классов void mumble( string whatYaSay ); using Diffident::mumble; // ... |
class Query { public: const vector // ... protected: vector // ... |
bool NameQuery:: compare( const Query *pquery ) { // правильно: защищенный член подобъекта Query int myMatches = _loc.size(); // ошибка: нет прав доступа к защищенному члену // независимого объекта Query int itsMatches = pquery->_loc.size(); return myMatches == itsMatches; |
bool NameQuery:: compare( const Query *pquery ) { // правильно: защищенный член подобъекта Query int myMatches = _loc.size(); // правильно: используется открытый метод доступа int itsMatches = pquery->locations()->size(); return myMatches == itsMatches; |
bool NameQuery:: compare( const NameQuery *pname ) { int myMatches = _loc.size(); // правильно int itsMatches = name->_loc.size(); // тоже правильно return myMatches == itsMatches; |
// ошибка: suffix() - не член класса Query |
// ошибка: _name - не член класса Query |
// ошибка: у класса Query нет базового класса NameQuery |
class Query { friend class NameQuery; public: // ... |
class Base { public: foo( int ); // ... protected: int _bar; double _foo_bar; }; class Derived : public Base { public: foo( string ); bool bar( Base *pb ); void foobar(); // ... protected: string _bar; |
Derived d; d.foo( 1024 ); |
(c) bool Derived::bar( Base *pb ) |
#include void Screen::copy( const Screen &sobj ) { // если этот объект и объект sobj - одно и то же, // копирование излишне // мы анализируем указатель this (см. раздел 13.4) if ( this != &sobj ) { _height = sobj._height; _width = sobj._width; _cursor = 0; // создаем новую строку; // ее содержимое такое же, как sobj._screen _screen = sobj._screen; }
| |
#include "Screen.h" int main() { Screen s1; // Установить s1 Screen s2; s2.copy(s1); // ... |
class Screen { public: // функции-члены private: // инициализация статических членов (см. 13.5) static const int _height = 24; static const int _width = 80; string _screen; string::size_type _cursor; |
class Screen { public: void home() { _cursor = 0; } char get() { return _screen[_cursor]; } char get( int, int ); void move( int, int ); // ... private: string _screen; string::size_type _cursor; short _height, _width; |
class Screen { friend istream& operator>>( istream&, Screen& ); friend ostream& operator<<( ostream&, const Screen& ); public: // ... оставшаяся часть класса Screen |
#include ostream& operator<<( ostream& os, const Screen& s ) { // правильно: можно обращаться к _height, _width и _screen os << "<" << s._height << "," << s._width << ">"; os << s._screen; return os;
| |
bool operator==( const String &str1, const String &str2 ) { if ( str1.size() != str2.size() ) return false; return strcmp( str1.c_str(), str2.c_str() ) ? false : true; |
bool String::operator==( const String &rhs ) const { if ( _size != rhs._size ) return false; return strcmp( _string, rhs._string ) ? false : true; |
class String { friend bool operator==( const String &, const String & ); friend bool operator==( const char *, const String & ); friend bool operator==( const String &, const char * ); public: // ... остальная часть класса String |
// в таком виде это не компилируется template < typename type > int count( const vector< type > &vec, type value ) { int count = 0; vector< type >::iterator iter = vec.begin(); while ( iter != vec.end() ) if ( *iter == value ) ++count; return count; |
// правильно: это компилируется без ошибок |
vector< int > vec0; |
vector< int >::iterator iter0 = vec0.begin(); |
// правильно: инициализация константного итератора неконстантным |
if ( ! outfile ) // false, если файл не открыт |
ifstream infile("name-of-file"); |
#include #include #include int main() { ifstream infile("in_file"); ofstream outfile("out_file"); if ( ! infile ) { cerr << "Ошибка открытия входного файла.\n" return -1; } if ( ! outfile ) { cerr << "Ошибка открытия выходного файла.\n" return -2; }
| |
class Screen { public: void home() { _cursor = 0; } char get() { return _screen[_cursor]; } char get( int, int ); void move( int, int ); bool checkRange( int, int ); int height() { return _height; } int width() { return _width; } // ... |
Screen myScreen, groupScreen; myScreen.home(); |
template class Queue { // ... public: // встроенный конструктор Queue() : front( 0 ), back( 0 ) { } // ...
| |
template class Queue { public: Queue(); private: // ... }; template inline Queue
| |
template class Queue { public: Queue() : front( 0 ), back ( 0 ) { } ~Queue(); Type& remove(); void add( const Type & ); bool is_empty() const { return front == 0; } private: QueueItem QueueItem
| |
template Queue { while (! is_empty() ) remove();
| |
template void Queue { // создать новый объект QueueItem QueueItem new QueueItem if ( is_empty() ) front = back = pt; else { back->next = pt; back = pt; }
| |
#include #include template Type Queue { if ( is_empty() ) { cerr << "remove() вызвана для пустой очереди\n"; exit( -1 ); } QueueItem front = front->next; Type retval = pt->item; delete pt; return retval;
| |
#include #include "Queue.h" int main() { // конкретизируется класс Queue // оператор new требует, чтобы Queue Queue int ival; for ( ival = 0; ival < 10; ++ival ) // конкретизируется функция-член add() p_qi->add( ival ); int err_cnt = 0; for ( ival = 0; ival < 10; ++ival ) { // конкретизируется функция-член remove() int qval = p_qi->remove(); if ( ival != qval ) err_cnt++; } if ( !err_cnt ) cout << "!! queue executed ok\n"; else cerr << "?? queue errors: " << err_cnt << endl; return 0;
| |
const char blank = ' '; |
const Screen blankScreen; blankScreen.display(); // читает объект класса |
class Screen { public: char get() const { return _screen[_cursor]; } // ... |
class Screen { public: bool isEqual( char ch ) const; // ... private: string::size_type _cursor; string _screen; // ... }; bool Screen::isEqual( char ch ) const { return ch == _screen[_cursor]; |
class Screen { public: int ok() const { return _cursor; } void error( int ival ) const { _cursor = ival; } // ... private: string::size_type _cursor; // ... |
#include class Text { public: void bad( const string &parm ) const; private: char *_text; }; void Text::bad( const string &parm ) const { _text = parm.c_str(); // ошибка: нельзя модифицировать _text for ( int ix = 0; ix < parm.size(); ++ix ) _text[ix] = parm[ix]; // плохой стиль, но не ошибка |
class Screen { public: char get(int x, int y); char get(int x, int y) const; // ... |
int main() { const Screen cs; Screen s; char ch = cs.get(0,0); // вызывает константную функцию-член ch = s.get(0,0); // вызывает неконстантную функцию-член |
class Screen { public: char poll() volatile; // ... }; |
class Screen { public: void home(); void move( int, int ); char get(); char get( int, int ); void checkRange( int, int ); // ... |
class Screen { public: // определения функций home() и get() void home() { _cursor = 0; } char get() { return _screen[_cursor]; } // ... |
ptrScreen->home(); |
class Screen { public: // объявления перегруженных функций-членов get() char get() { return _screen[_cursor]; } char get( int, int ); // ... |
namespace NS { struct myClass { void k( int ); static void k( char* ); void mf(); }; int k( double ); }; void h(char); void NS::myClass::mf() { h('a'); // вызывается глобальная h( char ) k(4); // вызывается myClass::k( int ) |
void f(); void f( int ); void f( double, double = 3.4 ); void f( char*, char* ); int main() { f( 5.6 ); // для разрешения этого вызова есть четыре кандидата return 0; |
namespace NS { class C { /* ... */ }; void takeC( C& ); } // тип cobj - это класс C, объявленный в пространстве имен NS NS::C obj; int main() { // в точке вызова не видна ни одна из функций takeC() takeC( cobj); // правильно: вызывается NS::takeC( C& ), // потому что аргумент имеет тип NS::C, следовательно, // принимается во внимание функция takeC(), // объявленная в пространстве имен NS return 0; |
SmallInt si(15); |
const matrix& add( const matrix &, int ); double add( double, double ); int main() { SmallInt si(15); add( si, 566 ); // ... |
namespace NS { class SmallInt { /* ... */ }; class String { /* ... */ }; String add( const String &, const String & ); } int main() { // si имеет тип class SmallInt: // класс объявлен в пространстве имен NS NS::SmallInt si(15); add( si, 566 ); // NS::add() - функция-кандидат return 0; |
namespace NS { class SmallInt { friend SmallInt add( SmallInt, int ) { /* ... */ } }; } int main() { NS::SmallInt si(15); add( si, 566 ); // функция-друг add() - кандидат return 0; |
object.memfunc( args ); |
namespace NS { class ZooAnimal { /* ... */ }; void display( const ZooAnimal& ); } // базовый класс Bear объявлен в пространстве имен NS class Bear : public NS::ZooAnimal { }; int main() { Bear baloo; display( baloo ); return 0; |
mc.mf( arg ); |
class myClass { public: void mf( double ); void mf( char, char = '\n' ); static void mf( int* ); // ... }; int main() { myClass mc; int iobj; mc.mf( iobj ); |
void mf( double ); void mf( char, char = '\n' ); |
prog [-d] [-h] [-v] [-o output_file] [-l limit_value] file_name |
prog -l 1024 -o chap1-2.out chapl.doc chap2.doc prog d chap3.doc |
for ( int ix = 1; ix < argc; ++ix ) { char *pchar = argv[ ix ]; // ... |
switch ( pchar[ 0 ] ) { case '-': { // -h, -d, -v, -l, -o } default: { // обработаем максимальный размер для опции -1 // имя выходного файла для -o // имена входных файлов ... } |
case '-': { switch( pchar[ 1 ] ) { case 'd': // обработка опции debug break; case 'v': // обработка опции version break; case 'h': // обработка опции help break; case 'o': // приготовимся обработать выходной файл break; case 'l': // приготовимся обработать макс.размер break; default: // неопознанная опция: // сообщить об ошибке и завершить выполнение } |
case 'd': debug_on = true; |
if ( debug_on ) |
case 'v': cout << program_name << "::" << program_version << endl; |
case 'h': // break не нужен: usage() вызывает exit() |
// если ofi1e_on==true, // следующий параметр - имя выходного файла bool ofi1e_on = false; // если ofi1e_on==true, // следующий параметр - максимальный размер |
case 'l': limit_on = true; break; case 'o': ofile_on = true; |
// обработаем максимальный размер для опции -1 // имя выходного файла для -o // имена входных файлов ... default: { // ofile_on включена, если -o встречалась if ( ofile_on ) { // обработаем имя выходного файла // выключим ofile_on } else if ( limit_on ) { // если -l встречалась // обработаем максимальный размер // выключим limit_on } else { // обработаем имя входного файла } |
if ( ofile_on ) { ofile_on = false; ofile = pchar; |
// int limit; else if ( limit_on ) { limit_on = false; limit = atoi( pchar ); if ( limit < 0 ) { cerr << program_name << "::" << program_version << " : error: " << "negative value for limit.\n\n"; usage( -2 ); } |
else |
prog - d dataOl |
#include #include #include #include const char *const program_name = "comline"; const char *const program_version = "version 0.01 (08/07/97)"; inline void usage( int exit_value = 0 ) { // печатает отформатированное сообщение о порядке вызова // и завершает программу с кодом exit_value ... cerr << "порядок вызова:\n" << program_name << " " << "[-d] [-h] [-v] \n\t" << "[-o output_file] [-l limit] \n\t" << "file_name\n\t[file_name [file_name [ ... ]]]\n\n" << "где [] указывает на необязательность опции:\n\n\t" << "-h: справка.\n\t\t" << "печать этого сообщения и выход\n\n\t" << "-v: версия.\n\t\t" << "печать информации о версии программы и выход\n\n\t" << "-d: отладка.\n\t\t включает отладочную печать\n\n\t" << "-l limit\n\t\t" << "limit должен быть неотрицательным целым числом\n\n\t" << "-o ofile\n\t\t" << "файл, в который выводится результат\n\t\t" << "по умолчанию результат записывается на стандартный вывод\n\n" << "file_name\n\t\t" << "имя подлежащего обработке файла\n\t\t" << "должно быть задано хотя бы одно имя --\n\t\t" << "но максимальное число не ограничено\n\n" << "примеры:\n\t\t" << "$command chapter7.doc\n\t\t" << "$command -d -l 1024 -o test_7_8 " << "chapter7.doc chapter8.doc\n\n"; exit( exit_value ); } int main( int argc, char* argv[] ) { bool debug_on = false; bool ofile_on = false; bool limit_on = false; int limit = -1; string ofile; vector cout << "демонстрация обработки параметров в командной строке:\n" << "argc: " << argc << endl; for ( int ix = 1; ix < argc; ++ix ) { cout << "argv[ " << ix << " ]: " << argv[ ix ] << endl; char *pchar = argv[ ix ]; switch ( pchar[ 0 ] ) { case '-': { cout << "встретился \'-\'\n"; switch( pchar[ 1 ] ) { case 'd': cout << "встретилась -d: " << "отладочная печать включена\n"; debug_on = true; break; case 'v': cout << "встретилась -v: " << "выводится информация о версии\n"; cout << program_name << " :: " << program_version << endl; return 0; case 'h': cout << "встретилась -h: " << "справка\n"; // break не нужен: usage() завершает программу usage(); case 'o': cout << "встретилась -o: выходной файл\n"; ofile_on = true; break; case 'l': cout << "встретилась -l: " << "ограничение ресурса\n"; limit_on = true; break; default: cerr << program_name << " : ошибка : " << "неопознанная опция: - " << pchar << "\n\n"; // break не нужен: usage() завершает программу usage( -1 ); } break; } default: // либо имя файла cout << "default: параметр без дефиса: " << pchar << endl; if ( ofile_on ) { ofile_on = false; ofile = pchar; } else if ( limit_on ) { limit_on = false; limit = atoi( pchar ); if ( limit < 0 ) { cerr << program_name << " : ошибка : " << "отрицательное значение limit.\n\n"; usage( -2 ); } } else file_names.push_back( string( pchar )); break; } } if ( file_names.empty() ) { cerr << program_name << " : ошибка : " << "не задан ни один входной файл.\n\n"; usage( -3 ); } if ( limit != -1 ) cout << "Заданное пользователем значение limit: " << limit << endl; if ( ! ofile.empty() ) cout << "Заданный пользователем выходной файл: " << ofile << endl; cout << (file_names.size() == 1 ? "Файл, " : "Файлы, ") << "подлежащий(е) обработке:\n"; for ( int inx = 0; inx < file_names.size(); ++inx ) cout << "\t" << file_names[ inx ] << endl; |
class SoSpotLight : public SoLight { ... } class SoPointLight : public SoLight { ... } |
class RiSpotLight : public SoSpotLight { ... } class RiPointLight : public SoPointLight { ... } |
SoLight *plight = next_scene_light(); if ( RiDirectionalLight *pdilite = dynamic_cast pdilite->scls.cast_shadow_map(); else if ( RiSpotLight *pslite = dynamic_cast pslite->scls.cast_shadow_map(); |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |

|
class RiDirectionalLight : public SoDirectionalLight, public SCLS { ... }; class RiSpotLight : public SoSpotLight, public SCLS { ... }; // ... SoLight *plight = next_scene_light(); if ( SCLS *pscls = dynamic_cast |
|
class SoLight : public SoNode { public: void cast_shadow_map() { if ( _scls ) _scls->cast_shadow_map(); } // ... protected: SCLS *_scls; }; // ... SdSoLight *plight = next_scene_light(); |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
namespace std { class exception public: exception() throw(); exception( const exception & ) throw(); exception& operator=( const exception & ) throw(); virtual ~exception() throw(); virtual const char* what() const throw(); }; |
namespace std { class logic_error : public exception { // логическая ошибка public: explicit logic_error( const string &what_arg ); }; class invalid_argument : public logic_error { // неверный аргумент public: explicit invalid_argument( const string &what_arg ); }; class out_of_range : public logic_error { // вне диапазона public: explicit out_of_range( const string &what_arg ); }; class length_error : public logic_error { // неверная длина public: explicit length_error( const string &what_arg ); }; class domain_error : public logic_error { // вне допустимой области public: explicit domain_error( const string &what_arg ); }; |
namespace std { class runtime_error : public exception { // ошибка времени выполнения public: explicit runtime_error( const string &what_arg ); }; class range_error : public runtime_error { // ошибка диапазона public: explicit range_error( const string &what_arg ); }; class overflow_error : public runtime_error { // переполнение public: explicit overflow_error( const string &what_arg ); }; class underflow_error : public runtime_error { // потеря значимости public: explicit underflow_error( const string &what_arg ); }; |
#include (a) void operate() throw( logic_error ); (b) int mathErr( int ) throw( underflow_error, overflow_error ); |
#include int main() { try { // использование функций из стандартной библиотеки } catch( exception ) { } catch( runtime_error &re ) { } catch( overflow_error eobj ) { } |
int main() { // использование стандартной библиотеки |
#include #include template class Array { public: // ... elemType& operator[]( int ix ) const { if ( ix < 0 || ix >= _size ) { string eObj = "ошибка: вне диапазона в Array throw out_of_range( eObj ); } return _ia[ix]; } // ... private: int _size; elemType *_ia; |
int main() { try { // функция main() такая же, как в разделе 16.2 } catch ( const out_of_range &excep ) { // печатается: // ошибка: вне диапазона в Array cerr << excep.what() << "\n"; return -1; } |
| + | - | * | / | % | ^ | & | | | ~ | |||||||||
| ! | , | = | < | > | <= | >= | ++ | -- | |||||||||
| << | >> | == | != | && | || | += | -= | /= | |||||||||
| %= | ^= | &= | |= | *= | <<= | >>= | [] | () | |||||||||
| -> | ->* | new | new[] | delete | delete[] |
| // неперегружаемые операторы |
| // ошибка: нельзя переопределить встроенный оператор сложения int |
| // некорректно: ! - это унарный оператор bool operator!( const String &s1, const String &s2 ) { return ( strcmp( s1.c_str(), s2.c_str() ) != 0 ); |
| asm | auto | bool | break | case | |||||
| catch | char | class | const | const_cast | |||||
| continue | default | delete | do | double | |||||
| dynamic_cast | else | enum | explicit | export | |||||
| extern | false | float | for | friend | |||||
| goto | if | inline | int | long | |||||
| mutable | namespace | new | operator | private | |||||
| protected | public | register | reinterpret_cast | return | |||||
| short | signed | sizeof | static | static_cast | |||||
| struct | switch | template | this | throw | |||||
| true | try | typedef | typeid | typename | |||||
| union | unsigned | using | virtual | void | |||||
| volatile | wchar_t | while |
inline Account:: Account( const Account &rhs ) { _acct_nmbr = rhs._acct_nmbr; _balance = rhs._balance; // Псевдокод на C++ // иллюстрирует вызов копирующего конструктора // для члена, являющегося объектом класса _name.string::string( rhs._name ); |
// не совсем правильно... inline Account:: Account( const Account &rhs ) { _name = rhs._name; _balance = rhs._balance; _acct_nmbr = get_unique_acct_nmbr(); |
inline Account:: Account( const Account &rhs ) : _name( rhs._name ) { _balance = rhs._balance; _acct_nmbr = get_unique_acct_nmbr(); |
(a) class BinStrTreeNode { public: // ... private: string _value; int _count; BinStrTreeNode *_leftchild; BinStrTreeNode *_rightchild; |
(b) class BinStrTree { public: // ... private: BinStrTreeNode *_root; |
(c) class iMatrix { public: // ... private: int _rows; int _cols; int *_matrix; |
(d) class theBigMix { public: // ... private: BinStrTree _bst; iMatrix _im; string _name; vectorMfloat> *_pvec; |
Point global; Point foo_bar( Point arg ) { Point local = arg; Point *heap = new Point( global ); *heap = local; Point pa[ 4 ] = { local, *heap }; return *heap; |
int (*pfi)( const string &, const string & ) = lexicoCompare; |
pfi = lexicoCompare; |
int calc( int, int ); int (*pfi2s)( const string &, const string & ) = 0; int (*pfi2i)( int, int ) = 0; int main() { pfi2i = calc; // правильно pri2s = calc; // ошибка: несовпадение типов pfi2s = pfi2i; // ошибка: несовпадение типов return 0; |
class Data { public: int ival; char *ptr; |
Data dat01( "Venus and the Graces", 107925 ); Data dat02( "about" ); Data dat03( 107925 ); |
int main() { // local1.ival = 0; local1.ptr = 0 Data local1 = { 0, 0 }; // local2.ival = 1024; // local3.ptr = "Anna Livia Plurabelle" Data.local2 - { 1024, "Anna Livia Plurabelle" }; // ... |
// ошибка: ival = "Anna Livia Plurabelle"; // ptr = 1024 |
#include #include #include #include #include "Accounts.h" typedef pair /* init_heap_array() * объявлена как статическая функция-член * обеспечивает выделение памяти из хипа и инициализацию * массива объектов * init_values: пары начальных значений элементов массива * elem_count: число элементов в массиве * если 0, то размером массива считается размер вектора * init_values */ Account* Account:: init_heap_array( vector vector { vector vec_size = init_value.size(); if ( vec_size == 0 && elem_count == 0 ) return 0; // размер массива равен либо elem_count, // либо, если elem_count == 0, размеру вектора ... size_t elems = elem_count ? elem_count : vec_size(); // получить блок памяти для размещения массива char *p = new char[sizeof(Account)*elems]; // по отдельности инициализировать каждый элемент массива int offset = sizeof( Account ); for ( int ix = 0; ix < elems; ++ix ) { // смещение ix-ого элемента // если пара начальных значений задана, // передать ее конструктору; // в противном случае вызвать конструктор по умолчанию if ( ix < vec_size ) new( p+offset*ix ) Account( init_values[ix].first, init_values[ix].second ); else new( p+offset*ix ) Account; } // отлично: элементы распределены и инициализированы; // вернуть указатель на первый элемент return (Account*)p;
| |
for ( int ix = 0; ix < elems; ++ix ) { if ( ix < vec_size ) new( p+offset*ix ) Account( init_values[ix].first, init_values[ix].second ); else new( p+offset*ix ) Account; |
void Account:: dealloc_heap_array( Account *ps, size_t elems ) { for ( int ix = 0; ix < elems; ++ix ) ps[ix].Account::~Account(); delete [] reinterpret_cast |
class Account { public: // ... static Account* init_heap_array( vector vector static void dealloc_heap_array( Account*, size_t ); // ... |
#include #include #include int main() { string fileName; // #1 cout << "Введите имя файла: "; cin >> fileName; if ( fileName.empty() ) { // странный случай cerr << "Пустое имя файла. Завершение работы.\n"; return -1; } ifstream inFile( fileName.c_str() ); // #2 if ( ! inFile ) { cerr << "Невозможно открыть файл.\n"; return -2; } string inBuf; // #3 vector< string > text; // #4 while ( inFile >> inBuf ) { for ( int ix = 0; ix < inBuf .size(); ++ix ) // #5 // можно обойтись без ch, // но мы использовали его для иллюстрации if (( char ch = inBuf[ix] )=='.'){ // #6 ch = '_'; inBuf[ix] = ch; } text.push_back( inBuf ); } if ( text.empty() ) return 0; // одна инструкция объявления, // определяющая сразу два объекта vector iend = text.end(); while ( iter != -iend ) { cout << *iter << '\n'; ++iter; } return 0;
| |
// одна инструкция объявления, // определяющая сразу два объекта vector |
vector |
// то ли хотел определить программист? |
string *ptr1; |
int aCnt=0, eCnt=0, iCnt=0, oCnt=0, uCnt=0; |
// возвращается индекс элемента или -1 int search( int *ia, int size, int value ) { // проверка что ia != 0 и size > 0 ... int loc = -1; for ( int ix = 0; ix < size; ++ix ) { if ( value == ia[ ix ] ) { // нашли! // запомним индекс и выйдем из цикла 1oc = ix; break; } } // конец цикла // сюда попадаем по break ... return 1oc; |
// ошибка: неверное использование break if ( ptr ) { if ( *ptr == "quit" ) break; // ... |
white ( cin >> inBuf ) { switch( inBuf[ 0 ] ) { case '-': for ( int ix = 1; ix < inBuf.size(); ++ix ) { if ( inBuf[ ix ] == ' ' ) break; // #1 // ... // ... } break; // #2 case '+': // ... } |
#include int main() { int ia[ 10 ]; for ( int ix = 0; ix < 10; ++-ix ) ia[ ix ] = ix; vector vector for ( ; iter != ivec.end(); ++iter ) *iter *= 2; return 0;
| |
for (инструкция-инициализации; условие; выражение ) |
// index и iter определены в другом месте for ( index =0; ... for ( ; /* пустая инструкция */ ... for ( iter = ivec.begin(); ... for ( int 1o = 0,hi = max; ... |
(... index < arraySize; ... ) (... iter != ivec.end(); ... ) (... *stl++ = *st2++; ... ) |
( ... ...; ++-index ) ( ... ...; ptr = ptr->next ) ( ... ...; ++i, --j, ++cnt ) |
const int sz = 24; int ia[ sz ]; vector for ( int ix = 0; ix < sz; ++ix ) { ivec[ ix ] = ix; ia[ ix ]= ix; |
for ( int ival = 0, *pi = &ia, &ri = val; ival < size; ++iva1, ++pi, ++ri ) |
#include int main() { for ( int ix = 0; bool done = ix == 10; ++ix ) cout << "ix: " << ix << endl; |
int main() { string word; vector< string > text; // ... for ( vector< string >::iterator iter = text.begin(), iter_end = text.end(); iter != text.end(); ++iter ) { if ( *iter == word ) break; // ... } // ошибка: iter и iter_end невидимы if ( iter != iter_end ) |
(a) for ( int *ptr = &ia, ix = 0; ix < size && ptr != ia+size; ++ix, ++ptr ) // ... |
(b) for ( ; ; ) { if ( some_condition ) break; // ... |
(c) for ( int ix = 0; ix < sz; ++ix ) // ... if ( ix != sz ) // ... (d) int ix; for ( ix < sz; ++ix ) // ... (e) for ( int ix = 0; ix < sz; ++ix, ++ sz ) |
bool is_equa1( const vector |
while ( cin >> inBuf ) { if ( inBuf[0] '= '_' ) continue; // завершение итерации // обработка слова ... |
int val; bool more = true; // фиктивное значение, нужное для // начала цикла while ( more ) { val = getValue(); val = convertValue(val); printValue(val); more = doMore(); |
do инструкция |
do { val = getValue(); val = convertValue(val); printValue(val); |
// ошибка: объявление переменной // в условии не разрешается do { // ... mumble( foo ); |
do string rsp; int vail, va12; cout << "Введите два числа: "; c-in >> vail >> va12; cout << "Сумма " << vail << " и " << va12 << " = " << vail + va12 << "\n\n" << "Продолжить? [да][нет] "; cin >> rsp; while ( rsp[0] != 'n' ); (b) do { // ... } while ( int iva1 = get_response() ); (c) do { int ival = get_response(); if ( iva1 == some_value() ) break; } while ( iva1 ); if ( !iva1 ) |
end: ; // пустая инструкция |
int oops_in_error() { // mumble ... goto end; // ошибка: переход через объявление int ix = 10; // ... код, использующий ix end: ; |
int oops_in_error() { // mumble ... goto end; { // правильно: объявление во вложенном блоке int ix = 10; // ... код, использующий ix } end: ; |
// переход назад через объявление не считается ошибкой. void mumble ( int max_size ) { begin: int sz = get_size(); if ( sz <= 0 ) { // выдать предупреждение ... goto end; } else if ( sz > max_size ) // получить новое значение sz goto begin; { // правильно: переход через целый блок int ia = new int[ sz ]; doit( ia, sz ) ; delete [] ia; } end: ; |
if ( условие ) |
if ( int ival = compute_value() ) { // область видимости ival // ограничена этим блоком } // ошибка: ival невидим |
if ( minVal > ivec[ i ] )...// новое значение minVal |
if ( minVal > ivec[ i ] ) minVal = ivec[ i ]; |
if ( minVal > ivec[ i ] ) { minVal = ivec[ i ]; occurs = 1; |
if ( minVal == ivec [ i ] ) |
if ( minVal > ivec[ i ] ) { minVal = ivec[ i ]; occurs = 1; } // если minVal только что получила новое значение, // то occurs будет на единицу больше, чем нужно if ( minVal == ivec[ i ] ) |
if ( условие ) инструкция1 else |
if ( minVal == ivec[ i ] ) ++occurs; else if ( minVal > ivec[ i ] ) { minVal = ivec[ i ]; occurs = 1; |
if ( minVal < ivec[ i ] ) {} // пустая инструкция else if ( minVal > ivec[ i ] ) { minVal = ivec[ i ]; occurs = 1; } else // minVal == ivec[ i ] |
if ( minVal <= ivec[ i ] ) if ( minVal == ivec[ i ] ) ++occurs; else { minVal = ivec[ i ]; occurs = 1; |
if ( minVal <= ivec[ i ] ) { if ( minVal == ivec[ i ] ) ++occurs; else { minVal = ivec[ i ]; occurs = 1; } |
if ( minVal <= ivec[ i ] ) { if ( minVal == ivec[ i ] ) ++occurs; } else { minVal = ivec[ i ]; occurs = 1; |
#include int min( const vector { int minVal = 0; occurs = 0; int size = ivec.size(); for ( int ix = 0; ix < size; ++ix ) { if ( minVal == ivec[ ix ] ) ++occurs; else if ( minVal > ivec[ ix ] ) { minVal = ivec[ ix ]; occurs = 1; } } return minVal; |
int main() { int occur_cnt = 0; vector< int > ivec; // occur_cnt получает значение occurs // из функции min() int minval = min( ivec, occur_cnt ); // ... |
// альтернативная реализация // с помощью пары #include #include typedef pair min_va1_pair min( const vector { int minVal = 0; int occurs = 0; // то же самое ... return make_pair( minVal, occurs ); |
// исправленная версия min() // оставляющая возможность для оптимизации ... int minVal = ivec[0]; occurs = 0; int size = ivec.size(); for ( int ix = 0; ix < size; ++ix ) { if ( minVal == ivec[ ix ] ) ++occurs; |
// оптимизированная версия min(), // к сожалению, содержащая ошибку... int minVal = ivec[0]; occurs = 0; int size = ivec.size(); for ( int ix = 1; ix < size; ++ix ) { if ( minVal == ivec[ ix ] ) ++occurs; |
int minVal = ivec[0]; |
#include #include int min( const vector< int > &ivec, int &occurs ) { int minVal = ivec[ 0 ]; occurs = 1; int size = ivec.size(); for ( int ix = 1; ix < size; ++ix ) { if ( minVal == ivec[ ix ] ) ++occurs; else if ( minVal > ivec[ ix ] ){ minVal = ivec[ ix ]; occurs = 1; } } return minVal; } int main() { int ia[] = { 9,1,7,1,4,8,1,3,7,2,6,1,5,1 }; vector int occurs = 0; int minVal = min( ivec, occurs ); cout << "Минимальное значение: " << minVal << " встречается: " << occurs << " раз.\n"; return 0; |
template inline const valueType& min( valueType &vall, valueType &va12 ) { if ( vall < va12 ) return vall; return va12; |
template inline const valueType& min( valueType &vall, valueType &va12 ) { return ( vall < va12 ) ? vall : va12; |
if ( ch == 'a' || ch == 'A' ) ++aCnt; else if ( ch == 'e' || ch == 'E' ) ++eCnt; else if ( ch == 'i' || ch == 'I' ) ++iCnt; else if ( ch == 'o' || ch == '0' ) ++oCnt; else if ( ch == 'u' || ch == 'U' ) |
(a) if ( ivall != iva12 ) ivall = iva12 else ivall = iva12 = 0; (b) if ( ivat < minval ) minvat = ival; occurs = 1; (c) if ( int ival = get_value()) cout << "ival = " << ival << endl; if ( ! ival ) cout << "ival = 0\n"; (d) if ( ival = 0 ) ival = get_value(); (e) if ( iva1 == 0 ) |
char ch; while ( cm >> ch ) |
case 'a': case 'e': case 'i': case 'o': |
default: // любой символ, не являющийся гласной |
// неверные значения меток case 3.14: // не целое |
#include int main() { char ch; int aCnt=0, eCnt=0, iCnt=0, oCnt=0, uCnt=0; while ( cin >> ch ) // Внимание! неверная реализация! switch ( ch ) { case 'a': ++aCnt; case 'e': ++eCnt; case 'i': ++iCnt; case 'o': ++oCnt; case 'u': ++uCnt; } cout << "Встретилась a: \t" << aCnt << '\n' << "Встретилась e: \t" << eCnt << '\n' << "Встретилась i: \t" << iCnt << '\n' << "Встретилась o: \t" << oCnt << '\n' << "Встретилась u: \t" << uCnt << '\n'; |
switch ( ch ) { case 'a': ++aCnt; break; case 'e': ++eCnt; break; case 'i': ++iCnt; break; case 'o': ++oCnt; break; case 'u': ++uCnt; break; |
int vowelCnt = 0; // ... switch ( ch ) { // любой из символов a,e,1,o,u // увеличит значение vowelCnt case 'a': case 'e': case 'i': case 'o': case 'u': ++vowe1Cnt; break; |
switch ( ch ) { // допустимый синтаксис case 'a': case 'e': case 'i': case 'o': case 'u': ++vowe1Cnt; break; |
switch ( ch ) { case 'a': case 'A': ++aCnt; break; case 'e': case 'E': ++eCnt; break; case 'i': case 'I': ++iCnt; break; case 'o': case 'O': ++oCnt; break; case 'u': case 'U': ++uCnt; break; |
#include #include int main() { char ch; int aCnt=0, eCnt=0, iCnt=0, oCnt=0, uCnt=0, consonantCount=0; while ( cin >> ch ) switch ( ch ) { case 'a': case 'A': ++aCnt; break; case 'e': case 'E': ++eCnt; break; case 'i': case 'I': ++iCnt; break; case 'o': case 'O': ++oCnt; break; case 'u': case 'U': ++uCnt; break; default: if ( isa1pha( ch ) ) ++consonantCnt; break; } cout << "Встретилась a: \t" << aCnt << '\n' << "Встретилась e: \t" << eCnt << '\n' << "Встретилась i: \t" << iCnt << '\n' << "Встретилась o: \t" << oCnt << '\n' << "Встретилась u: \t" << uCnt << '\n' << "Встретилось согласных: \t" << consonantCnt << '\n'; |
case illegal_definition: // ошибка: объявление не может // употребляться в этом месте string file_name = get_file_name(); // ... |
case ok: { // ок string file_name = get_file_name(); // ... |
switch ( ival ) { case 'a': aCnt++; case 'e': eCnt++; default: iouCnt++; |
switch ( ival ) { case 1: int ix = get_value(); ivec[ ix ] = ival; break; default: ix = ivec.sizeQ-1; ivec[ ix ] = ival; |
switch ( ival ) { case 1, 3, 5, 7, 9: oddcnt++; break; case 2, 4, 6, 8, 10: evencnt++; break; |
int iva1=512 jva1=1024, kva1=4096; int bufsize; // ... switch( swt ) { case ival: bufsize = ival * sizeof( int ); break; case jval: bufsize = jval * sizeof( int ); break; case kval: bufsize = kval * sizeof( int ); break; |
enum { illustrator = 1, photoshop, photostyler = 2 }; switch ( ival ) { case illustrator: --i11us_1icense; break; case photoshop: --pshop_1icense; break; case photostyler: --psty1er_license; |
while ( условие ) |
bool quit = false; // ... while ( ! quit ) { // ... quit = do_something(); } string word; |
while ( symbol *ptr = search( name )) { // что-то сделать |
int sumit( int *parray_begin, int *parray_end ) { int sum = 0; if ( ! parray_begin || ! parray_end ) return sum; while ( parray_begin != parray_end ) // прибавить к sum // и увеличить указатель sum += *parray_begin++; return sum; } int ia[6] = { 0, 1, 2, 3, 4, 5 }; int main() { int sum = sumit( &ia[0], &ia[ 6 ] ); // ... |
(a) string bufString, word; while ( cin >> bufString >> word ) |
(b) while ( vector // ... (c) while ( ptr = 0 ) ptr = find_a_value(); (d) while ( bool status = find( word )) { word = get_next_word(); if ( word.empty() ) break; // ... } if ( ! status ) |
void iStack::push( int value ) { // если стек полон, увеличить размер вектора if ( full() ) _stack.resize( 2 * _stack.size() ); _stack[ _top++ ] = value; |
class popOnEmpty { ... }; |
class Excp { ... }; class popOnEmpty : public Excp { ... }; |
class Excp { public: // напечатать сообщение об ошибке static void print( string msg ) { cerr << msg << endl; } |
class Excp { ... }; class stackExcp : public Excp { ... }; class popOnEmpty : public stackExcp { ... }; |
class mathExcp : public Excp ( ... }; class zeroOp : public mathExcp { ... }; |
if ( !infile ) { string errMsg("Невозможно открыть файл: "); errMsg += fileName; throw errMsg; |
int* stats (const int *ia, int size) |
catch (string exceptionMsg) { // код обработчика |
catch (string exceptionMsg) { |
catch (...) { // обрабатывает любое исключение, // однако ему недоступен объект, переданный // в обработчик в инструкции throw |
#include #include typedef vector void process_vocab( vector { if ( ! pvec ) { // выдать предупредительное сообщение return; } // ...
| |
#include #include void process_vocab( vector { // ... vector< string > texts; vector for ( ; iter != pvec->end(); ++iter ) copy( (*iter).begin(), (*iter).end(), back_inserter( texts )); // ...
| |
void process_vocab( vector { // ... // отсортировать вектор texts sort( texts.begin(), texts.end() ); // удалить дубликаты vector it = unique( texts.begin(), texts.end() ); texts.erase( it, texts.end() ); // ... |
bool less_than( const string & s1, const string & s2 ) { return s1.size() < s1.size(); } void process_vocab( vector { // ... // отсортировать элементы вектора texts по длине, // сохранив также прежний порядок stable_sort( texts.begin(), texts.end(), less_than ); // ... |
// объект-функция - операция реализована с помощью перегрузки // оператора operator() class LessThan { public: bool operator()( const string & s1, const string & s2 ) { return s1.size() < s2.size(); } |
string st1( "shakespeare" ); string st2( "marlowe" ); // вызывается lt.operator()( st1, st2 ); |
void process_vocab( vector { // ... stable_sort( texts.begin(), texts.end(), LessThan() ); // ... |
#include class GreaterThan { public: GreaterThan( int size = 6 ) : _size( size ){} int size() { return _size; } bool operator()( const string & s1 ) { return s1.size() > 6; } private: int _size; |
void process_vocab( vector { // ... // подсчитать число строк, длина которых больше 6 int cnt = count_if( texts.begin(), texts.end(), GreaterThan() ); cout << "Number of words greater than length six are " << cnt << endl; // ... |
void process_vocab( vector { // ... static string rw[] = { "and", "if", "or", "but", "the" }; vector< string > remove_words( rw, rw+5 ); vector< string >::iterator it2 = remove_words.begin(); for ( ; it2 != remove_words.end(); ++it2 ) { // просто для демонстрации другой формы count() int cnt = count( texts.begin(), texts.end(), *it2 ); cout << cnt << " instances removed: " << (*it2) << endl; texts.erase( remove(texts.begin(),texts.end(),*it2 ), texts.end() ); } // ... |
class PrintElem { public: PrintElem( int lineLen = 8 ) : _line_length( lineLen ), _cnt( 0 ) {} void operator()( const string &elem ) { ++_cnt; if ( _cnt % _line_length == 0 ) { cout << '\n'; } cout << elem << " "; } private: int _line_length; int _cnt; |
void process_vocab( vector { // ... for_each( texts.begin(), texts.end(), PrintElem() ); |
#include #include #include #include // предшествующий принятию стандарта синтаксис #include class GreaterThan { public: GreaterThan( int size = 6 ) : _size( sz ){} int size() { return _size; } bool operator()(const string &s1) { return s1.size() > _size; } private: int _size; }; class PrintElem { public: PrintElem( int lineLen = 8 ) : _line_length( lineLen ), _cnt( 0 ) {} void operator()( const string &elem ) { ++_cnt; if ( _cnt % _line_length == 0 ) { cout << '\n'; } cout << elem << " "; } private: int _line_length; int _cnt; |
class LessThan { public: bool operator()( const string & s1, const string & s2 ) { return s1.size() < s2.size(); } }; typedef vector void process_vocab( vector { if ( ! pvec ) { // вывести предупредительное сообщение return; } vector< string, allocator > texts; vector for ( iter = pvec->begin() ; iter != pvec->end(); ++iter ) copy( (*iter).begin(), (*iter).end(), back_inserter( texts )); // отсортировать вектор texts sort( texts.begin(), texts.end() ); // теперь посмотрим, что получилось for_each( texts.begin(), texts.end(), PrintElem() ); cout << "\n\n"; // разделить части выведенного текста // удалить дубликаты vector it = unique( texts.begin(), texts.end() ); texts.erase( it, texts.end() ); // посмотрим, что осталось for_each( texts.begin(), texts.end(), PrintElem() ); cout << "\n\n"; // отсортировать элементы // stable_sort сохраняет относительный порядок равных элементов stable_sort( texts.begin(), texts.end(), LessThan() ); for_each( texts.begin(), texts.end(), PrintElem() ); cout << "\n\n"; // подсчитать число строк, длина которых больше 6 int cnt = 0; // устаревшая форма count - в стандарте используется другая count_if( texts.begin(), texts.end(), GreaterThan(), cnt ); cout << "Number of words greater than length six are " << cnt << endl; static string rw[] = { "and", "if", "or", "but", "the" }; vector vector for ( ; it2 != remove_words.end(); ++it2 ) { int cnt = 0; // устаревшая форма count - в стандарте используется другая count( texts.begin(), texts.end(), *it2, cnt ); cout << cnt << " instances removed: " << (*it2) << endl; texts.erase( remove(texts.begin(),texts.end(),*it2), texts.end() ); } cout << "\n\n"; for_each( texts.begin(), texts.end(), PrintElem() ); } // difference_type - это тип, с помощью которого можно хранить результат // вычитания двух итераторов одного и того же контейнера // - в данном случае вектора строк ... // обычно это предполагается по умолчанию typedef vector // предшествующий принятию стандарта синтаксис для #include main() { vector vector string t1fn, t2fn; // запросить у пользователя имена входных файлов ... // в реальной программе надо бы выполнить проверку cout << "text file #1: "; cin >> t1fn; cout << "text file #2: "; cin >> t2fn; // открыть файлы ifstream infile1( t1fn.c_str()); ifstream infile2( t2fn.c_str()); // специальная форма итератора // обычно diff_type подразумевается по умолчанию ... istream_iterator< string, diff_type > input_set1( infile1 ), eos; istream_iterator< string, diff_type > input_set2( infile2 ); // специальная форма итератора copy( input_set1, eos, back_inserter( t1 )); copy( input_set2, eos, back_inserter( t2 )); sample.push_back( t1 ); sample.push_back( t2 ); process_vocab( &sample ); |
namespace Cplusplus_Primer_3E { template
| |
Cplusplus_Primer_3E::Array |
#include |
namespace Exercize { |
int main() { |
template class Array { public: explicit Array( int sz = DefaultArraySize ); Array( const elemType *ar, int sz ); Array( const Array &iA ); virtual ~Array() { delete[] _ia; } Array& operator=( const Array & ); int size() const { return _size; } virtual elemType& operator[]( int ix ) { return _ia[ix]; } virtual void sort( int,int ); virtual int find( const elemType& ); virtual elemType min(); virtual elemType max(); protected: void init( const elemType*, int ); void swap( int, int ); static const int DefaultArraySize = 12; int _size; elemType *_ia;
| |
#include #include "Array.h" int main() { const int array_size = 4; // elemType заменяется на int Array // elemType заменяется на double Array // elemType заменяется на char Array int ix; for ( ix = 0; ix < array_size; ++ix ) { ia[ix] = ix; da[ix] = ix * 1.75; ca[ix] = ix + 'a'; } for ( ix = 0; ix < array_size; ++ix ) cout << "[ " << ix << " ] ia: " << ia[ix] << "\tca: " << ca[ix] << "\tda: " << da[ix] << endl; return 0; |
Array |
// Array |
#include |
// функцию swap() тоже следует сделать шаблоном |
#include "Array.h" |
#include |
template |
(a) Array< int*& > pri(1024); (b) Array< Array (c) Array< complex< double > > acd(1024); (d) Array< Status > as(1024); |
class example1 { public: example1 (double min, double max); example1 (const double *array, int size); double& operator[] (int index); bool operator== (const example1&) const; bool insert (const double*, int); bool insert (double); double min (double) const { return _min; }; double max (double) const { return _max; }; void min (double); void max (double); int count (double value) const; private: int size; double *parray; double _min; double _max; |
template |
(a) Example2 (b) ex1.min (&ex1); (c) Example2 (d) sa = sb; (e) Example2 |
#include #include #include #include // прочитать последовательность объектов типа complex // из стандартного ввода istream_iterator< complex > is_complex( cin ); // прочитать последовательность строк из именованного файла ifstream infile( "C++Primer" );
| |
// конструирует итератор end_of_stream, который будет служить маркером // конца потока в итераторной паре istream_iterator< string > end_of_stream vector // правильно: передаем пару итераторов copy( is_string, end_of_stream, inserter( text, text.begin() ));
| |
ostream_iterator
| |
#include #include #include #include // записать последовательность объектов типа complex // в стандартный вывод, разделяя элементы пробелами ostream_iterator< complex > os_complex( cin, " " ); // записать последовательность строк в именованный файл ofstream outfile( "dictionary" );
| |
#include #include #include int main() { copy( istream_iterator< int >( cin ), istream_iterator< int >(), ostream_iterator< int >( cout, " " ));
| |
#include #include #include #include main() { string file_name; cout << "please enter a file to open: "; cin >> file_name; if ( file_name.empty() || !cin ) { cerr << "unable to read file name\n"; return -1; } ifstream infile( file_name.c_str()); if ( !infile ) { cerr << "unable to open " << file_name << endl; return -2; } istream_iterator< string > ins( infile ), eos; ostream_iterator< string > outs( cout, " " ); copy( ins, eos, outs );
| |
int ia[] = { 0, 1, 1, 2, 3, 5, 5, 8 }; vector< int > ivec( ia, ia+8 ), vres; // ... // поведение программы во время выполнения не определено |
// правильно: теперь unique_copy() вставляет элементы с помощью // vres.push_back()... unique_copy( ivec.begin(), ivec.end(), |
// увы, ошибка: // класс vector не поддерживает операцию push_front() // следует использовать контейнеры deque или list unique_copy( ivec.begin(), ivec.end(), |
unique_copy( ivec.begin(), ivec.end(), |
vector< int >::iterator iter = vres.begin(), iter2 = ivec.begin(); for ( ; iter2 != ivec.end() ++ iter, ++iter2 ) |
for ( iter = container. begin(); iter != container.end(); ++iter ) |
// vector vector
| |
for( ; iter != iter_end; ++iter ) |
#include void even_odd( const vector vector vector { // const_iterator необходим для навигации по pvec vector vector for ( ; c_iter != c_iter_end; ++c_iter ) if ( *c_iter % 2 ) pvec_even->push_back( *c_iter ); else pvec_odd->push_back( *c_iter );
| |
#include #include #include int main() { vector string intext; while ( cin >> intext ) svec.push_back( intext ); // обработать svec ... |
int main() { vector // ... // инициализация svec2 всеми элементами svec vector // инициализация svec3 первой половиной svec vector svec.begin() + svec.size()/2; vector // ... |
#include #include #include int mainQ { // привязка istream_iterator к стандартному вводу istream_iterator // istream_iterator, отмечающий конец потока istream_iterator // инициализация svec элементами, считываемыми из cin; vector // ... |
#include string words[4] = { "stately", "plump", "buck", "mulligan" |
int ia[6] = { 0, 1, 2, 3, 4, 5 }; |
const vector< int > ivec; vector< string > svec; list< int > ilist; (a) vector (b) list (c) vector (d) for ( vector it = svec.begin(); it != 0; ++it ) |
int ia[7] = { 0, 1, 1, 2, 3, 5, 8 }; string sa[6] = { "Fort Sumter", "Manassas", "Perryville", "Vicksburg", "Meridian", "Chancellorsvine" }; (a) vector (b) list (c) list (d) vector (e) list |
// обобщенное определение шаблона template T max( T t1, T t2 ) { return ( t1 > t2 ? t1 : t2 );
| |
#include // явная специализация для const char*: // имеет приоритет над конкретизацией шаблона // по обобщенному определению typedef const char *PCC; template<> PCC max< PCC >( PCC s1, PCC s2 ) {
| |
#include // здесь должно быть определение шаблона функции max() // и его специализации для аргументов const char* int main() { // вызов конкретизированной функции: int max< int >( int, int ); int i = max( 10, 5 ); // вызов явной специализации: // const char* max< const char* >( const char*, const char* ); const char *p = max( "hello", "world" ); cout << "i: " << i << " p: " << p << endl; return 0; |
// объявление явной специализации шаблона функции |
// ошибка: неправильные объявления специализации // отсутствует template<> PCC max< PCC >( PCC, PCC ); // отсутствует список параметров |
// правильно: аргумент шаблона const char* выводится из типов параметров |
template T1 sum( T2 op1, T3 op2 ); // объявления явных специализаций // ошибка: аргумент шаблона для T1 не может быть выведен; // он должен быть задан явно template<> double sum( float, float ); // правильно: аргумент для T1 задан явно, // T2 и T3 выводятся и оказываются равными float template<> double sum // правильно: все аргументы заданы явно |
// обобщенное определение шаблона template T max( T t1, T t2 ) { /* ... */ } // правильно: обычное объявление функции |
#include #include // обобщенное определение шаблона template T max( T t1, T t2 ) { /* ... */ } int main() { // конкретизация функции // const char* max< const char* >( const char*, const char* ); const char *p = max( "hello", "world" ); cout << "p: " << p << endl; return 0; } // некорректная программа: явная специализация const char *: // имеет приоритет над обобщенным определением шаблона typedef const char *PCC; |
// --------- max.h ------- // обобщенное определение шаблона template Type max( Type t1, Type t2 ) { /* ... */ } // --------- File1.C ------- #include #include "max.h" void another(); int main() { // конкретизация функции // const char* max< const char* >( const char*, const char* ); const char *p = max( "hello", "world" ); cout << "p: " << p << endl; another(); return 0; } // --------- File2.C ------- #include #include #include "max.h" // явная специализация шаблона для const char* typedef const char *PCC; template<> PCC max< PCC >( PCC s1, PCC s2 ) { /* ... */ } void another() { // явная специализация // const char* max< const char* >( const char*, const char* ); const char *p = max( "hi", "again" ); cout << " p: " << p << endl; return 0; |
// --------- max.h ------- // обобщенное определение шаблона template Type max( Type t1, Type t2 ) { /* ... */ } // объявление явной специализации шаблона для const char* typedef const char *PCC; template<> PCC max< PCC >( PCC s1, PCC s2 ); // --------- File1.C ------- #include #include "max.h" void another(); int main() { // специализация // const char* max< const char* >( const char*, const char* ); const char *p = max( "hello", "world" ); // .... |
int iva1; int *pi = 0; char *pc = 0; void *pv; pv = pi; // правильно: неявное преобразование pv = pc; // правильно: неявное преобразование const int *pci = &iva1; pv = pci; // ошибка: pv имеет тип, отличный от const void*; |
#inc1ude int ival = 1024; void *pv; int *pi = &iva1; const char *pc = "a casting call"; void mumble() { pv = pi; // правильно: pv получает адрес ival pc = pv; // ошибка: нет стандартного преобразования char *pstr = new char[ str1en( pc )+1 ]; strcpy( pstr, pc );
| |
void mumble 0 { // правильно: программа по-прежнему содержит ошибку, // но теперь она компилируется! // Прежде всего нужно проверить // явные преобразования типов... pc = static_cast< char* >( pv ); char *pstr = new char[ str1en( pc )+1 ]; // скорее всего приведет к краху strcpy( pstr, pc ); |
double dval; int iva1; |
extern char *string_copy( char* ); const char *pc_str; |
double d = 97.0; |
enum mumble { first = 1, second, third }; extern int ival; |
complex |
// конкретизируется min5( unsigned int, unsigned int ) |
// каким должен быть тип возвращаемого значения: T или U template |
char ch; unsigned int ui; // ни T, ни U нельзя использовать в качестве типа возвращаемого значения sum( ch, ui ); // правильно: U sum( T, U ); |
// T1 не появляется в списке параметров шаблона функции template |
typedef unsigned int ui_type; ui_type calc( char ch, ui_type ui ) { // ... // ошибка: невозможно вывести T1 ui_type loc1 = sum( ch, ui ); // правильно: аргументы шаблона заданы явно // T1 и T3 - это unsigned int, T2 - это char ui_type loc2 = sum< ui_type, ui_type >( ch, ui ); |
// правильно: T3 - это unsigned int // T3 выведен из типа ui ui_type loc3 = sum< ui_type, char >( ch, ui ); // правильно: T2 - это char, T3 - unsigned int // T2 и T3 выведены из типа pf ui_type (*pf)( char, ui_type ) = &sum< ui_type >; // ошибка: опускать можно только “хвостовые” аргументы |
template T1 sum( T2 op1, T3 op2 ) { /* ... */ } void manipulate( int (*pf)( int,char ) ); void manipulate( double (*pf)( float,float ) ); int main() { // ошибка: какой из возможных экземпляров sum: // int sum( int,char ) или double sum( float, float )? manipulate( &sum ); // берется адрес конкретизированного экземпляра // double sum( float, float ) // вызывается: void manipulate( double (*pf)( float, float ) ); manipulate( &sum< double, float, float > ); |
template |
double dobj1, dobj2; float fobj1, fobj2; char cobj1, cobj2; (a) sum( dobj1, dobj2 ); (b) sum (c) sum |
template Type sum( Type op1, Type op2 ) { /* ... */ } // явное объявление конкретизации
| |
#include template Type sum( Type op1, int op2 ); // только объявление // определяем typedef для vector< int > typedef vector< int > VI; // ошибка: sum() не определен
| |
// плохо: не только вызывает деструктор, но и освобождает память |
// деструктор не вызывается |
#include #inclnde #include #include |
vector< string > svec; |
if ( svec.empty() != true ) |
string text_word; while ( cin >> text_word ) |
for ( int ix=0; ix<4; ++ix ) |
for ( int ix=0; ix<4; ++ix ) |
#include #include #include extern int get_word_count( string file_name ); const int list_size = 64; list< int > ilist( list_size );
| |
list< int > ilist( list_size, -1 ); |
// каждый новый элемент получает значение "piglet" |
vector< string > svec2( svec ); |
#include #include #include #int main() { vector svec.reserve( 1024 ); string text_word; while ( cin >> text_word ) svec.push_back( text_word ); svec.resize( svec.size()+svec.size()/2 ); // ... |
(a) class cl1 { public: c11( int=0 ); bool operator==(); bool operator!=(); bool operator<=(); bool operator<(); // ... }; (b) class c12 { public: c12( int=0 ); bool operator!=(); bool operator<=(); // ... }; (с) class c13 { public: int ival; }; (d) class c14 { public: c14( int, int=0 ); bool operator==(); bool operator!=(); // ... |
int max ( int, int ); int max( const vector
| |
// перегруженные функции void print( const string & ); |
// объявления одной и той же функции void print( const string &str ); |
unsigned int max( int i1, int i2 ); int max( int i1, int i2 ); // ошибка: отличаются только типы |
// объявления одной и той же функции int max ( int *ia, int sz ); |
// typedef не вводит нового типа typedef double DOLLAR; // ошибка: одинаковые списки параметров, но разные типы // возвращаемых значений extern DOLLAR calc( DOLLAR ); |
// объявляют одну и ту же функцию void f( int ); |
// объявляются разные функции void f( int* ); void f( const int* ); // и здесь объявляются разные функции void f( int& ); |
#include #include int main() { vector< int > ivec; cout << "ivec: размер: " << ivec.size() << " емкость: " << ivec.capacity() << endl; for ( int ix = 0; -ix < 24; ++ix ) { ivec.push_back( ix ); cout << "ivec: размер: " << ivec.size() << " емкость: " << ivec.capacity() << endl; }
| |
|
Тип данных |
Размер в байтах |
Емкость после первой вставки |
|
int |
4 |
256 |
|
double |
8 |
128 |
|
простой класс #1 |
12 |
85 |
|
string |
12 |
85 |
|
большой простой класс |
8000 |
1 |
|
большой сложный класс |
8000 |
1 |
|
Тип данных |
List |
Vector |
|
int |
10.38 |
3.76 |
|
double |
10.72 |
3.95 |
|
простой класс |
12.31 |
5.89 |
|
string |
14.42 |
11.80 |
|
Тип данных |
List |
Vector |
|
большой простой класс |
0.36 |
2.23 |
|
большой сложный класс |
2.37 |
6.70 |
int main() { vector< string > svec; svec.reserve( 32 ); // задает емкость равной 32 // ... |
|
Емкость |
Время в секундах |
|
1 по умолчанию |
670 |
|
4,096 |
555 |
|
8,192 |
444 |
|
10,000 |
222 |
|
*Сложный класс размером 8000 байт с конструктором копирования и деструктором |
| Операция | Значение | Использование | |||
| test(pos) | Бит pos равен 1? | a.test(4) | |||
| any() | Хотя бы один бит равен 1? | a.any() | |||
| none() | Ни один бит не равен 1? | a.none() | |||
| count() | Количество битов, равных 1 | a.count() | |||
| size() | Общее количество битов | a.size() | |||
| [pos] | Доступ к биту pos | a[4] | |||
| flip() | Изменить значения всех | a.flip() | |||
| flip(pos) | Изменить значение бита pos | a.flip(4) | |||
| set() | Выставить все биты в 1 | a.set() | |||
| set(pos) | Выставить бит pos в 1 | a.set(4) | |||
| reset() | Выставить все биты в 0 | a.reset() | |||
| reset(pos) | Выставить бит pos в 0 | a.reset(4) |
for ( int index=0; index<32; ++index ) if ( index % 2 == 0 ) |
if ( bitvec.test( 0 )) |
cout << "bitvec: включенные биты:\n\t"; for ( int index = 0; index < 32; ++-index ) if ( bitvec[ index ] ) cout << index << " "; |
bitvec.reset(0); |
// сброс всех битов bitvec.reset(); if (bitvec.none() != true) // что-то не сработало // установить в 1 все биты вектора bitvec if ( bitvec.any() != true ) |
bitvec.f1ip( 0 ); // меняет значение первого бита bitvec[0].flip(); // тоже меняет значение первого бита |
// эквивалентно bitvec3 string bitva1( "1010" ); |
// подстрока с шестой позиции длиной 4: 1010 string bitval ( "1111110101100011010101" ); |
// подстрока с шестой позиции до конца строки: 1010101 string bitva1( "1111110101100011010101" ); |
extern void bitstring(const char*); bool bit_on (unsigned long, int); bitset<32> bitvec; (a) bitsting( bitvec.to_string().c_str() ); (b) if ( bit_on( bitvec.to_1ong(), 64 )) ... |
// чисто мнимое число: 0 + 7-i comp1ex< double > purei( 0, 7 ); // мнимая часть равна 0: 3 + Oi comp1ex< float > rea1_num( 3 ); // и вещественная, и мнимая часть равны 0: 0 + 0-i comp1ex< long double > zero; // инициализация одного комплексного числа другим |
complex< double > conjugate[ 2 ] = { complex< double >( 2, 3 ), complex< double >( 2, -3 ) |
complex< double > *ptr = &conjugate[0]; |
extern int parse_options( int arg_count, char *arg_vector ); int main( int argc, char *argv[] ) { // ... int option_status; option_status = parse_options( argc, argv ); // ... |
#include #include class CommandOpt { public: CommandOpt() : _limit( -1 ), _debug_on( false ) {} int parse_options( int argc, char *argv[] ); string out_file() { return _out_file; } bool debug_on() { return _debug_on; } int files() { return _file_names.size(); } string& operator[]( int ix ); private: inline void usage( int exit_value = 0 ); bool _debug_on; int _limit; string _out_file; vector static const char *const program_name; static const char *const program_version;
| |
#include "CommandOpt.h" int main( int argc, char "argv[] ) { // ... CommandOpt com_opt; int option_status; opttion_status = com_opt. parse_options (argc, argv); // ... |
#ifndef ARRAY_RC_S_H #define ARRAY_RC_S_H #include "Array_S.C" #include "Array_RC.C" template class Array_RC_S : public Array_RC public Array_Sort { public: Array_RC_S( int sz = Array : Array { clear_bit(); } Array_RC_S( const Array_RC_S &rca ) : Array { sort( 0,Array Array_RC_S( const Type* arr, int sz ) : Array { sort( 0,Array Type& operator[]( int index ) { set_bit(); return Array_RC } };
| |
string firstBook; if ( Joyce.first == "James" && Joyce.second == "Joyce" ) |
typedef pair< string, string > Authors; Authors proust( "marcel", "proust" ); Authors joyce( "James", "Joyce" ); |
class EntrySlot; extern EntrySlot* 1ook_up( string ); typedef pair< string, EntrySlot* > SymbolEntry; SymbolEntry current_entry( "author", 1ook_up( "author" )); // ... if ( EntrySlot *it = 1ook_up( "editor" )) { current_entry.first = "editor"; current_entry.second = it; |
char str = 0; //... if ( ! str || ! *str ) |
#include |
cout << "Длина " << st << ": " << st.size() << " символов, включая символ новой строки\n"; |
string s1( "hello" ); |
string str( "fa.disney.com" ); int size = str.size(); for ( int ix = 0; ix < size; ++ix ) if ( str[ ix ] == '.' ) |
(a) char ch = "The long and winding road"; (b) int ival = &ch; (c) char *pc = &ival; (d) string st( &ch ); (e) pc = 0; (i) pc = '0'; (f) st = pc; (j) st = &ival; (g) ch = pc[0]; (k) ch = *pc; |
while ( st++ ) |
// ***** Реализация с использованием C-строк ***** |
// ***** Реализация с использованием класса string ***** |
class type_info { // ïðåäñòàâëåíèå çàâèñèò îò ðåàëèçàöèè private: type_info( const type_info& ); type_info& operator= ( const type_info& ); public: virtual ~type_info(); int operator==( const type_info& ); int operator!=( const type_info& ); const char * name() const; |
#include type_info t1; // îøèáêà: íåò êîíñòðóêòîðà ïî óìîë÷àíèþ // îøèáêà: êîïèðóþùèé êîíñòðóêòîð çàêðûò
| |
typeid( re ) == typeid( manager ) // èñòèííî |
#include int main() { employee *pe = new manager; // ïå÷àòàåò: "manager" cout << typeid( *pe ).name() << endl; |
#include // Файл typeinfo содержит определение типа extended_type_info void func( employee* p ) { // понижающее приведение типа type_info* к extended_type_info* if ( eti *eti_p = dynamic_cast { // если dynamic_cast завершается успешно, // можно пользоваться информацией из extended_type_info через eti_p } else { // если dynamic_cast завершается неудачно, // можно пользоваться только стандартным type_info } |
class X { ... }; class A { ... }; class B : public A { ... }; class C : public B { ... }; |
(a) D *pd = new D; |
(b) A *pa = new C; |
(c) B *pb = new B; |
(d) A *pa = new D; |
if ( D *pd = dynamic_cast< D* >( pa ) ) { // использовать члены D } else { // использовать члены A |
class X { ... }; class A { ... }; class B : public A { ... }; class C : public B { ... }; |
(a) A *pa = new D; cout << typeid( pa ).name() << endl; (b) X *px = new D; cout << typeid( *px ).name() << endl; (c) C obj; A& ra = cobj; cout << typeid( &ra ).name() << endl; (d) X *px = new D; A& ra = *px; |
void simp1e_examp1e() { const int e1em_size = 10; vector< int > ivec( e1em_size ); int ia[ e1em_size ]; for ( int ix = 0; ix < e1em_size; ++ix ) ia[ ix ] = ivec[ ix ]; // ... |
void print_vector( vector { if ( ivec.empty() ) return; for ( int ix=0; ix< ivec.size(); ++ix ) cout << ivec[ ix ] << ' ';
| |
// 6 элементов ia копируются в ivec |
// копируются 3 элемента: ia[2], ia[3], ia[4] |
vector< string > svec; void init_and_assign() { // один вектор инициализируется другим vector< string > user_names( svec ); // ... // один вектор копируется в другой svec = user_names; |
string word; while ( cin >> word ) { text.push_back( word ); // ... |
cout << "считаны слова: \n"; for ( int ix =0; ix < text.size(); ++ix ) cout << text[ ix ] << ' '; |
cout << "считаны слова: \n"; for ( vector it != text.end(); ++it ) cout << *it << ' '; |
const int size = 7; int ia[ size ] = { 0, 1, 1, 2, 3, 5, 8 }; vector< int > ivec( size ); for ( int ix = 0; ix < size; ++ix ) |
int ia[ 7 ] = { 0, 1, 1, 2, 3, 5, 8 }; (a) vector< vector< int > > ivec; (b) vector< int > ivec = { 0, 1, 1, 2, 3, 5, 8 }; (c) vector< int > ivec( ia, ia+7 ); (d) vector< string > svec = ivec; |
bool is_equa1( const int*ia, int ia_size, |
namespace cplusplus_primer { class Node { /* ... */ }; } namespace DisneyFeatureAnimation { class Node { /* ... */ }; } Node *pnode; // ошибка: Node не видно в глобальной области видимости // правильно: объявляет nodeObj как объект // квалифицированного типа DisneyFeatureAnimation::Node DisneyFeatureAnimation::Node nodeObj; // using-объявление делает Node видимым в глобальной области видимости using cplusplus_primer::Node; |
// --- primer.h --- namespace cplusplus_primer { class List { // ... private: class ListItem { public: void check_status(); int action(); // ... }; }; } // --- primer.C --- #include "primer.h" namespace cplusplus_primer { // правильно: check_status() определено в том же пространстве имен, // что и List void List::ListItem::check_status() { } } // правильно: action() определена в глобальной области видимости // в пространстве имен, объемлющем определение класса List // Имя члена квалифицировано именем пространства |
int cplusplus_primer::List::ListItem::action() { int local = someVal; // ... |
// --- primer.h --- namespace cplusplus_primer { class List { // ... private: class ListItem { public: int action(); // ... }; }; const int someVal = 365; } // --- primer.C --- #include "primer.h" namespace cplusplus_primer { int List::ListItem::action() { // правильно: cplusplus_primer::someVal int local = someVal; // ошибка: calc() еще не объявлена double result = calc( local ); // ... } double calc(int) { } // ... |
// --- primer.h --- namespace cplusplus_primer { class List { // ... } const int someVal = 365; double calc(int); |
namespace LibException { class pushOnFull{ }; class popOnEmpty{ }; |
int main() { // ... myScreen.clear().move( 2, 2 ), set( '*' ). display(); bufScreen.reSize( 5, 5 ).display(); |
// объявление clear() находится в теле класса // в нем задан аргумент по умолчанию bkground = '#' Screen& Screen::clear( char bkground ) { // установить курсор в левый верхний угол и очистить экран _cursor = 0; _screen.assign( // записать в строку _screen.size(), // size() символов bkground // со значением bkground ); // вернуть объект, для которого была вызвана функция return *this; |
Screen& Screen::display() { typedef string::size_type idx_type; for ( idx_type ix = 0; ix < _height; ++ix ) { // для каждой строки idx_type offset = _width * ix; // смещение строки for ( idx_type iy = 0; iy < _width; ++iy ) // для каждой колонки вывести элемент cout << _screen[ offset + iy ]; cout << endl; } return *this; |
// объявление reSize() находится в теле класса // в нем задан аргумент по умолчанию bkground = '#' Screen& Screen::reSize( int h, int w, char bkground ) { // сделать высоту экрана равной h, а ширину - равной w // запомнить содержимое экрана string local(_screen); // заменить строку _screen _screen.assign( // записать в строку h * w, // h * w символов bkground // со значением bkground ); typedef string::size_type idx_type; idx_type local_pos = 0; // скопировать содержимое старого экрана в новый for ( idx_type ix = 0; ix < _height; ++ix ) { // для каждой строки idx_type offset = w * ix; // смещение строки for ( idx_type iy = 0; iy < _width; ++iy ) // для каждой колонки присвоить новое значение _screen[ offset + iy ] = local[ local_pos++ ]; } _height = h; _width = w; // _cursor не меняется return *this; |
void Screen::copy( const Screen& sobj ) { // если этот объект Screen и sobj - одно и то же, // копирование излишне if ( this != sobj ) { // скопировать значение sobj в this } |
classType& classType::assign( const classType &source ) { if ( this != &source ) { this->~classType(); new (this) classType( source ); } return *this; |
class Screen { public: // использование ключевого слова inline // для объявления встроенных функций-членов inline void home() { _cursor = 0; } inline char get() { return _screen[_cursor]; } // ... |
#include #include "screen.h" // имя функции-члена квалифицировано именем Screen:: bool Screen::checkRange( int row, int col ) { // проверить корректность координат if ( row < 1 || row > _height || col < 1 || col > _width ) { cerr << "Screen coordinates ( " << row << ", " << col << " ) out of bounds.\n"; return false; } return true;
| |
inline void Screen::move( int r, int c ) { // переместить курсор в абсолютную позицию if ( checkRange( r, c ) ) // позиция на экране задана корректно? { int row = (r-1) * _width; // смещение начала строки _cursor = row + c - 1; } |
class Screen { public: inline char get( int, int ); // объявления других функций-членов не изменяются |
char Screen::get( int r, int c ) { move( r, c ); // устанавливаем _cursor return get(); // вызываем другую функцию-член get() |
void setDate( Date&, int, int, int ); Date &convertDate( const string & ); |
#include class Date { public: set( int, int, int ); Date& convert( const string & ); void print(); // ...
| |
Screen& moveHome(); Screen& moveAbs( int, int ); Screen& moveRel( int, int, char *direction ); Screen& moveX( int ); |
// функция, объединяющая moveX() и moveY() |
// какой вызов понятнее? myScreen.home(); // мы считаем, что этот! |
moveAbs(int, int); |
// ошибка: арифметические операции над итераторами // не поддерживаются списком |
class ZooAnimal { public: // ... const Endangered* Endangered() const; void addEndangered( Endangered* ); void removeEndangered(); // ... protected: Endangered *_endangered; // ... |
class DisplayManager { ... }; class DisplayUNIX : public DisplayManager { ... }; |
(a) Queue : List // очередь : список (b) EncryptedString : String // зашифрованная строка : строка (c) Gif : FileFormat (d) Circle : Point // окружность : точка (e) Dqueue : Queue, List |
// определение шаблона функции min() // с параметром-типом Type и параметром-константой size template Type min( Type (&r_array)[size] ) { Type min_val = r_array[0]; for ( int i = 1; i < size; ++i ) if ( r_array[i] < min_val ) min_val = r_array[i]; return min_val; } // size не задан -- ok // size = число элементов в списке инициализации int ia[] = { 10, 7, 14, 3, 25 }; double da[6] = { 10.2, 7.1, 14.5, 3.2, 25.0, 16.8 }; #include int main() { // конкретизация min() для массива из 5 элементов типа int // подставляется Type => int, size => 5 int i = min( ia ); if ( i != 3 ) cout << "??oops: integer min() failed\n"; else cout << "!!ok: integer min() worked\n"; // конкретизация min() для массива из 6 элементов типа double // подставляется Type => double, size => 6 double d = min( da ); if ( d != 3.2 ) cout << "??oops: double min() failed\n"; else cout << "!!ok: double min() worked\n"; return 0;
| |
int min( int (&r_array)[5] ) { int min_val = r_array[0]; for ( int i = 1; i < 5; ++i ) if ( r_array[i] < min_val ) min_val = r_array[i]; return min_val; |
template Type min( Type (&p_array)[size] ) { /* ... */ } // pf указывает на int min( int (&)[10] ) |
template Type min( Type (&r_array)[size] ) { /* ... */ } typedef int (&rai)[10]; typedef double (&rad)[20]; void func( int (*)(rai) ); void func( double (*)(rad) ); int main() { // ошибка: как конкретизировать min()? func( &min ); |
min( int (*)(int(&)[10]) ) |
int main() { // правильно: с помощью явного приведения указывается тип аргумента func( static_cast< double(*)(rad) >(&min) ); |
template class Queue { public: Queue() : front( 0 ), back ( 0 ) { } ~Queue(); int& remove(); void add( const int & ); bool is_empty() const { return front == 0; } private: QueueItem QueueItem
| |
// типы возвращаемого значения и обоих параметров конкретизированы из // шаблона класса Queue extern Queue< complex foo( Queue< complex // указатель на функцию- член класса, конкретизированного из шаблона Queue bool (Queue // явное приведение 0 к указателю на экземпляр Queue |
extern Queue Queue Queue int main() { int ix; if ( ! pqi->is_empty() ) ix = pqi->remove(); // ... for ( ix = 0; ix < 1024; ++ix ) eqd[ ix ].add( ix ); // ... |
// объявление шаблона функции template void bar( Queue Queue |
void foo( Queue { Queue // ... |
class Matrix; Matrix *pm; // правильно: определение класса Matrix знать необязательно |
// Queue void foo( Queue { Queue // ... |
class Matrix; Matrix obj1; // ошибка: класс Matrix не определен class Matrix { ... }; |
void foo( Queue { Queue // Queue pqi->add( 255 ); // ... |
template class Queue { public: // ... private: QueueItem QueueItem |
template class QueueItem { public: QueueItem( Type ); // неудачное проектное решение // ... |
template class QueueItem { // ... public: // потенциально неэффективно QueueItem( const Type &t ) { item = t; next = 0; } |
template class QueueItem { // ... public: // item инициализируется в списке инициализации членов конструктора QueueItem( const Type &t ) : item(t) { next = 0; } |
class NameQuery : public Query { public: // ... protected: bool _present; string _name; |
inline NameQuery:: NameQuery( const string &name ) : _name( name ), _present( false ) |
inline NameQuery:: NameQuery( const string &name, vector : _name( name ), Query( *ploc ), _present( true )
| |
class Query { public: // ... protected: set vector // ...
| |
inline Query:: Query( const vector< locaton > &loc ) : _solution( 0 ), _loc( loc ) |
class Query { public: // ... protected: Query(); // ... |
class Query { public: // ... protected: Query(); // ... private: explicit Query( const vector
| |
extern void calc( SmallInt ); int i; // необходимо преобразовать i в значение типа SmallInt // это достигается применением SmallInt(int) |
// Псевдокод на C++ // создается временный объект типа SmallInt { SmallInt temp = SmallInt( i ); calc( temp ); |
class Number { public: // создание значения типа Number из значения типа SmallInt Number( const SmallInt & ); // ... |
extern void func( Number ); SmallInt si(87); int main() { // вызывается Number( const SmallInt & ) func( si ); // ... |
extern void calc( SmallInt ); double dobj; // вызывается ли SmallInt(int)? Да // dobj преобразуется приводится от double к int // стандартным преобразованием |
class Number { public: // никогда не использовать для неявных преобразований explicit Number( const SmallInt & ); // ... |
extern void func( Number ); SmallInt si(87); int main() { // ошибка: не существует неявного преобразования из SmallInt в Number func( si ); // ... |
SmallInt si(87); int main() { // ошибка: не существует неявного преобразования из SmallInt в Number func( si ); func( Number( si ) ); // правильно: приведение типа func( static_cast< Number >( si ) ); // правильно: приведение типа |
class Account { public: // конструктор по умолчанию ... Account(); // ... private: char *_name; unsigned int _acct_nmbr; double _balance; |
// ошибки: у конструктора не может быть типа возвращаемого значения void Account::Account() { ... } |
class Account { public: // конструктор по умолчанию ... Account(); // имена параметров в объявлении указывать необязательно Account( const char*, double=0.0 ); const char* name() { return name; } // ... private: // ... |
int main() { // правильно: в обоих случаях вызывается конструктор // с двумя параметрами Account acct( "Ethan Stern" ); Account *pact = new Account( "Michael Lieberman", 5000 ); if ( strcmp( acct.name(), pact->name() )) // ... |
// псевдокод на C++, // иллюстрирующий внутреннюю вставку конструктора int main() { Account acct; acct.Account::Account("Ethan Stern", 0.0); // ... |
// псевдокод на C++, // иллюстрирующий внутреннюю вставку конструктора при обработке new int main() { // ... Account *pact; try { pact = _new( sizeof( Account )); pact->Acct.Account::Account( "Michael Liebarman", 5000.0); } catch( std::bad_alloc ) { // оператор new закончился неудачей: // конструктор не вызывается } // ... |
// в общем случае эти формы эквивалентны Account acct1( "Anna Press" ); Account acct2 = Account( "Anna Press" ); |
// рекомендуемая форма вызова конструктора |
// увы! работает не так, как ожидалось |
// ошибка компиляции ... |
// определяет функцию newAccount, // а не объект класса |
// правильно: определяется объект класса ... |
class Account { public: // имена параметров в объявлении указывать необязательно Account( const char*, double=0.0 ); const char* name() { return name; } // ... private: // ... |
// ошибка: требуется конструктор по умолчанию для класса Account |
// конструктор по умолчанию для класса Account inline Account:: Account() { _name = 0; _balance = 0.0; _acct_nmbr = 0; |
// конструктор по умолчанию класса Account с использованием // списка инициализации членов inline Account:: Account() : _name(0), _balance( 0.0 ), _acct_nmbr( 0 ) |
inline Account:: Account( const char* name, double opening_bal ) : _balance( opening_bal ) { _name = new char[ strlen(name)+1 ]; strcpy( _name, name ); _acct_nmbr = get_unique_acct_nmbr(); |
class Account { public: Account() const; // ошибка Account() volatile; // ошибка // ... |
// в каком-то заголовочном файле extern void print( const Account &acct ); // ... int main() { // преобразует строку "oops" в объект класса Account // с помощью конструктора Account::Account( "oops", 0.0 ) print( "oops" ); // ... |
class Account { public: explicit Account( const char*, double=0.0 ); |
// все это конструкторы по умолчанию Account::Account() { ... } iStack::iStack( int size = 0 ) { ... } |
int main() { Account acct; // ... |
class Account { public: char *_name; unsigned int _acct_nmbr; double _balance; |
// статический класс хранения // вся ассоциированная с объектом память обнуляется Account global_scope_acct; static Account file_scope_acct; Account foo() { static Account local_static_acct; // ... |
// локальные и распределенные из хипа объекты не инициализированы // до момента явной инициализации или присваивания Account bar() { Account local_acct; Account *heap_acct = new Account; // ... |
class NameQuery : public Query { public: explicit NameQuery( const string& ); NameQuery( const string&, const vector // ... protected: // ...
| |
inline NameQuery:: NameQuery( const string &name ) // Query::Query() вызывается неявно : _name( name ) |
inline NameQuery:: NameQuery( const string &name, vector : _name( name ), Query( *ploc )
| |
string title( "Alice" ); NameQuery *pname; // проверим, встречается ли "Alice" в отображении слов // если да, получить ассоциированный с ним вектор позиций if ( vector pname = new NameQuery( title, ploc );
| |
inline NotQuery:: NotQuery( Query *op = 0 ) : _op( op ) {} inline OrQuery:: OrQuery( Query *lop = 0, Query *rop = 0 ) : _lop( lop ), _rop( rop ) {} inline AndQuery:: AndQuery( Query *lop = 0, Query *rop = 0 ) : _lop( lop ), _rop( rop ) |
int main() { try { // тело функции main() } catch ( pushOnFull ) { // ... } catch ( popOnEmpty ) { // ... |
имя_класса( список_параметров ) // список инициализации членов: : член1(выражение1 ) , // инициализация член1 член2(выражение2 ) , // инициализация член2 // тело функции: |
inline Account:: Account( const char* name, double opening_bal ) : _balance( opening_bal - ServiceCharge() ) { _name = new char[ strlen(name) + 1 ]; strcpy( _name, name ); _acct_nmbr = get_unique_acct_nmbr(); |
inline Account:: Account( const char* name, double opening_bal ) : _balance( opening_bal - ServiceCharge() ) { try { _name = new char[ strlen(name) + 1 ]; strcpy( _name, name ); _acct_nmbr = get_unique_acct_nmbr(); } catch (...) { // специальная обработка // не перехватывает исключения, // возбужденные в списке инициализации членов } |
inline Account:: Account( const char* name, double opening_bal ) try : _balance( opening_bal - ServiceCharge() ) { _name = new char[ strlen(name) + 1 ]; strcpy( _name, name ); _acct_nmbr = get_unique_acct_nmbr(); |
catch (...) { // теперь специальная обработка // перехватывает исключения, // возбужденные в ServiceCharge() |
#include |
#include |
#include |
#include #include typedef multimap< string, string >::iterator iterator; pair< iterator, iterator > pos; string search_item( "Kazuo Ishiguro" ); // authors - multimap // эквивалентно // authors.erase( search_item ); pos = authors.equa1_range( search_item ); |
typedef multimap multimap // первый элемент с ключом Barth authors.insert( valType ( string( "Barth, John" ), string( "Sot-Weed Factor" ))); // второй элемент с ключом Barth authors.insert( va1Type( string( "Barth, John" ), |
#include "SmallInt.h" typedef char *tName; class Token { public: Token( char *, int ); operator SmallInt() { return val; } operator tName() { return name; } operator int() { return val; } // другие открытые члены private: SmallInt val; char *name; |
#include "Token.h" void print( int i ) { cout << "print( int ) : " << i << endl; } Token t1( "integer constant", 127 ); Token t2( "friend", 255 ); int main() { print( t1 ); // t1.operator int() print( t2 ); // t2.operator int() return 0; |
print( int ) : 127 |
operator int( SmallInt & ); // ошибка: не член class SmallInt { public: int operator int(); // ошибка: задан тип возвращаемого значения operator int( int = 0 ); // ошибка: задан список параметров // ... |
#include "Token.h" Token tok( "function", 78 ); // функциональная нотация: вызывается Token::operator SmallInt() SmallInt tokVal = SmallInt( tok ); // static_cast: вызывается Token::operator tName() |
#include "Token.h" Token tok( "function", 78 ); char *tokName = tok; // правильно: неявное преобразование |
typedef const char *cchar; class Token { public: operator cchar() { return name; } // ... }; // ошибка: преобразование char* в const char* не допускается char *pn = tok; |
class Token { public: Token( string, int ); operator SmallInt() { return val; } operator string() { return name; } operator int() { return val; } // другие открытые члены private: SmallInt val; string name; |
extern void calc( double ); Token tok( "constant", 44 ); // Вызывается ли оператор int()? Да // применяется стандартное преобразование int --> double |
extern void calc( int ); Token tok( "pointer", 37 ); // если Token::operator int() не определен, // то этот вызов приводит к ошибке компиляции |
class Date { public: // попробуйте догадаться, какой именно член возвращается! operator int(); private: int month, day, year; |
inline Account:: Account( const Account &rhs ) : _balance( rhs._balance ) { _name = new char[ strlen(rhs._name) + 1 ]; strcpy( _name, rhs._name ); // копировать rhs._acct_nmbr нельзя _acct_nmbr = get_unique_acct_nmbr(); |
class NoName { public: // здесь должны быть конструкторы // ... protected: char *pstring; int ival; double dval; |
class Account { public: Account(); explicit Account( const char*, double=0.0 ); // ... |
(a) Account acct; (b) Account acct2 = acct; (c) Account acct3 = "Rena Stern"; (d) Account acct4( "Anna Engel", 400.00 ); |
template < class ForwardIterator, class Type > ForwardIterator find( ForwardIterator first, ForwardIterator last, Type value ) { for ( ; first != last; ++first ) if ( value == *first ) return first; return last; |
#include #include int main() { int search_value; int ia[ 6 ] = { 27, 210, 12, 47, 109, 83 }; cout << "enter search value: "; cin >> search_value; int *presult = find( &ia[0], &ia[6], search_value ); cout << "The value " << search_value << ( presult == &ia[6] ? " is not present" : " is present" ) << endl; |
// искать только среди элементов ia[1] и ia[2] |
#include #include #include int main() { int search_value; int ia[ 6 ] = { 27, 210, 12, 47, 109, 83 }; vector cout << "enter search value: "; cin >> search_value; vector presult = find( vec.begin(), vec.end(), search_value ); cout << "The value " << search_value << ( presult == vec.end() ? " is not present" : " is present" ) << endl; |
#include #include #include int main() { int search_value; int ia[ 6 ] = { 27, 210, 12, 47, 109, 83 }; list cout << "enter search value: "; cin >> search_value; list presult = find( ilist.begin(), ilist.end(), search_value ); cout << "The value " << search_value << ( presult == ilist.end() ? " is not present" : " is present" ) << endl; |
// this is not a good idea |
(a) 'a', L'a', "a", L"a" (b) 10, 10u, 10L, 10uL, 012, 0*C |
(a) "Who goes with F\144rgus?\014" (b) 3.14e1L (c) "two" L"some" (d) 1024f (e) 3.14UL (f) "multiple line |
logical_and ires = intLess( ival1, ival2 );
| |
logical_or ires = intSub( ival1, ival2 );
| |
logical_not ires = IntNot( Ival1, Ival2 );
| |
const int notFound = -1; // глобальная область видимости int binSearch( const vector { // локальная область видимости: уровень #1 int low = 0; int high = vec.size() - 1; while ( low <= high ) { // локальная область видимости: уровень #2 int mid = ( low + high ) / 2; if ( val < vec[ mid ] ) high = mid - 1; else low = mid + 1; } return notFound; // локальная область видимости: уровень #1
| |
int binSearch( const vector { // локальная область видимости: уровень #1 int val; // ошибка: неверное переопределение val
| |
int low; int binSearch( const vector { // локальное объявление low // скрывает глобальное объявление int low = 0; // ... // low - локальная переменная while ( low <= high ) {//... } // ... |
for ( int index = 0; index < vecSize; ++index ) { // переменная index видна только здесь if ( vec[ index ] == someValue ) break; } // ошибка: переменная index не видна |
// представление компилятора { // невидимый блок int index = 0; for ( ; index < vecSize; ++index ) { // ... } |
int index = 0; for ( ; index < vecSize; ++index ) { // ... } // правильно: переменная index видна |
void fooBar( int *ia, int sz ) { for (int i=0; i for (int i=0; i for (int i=0; i |
if ( int *pi = getValue() ) { // pi != 0 -- *pi можно использовать здесь int result = calc(*pi); // ... } else { // здесь pi тоже видна // pi == 0 cout << "ошибка: getValue() завершилась неудачно" << endl; |
int ix = 1024; int ix() ; void func( int ix, int iy ) { int ix = 255; if (int ix=0) { int ix = 79; { int ix = 89; } } else { int ix = 99; } |
int ix = 1024; void func( int ix, int iy ) { ix = 100; for( int iy = 0; iy < 400; iy += 100 ) { iy += 100; ix = 300; } iy = 400; |
void foo( int val ) { class Bar { public: int barVal; class nested; // объявление вложенного класса обязательно }; // определение вложенного класса class Bar::nexted { // ... }; |
int a, val; void foo( int val ) { static int si; enum Loc { a = 1024, b }; class Bar { public: Loc locVal; // правильно int barVal; void fooBar ( Loc l = a ) { // правильно: Loc::a barVal = val; // ошибка: локальный объект barVal = ::val; // правильно: глобальный объект barVal = si; // правильно: статический локальный объект locVal = b; // правильно: элемент перечисления } }; // ... |
Account( "Piglet", 0.0 ); // первый элемент (Пятачок) Account( "Eeyore", 0.0 ); // второй элемент (Иа-Иа) |
Account pooh_pals[] = { Account( "Piglet", 1000.0 ), Account( "Eeyore", 1000.0 ), Account( "Tigger", 1000.0 ) |
Account pooh_pals[] = { Account( "Woozle", 10.0 ), // Бука Account( "Heffalump", 10.0 ), // Слонопотам Account(); |
Account pooh_pals[3] = { Account( "Woozle", 10.0 ), Account( "Heffalump", 10.0 ) |
// увы! это не совсем правильно |
// правильно: // показывает, что pact адресует массив |
// typedef делает объявление более понятным typedef int (*PFV)(); // typedef для указателя на функцию |
const int size = 10; PFV testCases[size]; int testResults[size]; void runtests() { for ( int i = 0; i < size; ++i ) // вызов через элемент массива testResults[ i ] = testCases[ i ](); |
int lexicoCompare( const string &, const string & ); int sizeCompare( const string &, const string & ); typedef int ( *PFI2S )( const string &, const string & ); PFI2S compareFuncs[2] = { lexicoCompare, sizeCompare |
compareFunc[ 0 ]; |
// эквивалентные вызовы pfCompare [ 0 ]( string1, string2 ); // сокращенная форма |
int ia[ 4 ][ 3 ] = { { 0, 1, 2 }, { 3, 4, 5 }, { 6, 7, 8 }, { 9, 10, 11 } |
int main() { const int rowSize = 4; const int colSize = 3; int ia[ rowSize ][ colSize ]; for ( int = 0; i < rowSize; ++i ) for ( int j = 0; j < colSize; ++j ) ia[ i ][ j ] = i + j j; |
void foo( parm_list, ... ); |
void f(); |
f( someValue ); |
(a) void print( int arr[][], int size ); (b) int ff( int a, int b = 0, int с = 0 ); |
(d) char *screenInit( int height = 24, int width, char background ); |
(a) char *screenInit( int height, int width, char background = ' ' ); char *screenInit( int height = 24, int width, char background ); (b) void print( int (*arr)[6], int size ); void print( int (*arr)[5], int size ); (c) void manip( int *pi, int first, int end = 0 ); |
void print( int arr[][5], int size ); void operate(int *matrix[7]); char *screenInit( int height = 24, int width = 80, |
(a) screenInit(); (b) int *matrix[5]; operate( matrix ); (c) int arr[5][5]; |
"put function declarations in header files" "use abstract container types instead of built-in arrays" "declare class parameters as references" "use reference to const types for invariant parameters" |
![]() |
![]() |
![]() |

// конструктор по умолчанию класса Bear вызывается до // êîíñòðóêòîðà êëàññà Endangered ñ äâóìÿ àðãóìåíòàìè ... Panda::Panda() : Endangered( Endangered::environment, Endangered::critical ) |
Error: ying_yang.print( cout ) -- ambiguous, one of Bear::print( ostream& ) |
Ошибка: ying_yang.print( cout ) -- неоднозначно, одна из Bear::print( ostream& ) |
extern void display( const Bear& ); extern void highlight( const Endangered& ); Panda ying_yang; display( ying_yang ); // ïðàâèëüíî highlight( ying_yang ); // ïðàâèëüíî extern ostream& operator<<( ostream&, const ZooAnimal& ); |
extern void display( const Bear& ); |
Panda ying_yang; |
|
class Bear : public ZooAnimal { public: virtual ~Bear(); virtual ostream& print( ostream& ) const; virtual string isA() const; // ... }; class Endangered { public: virtual ~Endangered(); virtual ostream& print( ostream& ) const; virtual void highlight() const; // ... |
|
class Panda : public Bear, public Endangered { public: virtual ~Panda(); virtual ostream& print( ostream& ) const; virtual void cuddle(); // ... |
|
Имя виртуальной функции |
Активный экземпляр |
| деструктор | Panda::~Panda() |
| print(ostream&) const | Panda::print(ostream&) |
| isA() const | Bear::isA() |
| highlight() const | Endangered::highlight() |
| cuddle() | Panda::cuddle() |
|
Bear *pb = new Panda; pb->print( cout ); // ïðàâèëüíî: Panda::print(ostream&) pb->isA(); // ïðàâèëüíî: Bear::isA() pb->cuddle(); // îøèáêà: ýòî íå ÷àñòü èíòåðôåéñà Bear pb->highlight(); // îøèáêà: ýòî íå ÷àñòü èíòåðôåéñà Bear |
Endangered *pe = new Panda; pe->print( cout ); // правильно: Panda::print(ostream&) // îøèáêà: ýòî íå ÷àñòü èíòåðôåéñà Endangered pe->cuddle(); pe->highlight(); // правильно: Endangered::highlight() |
// ZooAnimal *pz = new Panda; delete pz; // Bear *pb = new Panda; delete pb; // Panda *pp = new Panda; delete pp; // Endangered *pe = new Panda; |
class Panda : public Bear, public Endangered |
Panda yin_yang; |
(b) class DoublyLinkedList: |
(c) class iostream: |
class A { ... }; class B : public A { ... }; class C : public B { ... }; class X { ... }; class Y { ... }; class Z : public X, public Y { ... }; |
class X { ... }; class A { ... }; class B : public A { ... }; class C : private B { ... }; |
class Base { public: virtual ~Base(); virtual ostream& print(); virtual void debug(); virtual void readOn(); virtual void writeOn(); // ... }; class Derived1 : virtual public Base { public: virtual ~Derived1(); virtual void writeOn(); // ... }; class Derived2 : virtual public Base { public: virtual ~Derived2(); virtual void readOn(); // ... }; class MI : public Derived1, public Derived2 { public: virtual ~MI(); virtual ostream& print(); virtual void debug(); // ... |
Base *pb = new MI; (a) pb->print(); (c) pb->readOn(); (e) pb->log(); |
(b) MI obj; |
// model1.h // модель с включением: // определения шаблонов помещаются в заголовочный файл template Type min( Type t1, Type t2 ) { return t1 < t2 ? t1 : t2;
| |
// определения шаблонов включены раньше // используется конкретизация шаблона #include "model1.h" int i, j; |
template Type min( Type t1, Type t2 ) { return t1 < t2 ? t1 : t2;
| |
int i, j; |
extern void release( const ZooAnimal& ); Panda yinYang; // стандартное преобразование: Panda -> ZooAnimal |
class Panda : public Bear, public Endangered { // наследует ZooAnimal::operator const char *() }; Panda yinYang; extern void release( const ZooAnimal& ); extern void release( const char * ); // стандартное преобразование: Panda -> ZooAnimal // выбирается: release( const ZooAnimal& ) |
extern void release( const ZooAnimal& ); extern void release( const Bear& ); // правильно: release( const Bear& ) |
void receive( void* ); |
extern void mumble( const Bear& ); extern void mumble( const Endangered& ); /* ошибка: неоднозначный вызов: * может быть выбрана любая из двух функций * void mumble( const Bear& ); * void mumble( const Endangered& ); */ |
extern void release( const Bear& ); extern void release( const Panda& ); ZooAnimal za; // ошибка: нет соответствия |
Class ZooAnimal { public: // преобразование: ZooAnimal ==> const char* operator const char*(); // ... }; extern void release( const char* ); extern void release( const Bear& ); ZooAnimal za; // za ==> const char* // правильно: release( const char* ) |
class Base1 { public: ostream& print(); void debug(); void writeOn(); void log( string ); void reset( void *); // ... }; class Base2 { public: void debug(); void readOn(); void log( double ); // ... }; class MI : public Base1, public Base2 { public: ostream& print(); using Base1::reset; void reset( char * ); using Base2::log; using Base2::log; // ... |
MI *pi = new MI; (a) pi->print(); (c) pi->readOn(); (e) pi->log( num ); |
class Base { public: operator int(); operator const char *(); // ... }; class Derived : public Base { public: operator double(); // ... |
(a) void operate( double ); void operate( string ); void operate( const Base & ); Derived *pd = new Derived; |
(b) void calc( int ); void calc( double ); void calc( const Derived & ); Base *pb = new Derived; |
int arr[3]; void putValues(const int *); int main() { putValues(arr); // необходимо 2 преобразования // массив в указатель + преобразование спецификатора return 0; |
namespace libs_R_us { int max( int, int ); double max( double, double ); } // using-объявление using libs_R_us::max; void func() { char c1, c2; max( c1, c2 ); // вызывается libs_R_us::max( int, int ) |
int i, j; extern long calc( long, long ); extern double calc( double, double ); void jj() { // ошибка: неоднозначность, нет наилучшего соответствия calc( i, j ); |
void reset( int * ); void reset( const int * ); int* pi; int main() { reset( pi ); // без преобразования спецификаторов лучше: // выбирается reset( int * ) return 0; |
int extract( void * ); int extract( const void * ); int* pi; int main() { extract( pi ); // выбирается extract( void * ) return 0; |
#include void manip( vector void manip( const vector vector extern vector int main() { manip( vec ); // выбирается manip( vector manip( f() ); // выбирается manip( const vector return 0; |
extern int ff( char*, int ); extern int ff( int, int ); int main() { ff( 0, 'a' ); // ff( int, int ) return 0; |
int compute( const int&, short ); int compute( int&, double ); extern int iobj; int main() { compute( iobj, 'c' ); // compute( int&, double ) return 0; |
class PeekbackStack { private: const int static bos = -1; public: explicit PeekbackStack( int size ) : stack( size ), _top( bos ) {} bool empty() const { return _top == bos; } bool full() const { return _top == size()-1; } int top() const { return _top; } int pop() { if ( empty() ) /* обработать ошибку */ ; return stack[ _top-- ]; } void push( int value ) { if ( full() ) /* обработать ошибку */ ; stack[ ++_top ] = value; } bool peekback( int index, int &value ) const; private: int _top; IntArray stack; }; inline bool PeekbackStack:: peekback( int index, int &value ) const { if ( empty() ) /* обработать ошибку */ ; if ( index < 0 || index > _top ) { value = stack[ _top ]; return false; } value = stack[ index ]; return true; |
#include "TextQuery.h" int main() { TextQuery tq; tq.build_up_text(); tq.query_text(); |
void display_map_text( map { typedef map tmap::iterator iter = text_map->begin(), iter_end = text_map->end(); while ( iter != iter_end ) { cout << "word: " << (*iter).first << " ("; int loc_cnt = 0; loc *text_locs = (*iter).second; loc::iterator liter = text_locs->begin(), liter_end = text_locs->end(); while (liter != liter_end ) { if ( loc_cnt ) cout << ','; else ++loc_cnt; cout << '(' << (*liter).first << ',' << (*liter).second << ')'; ++liter; } cout << ")\n"; ++iter; } cout << endl;
| |
if ( text_map->size() ) |
if ( ! text_map->empty() ) |
// получим указатель на вектор позиций loc ploc = (*text_map)[ query_text ]; // переберем все позиции // вставим все номера строк в множество set< short > occurrence_lines; loc::iterator liter = ploc->begin(), liter_end = ploc->end(); while ( liter != liter_end ) { occurrence_lines.insert( occurrence_lines.end(), (*liter).first ); ++liter; |
register int size = occurrence_lines.size(); cout << "\n" << query_text << " встречается " << size << " раз(а):") << "\n\n"; set< short >::iterator it=occurrence_lines.begin(); for ( ; it != occurrence_lines.end(); ++it ) { int line = -it; cout << "\t( строка " << line + 1 << " ) " << (*text_file)[line] << endl; |
int ival = 3; double dva1 = 3.14159; // ival преобразуется в double: 3.0 |
// 0 преобразуется в нулевой указатель типа int* int *pi = 0; // dva1 преобразуется в int: 3 |
extern double sqrt( double ); // 2 преобразуется в double: 2.0 |
double difference( int ivati, int iva12 ) { // результат преобразуется в double return ivati - iva12; |
int main() { Screen myScreen( 3, 3 ), bufScreen; myScreen.clear(); myScreen.move( 2, 2 ); myScreen.set( '*' ); myScreen.display(); bufScreen.resize( 5, 5 ); bufScreen.display(); |
inline void Screen::move( int r, int c ) { if ( checkRange( r, c ) ) // позиция на экране задана корректно? { int row = (r-1) * _width; // смещение строки _cursor = row + c - 1; } |
// псевдокод, показывающий, как происходит расширение // определения функции-члена // ЭТО НЕ КОРРЕКТНЫЙ КОД C++ inline void Screen::move( Screen *this, int r, int c ) { if ( checkRange( r, c ) ) { int row = (r-1) * this->_width; this->_cursor = row + c - 1; } |
inline void Screen::home() { this->_cursor = 0; |
/* * Это первое знакомство с определением класса в C++. * Классы используются как в объектном, так и в * объектно-ориентированном программировании. Реализация * класса Screen представлена в главе 13. */ class Screen { /* Это называется телом класса */ public: void home(); /* переместить курсор в позицию 0,0 */ void refresh ();/* перерисовать экран */ private: /* Классы поддерживают "сокрытие информации" */ /* Сокрытие информации ограничивает доступ из */ /* программы к внутреннему представлению класса */ /* (его данным). Для этого используется метка */ /* "private:" */ int height, width; |
#include /* комментарии /* */ не могут быть вложенными. * Строку "не вкладываются" компилятор рассматривает, * как часть программы. Это же относится к данной и следующей строкам */ int main() { cout << "Здравствуй, мир\n"; |
/* * Первое знакомство с определением класса в C++. * Классы используются как в объектном, так и в * объектно-ориентированном программировании. Реализация * класса Screen представлена в главе 13. */ class Screen { // Это называется телом класса public: void home(); // переместить курсор в позицию 0,0 void refresh (); // перерисовать экран private: /* Классы поддерживают "сокрытие информации". */ /* Сокрытие информации ограничивает доступ из */ /* программы к внутреннему представлению класса */ /* (его данным). Для этого используется метка */ /* "private:" */ int height, width; |
class String { // ... public: String( const char * = 0 ); bool operator== ( const String & ) const; // нет оператора operator== ( const char * ) |
String flower( "tulip" ); void foo( const char *pf ) { // вызывается перегруженный оператор String::operator==() if ( flower == pf ) cout << pf << " is a flower!\en"; // ... |
class String { // ... public: String( const char * = 0 ); bool operator== ( const String & ) const; operator const char*(); // новый конвертер |
// проверка на равенство больше не компилируется! |
namespace NS { class complex { complex( double ); // ... }; class LongDouble { friend LongDouble operator+( LongDouble &, int ) { /* ... */ } public: LongDouble( int ); operator double(); LongDouble operator+( const complex & ); // ... }; LongDouble operator+( const LongDouble &, double ); } int main() { NS::LongDouble ld(16.08); double res = ld + 15.05; // какой operator+? return 0; |
// ----- token.h ----- typedef unsigned char uchar; const uchar INLINE = 128; // ... const uchar IT = ...; const uchar GT = ...; extern uchar lastTok; extern int addToken( uchar ); inline bool is_relational( uchar tok ) { return (tok >= LT && tok <= GT); } // ----- lex.C ----- #include "token.h" // ... // ----- token.C ----- #include "token.h" |
extern int ival = 10; double fica_rate; |
// ----- заголовочный файл ----- const int buf_chunk = 1024; extern char *const bufp; // ----- исходный файл ----- |
// ошибка: не должно быть в заголовочном файле |
(a) extern int ix = 1024; (b) int iy; (c) extern void reset( void *p ) { /* ... */ } (d) extern const int *pi; |
(a) int var; (b) inline bool is_equal( const SmallInt &, const SmallInt & ){ } (c) void putValues( int *arr, int size ); (d) const double pi = 3.1416; |
Type ID Assign Constant Semicolon |
Type <==> int ID <==> i |
union TokenValue { char _cval; int _ival; char *_sval; double _dval; |
// объект типа TokenValue TokenValue last_token; // указатель на объект типа TokenValue |
last_token._ival = 97; |
union TokenValue { public: char _cval; // ... private: int priv; } int main() { TokenValue tp; tp._cval = '\n'; // правильно // ошибка: main() не может обращаться к закрытому члену // TokenValue::priv tp.priv = 1024; |
union illegal_members { Screen s; // ошибка: есть конструктор Screen *ps; // правильно static int is; // ошибка: статический член int &rfi; // ошибка: член-ссылка |
union TokenValue { public: TokenValue(int ix) : _ival(ix) { } TokenValue(char ch) : _cval(ch) { } // ... int ival() { return _ival; } char cval() { return _cval; } private: int _ival; char _cval; // ... }; int main() { TokenValue tp(10); int ix = tp.ival(); //... |
enum TokenKind ( ID, Constant /* и другие типы лексем */ } class Token { public: TokenKind tok; TokenValue val; |
int lex() { Token curToken; char *curString; int curIval; // ... case ID: // идентификатор curToken.tok = ID; curToken.val._sval = curString; break; case Constant: // целая константа curToken.tok = Constant; curToken.val._ival = curIval; break; // ... и т.д. |
char *idVal; // проверить значение дискриминанта перед тем, как обращаться к sval if ( curToken.tok == ID ) |
#include // функции доступа к члену объединения sval string Token::sval() { assert( tok==ID ); return val._sval; |
class Token { public: TokenKind tok; // имя типа объединения опущено union { char _cval; int _ival; char *_sval; double _dval; } val; |
class Token { public: TokenKind tok; // анонимное объединение union { char _cval; int _ival; char *_sval; double _dval; }; |
int lex() { Token curToken; char *curString; int curIval; // ... выяснить, что находится в лексеме // ... затем установить curToken case ID: curToken.tok = ID; curToken._sval = curString; break; case Constant: // целая константа curToken.tok = Constant; curToken._ival = curIval; break; // ... и т.д. |
// pquery может адресовать любой из классов, производных от Query void eval( const Query *pquery ) { pquery->eval(); |
int main() { AndQuery aq; NotQuery notq; OrQuery *oq = new OrQuery; NameQuery nq( "Botticelli" ); // правильно: любой производный от Query класс // компилятор автоматически преобразует в базовый класс eval( &aq ); eval( ¬q ); eval( oq ); eval( &nq ); |
int main() { string name( "Scooby-Doo" ); // ошибка: тип string не является производным от Query eval( &name ); |
// полиморфизма нет int *pi; // нет поддержанного языком полиморфизма void *pvi; // pquery может адресовать объект любого производного от Query класса |
if ( NameQuery *pnq = |
class AndQuery { public: // ... private: Query *_lop; Query *_rop; |

![]() |
![]() |
![]() |
![]() |
|
class Query { ... }; class AndQuery : public Query { ... }; class OrQuery : public Query { ... }; class NotQuery : public Query { ... }; |
|
// ошибка: Query должен быть определен class Query; |
|
// ошибка: опережающее объявление не должно // включать списка базовых классов |
|
// опережающее объявление как производного, // так и обычного класса содержит только имя класса class Query; |
книга аудио-книга аудиокассета детская кукла видеокассета видеоигра для приставки SEGA книга с подневной оплатой видеоигра для приставки SONY |
// неупорядоченный массив без проверки границ индекса class IntArray { ... }; // неупорядоченный массив с проверкой границ индекса class IntArrayRC { ... }; // упорядоченный массив без проверки границ индекса |
void process_array (IntArray&); void process_array (IntArrayRC&); |
#include void swap (IntArray &ia, int i, int j) { int temp ia[i]; ia[i] = ia[j]; ia[j] = temp; } // ниже идут обращения к функции swap: IntArray ia; IntArrayRC iarc; IntSortedArray ias; // правильно - ia имеет тип IntArray swap (ia,0,10); // правильно - iarc является подклассом IntArray swap (iarc,0,10); // правильно - ias является подклассом IntArray swap (ias,0,10); |
class IntArray { public: // конструкторы explicit IntArray (int sz = DefaultArraySize); IntArray (int *array, int array_size); IntArray (const IntArray &rhs); // виртуальный деструктор virtual ~IntArray() { delete[] ia; } // операции сравнения: bool operator== (const IntArray&) const; bool operator!= (const IntArray&) const; // операция присваивания: IntArray& operator= (const IntArray&); int size() const { return _size; }; // мы убрали проверку индекса... |
void init (IntArray &ia) |
#ifndef IntArrayRC_H #define IntArrayRC_H #include "IntArray.h" class IntArrayRC : public IntArray { public: IntArrayRC( int sz = DefaultArraySize ); IntArrayRC( const int *array, int array_size ); IntArrayRC( const IntArrayRC &rhs ); virtual int& operator[]( int ) const; private: void check_range( int ix ); }; |
IntArrayRC::operator[]( int index ) { check_range( index ); return _ia[ index ]; |
#include inline void IntArrayRC::check_range(int index) { assert (index>=0 && index < _size); |
int ia[] = {0,1,1,2,3,5,8,13}; |
inline IntArrayRC::IntArrayRC( int sz ) : IntArray( sz ) {} inline IntArrayRC::IntArrayRC( const int *iar, int sz ) |
#include #include "IntArray.h" #include "IntArrayRC.h" void swap( IntArray &ia, int ix, int jx ) { int tmp = ia[ ix ]; ia[ ix ] = ia[ jx ]; ia[ jx ] = tmp; } int main() { int array[ 4 ] = { 0, 1, 2, 3 }; IntArray ia1( array, 4 ); IntArrayRC ia2( array, 4 ); // ошибка: должно быть size-1 // не может быть выявлена объектом IntArray cout << "swap() with IntArray ia1" << endl; swap( ia1, 1, ia1.size() ); // правильно: объект IntArrayRC "поймает" ошибку cout << "swap() with IntArrayRC ia2" << endl; swap( ia2, 1, ia2.size() ); return 0; |
(a) функция-член является подвидом функции (b) функция-член является подвидом класса (c) конструктор является подвидом функции-члена (d) самолет является подвидом транспортного средства (e) машина является подвидом грузовика (f) круг является подвидом геометрической фигуры (g) квадрат является подвидом треугольника (h) автомобиль является подвидом самолета |
(a) rotate(); (b) print(); (c) size(); (d) DateBorrowed(); // дата выдачи книги (e) rewind(); (f) borrower(); // читатель (g) is_late(); // книга просрочена |
(a) Точка (b) Служащий (c) Фигура (d) Телефонный_номер (e) Счет_в_банке |
class classname { public: // набор открытых операций private: // закрытые функции, обеспечивающие реализацию |
// статический объект типа IntArray |
// объявление класса IntArray |
class IntArray { public: // операции сравнения: #2b bool operator== (const IntArray&) const; bool operator!= (const IntArray&) const; // операция присваивания: #2a IntArray& operator= (const IntArray&); int size() const; // #1 void sort(); // #4 int min() const; // #3a int max() const; // #3b // функция find возвращает индекс первого // найденного элемента массива // или -1, если элементов не найдено |
// инициализация переменной min_val |
int min_val = myArray.min(); |
// инструкция присваивания - // вызывает функцию-член myArray0.operator=(myArray1) myArray0 = myArray1; // инструкция сравнения - // вызывает функцию-член myArray0.operator==(myArray1) if (myArray0 == myArray1) |
class IntArray { public: // ... int size() const { return _size; } private: // внутренние данные-члены |
IntArray array; |
for (int index=0; index |
// список перегруженных функций min() // каждая функция отличается от других списком параметров #include int min (const int *pia,int size); int min (int, int); int min (const char *str); char min (string); |
class IntArray { public: explicit IntArray (int sz = DefaultArraySize); IntArray (int *array, int array_size); IntArray (const IntArray &rhs); // ... private: static const int DefaultArraySize = 12; |
IntArray::IntArray (int sz) { // инициализация членов данных _size = sz; ia = new int[_size]; // инициализация элементов массива for (int ix=0; ix<_size; ++ix) ia[ix] = 0; |
int ia[10] = {0,1,2,3,4,5,6,7,8,9}; |
IntArray::IntArray (int *array, int sz) { // инициализация членов данных _size = sz; ia = new int[_size]; // инициализация элементов массива for (int ix=0; ix<_size; ++ix) ia[ix] = array[ix]; |
IntArray::IntArray (const IntArray &rhs ) |
class IntArray { public: explicit IntArray (int sz = DefaultArraySize); IntArray (int *array, int array_size); IntArray (const IntArray &rhs); // ... private: void init (int sz,int *array); // ... }; // функция, используемая всеми конструкторами void IntArray::init (int sz,int *array) { _size = sz; ia = new int[_size]; for (int ix=0; ix<_size; ++ix) if ( !array ) ia[ix] = 0; else ix[ix] = array[ix]; } // модифицированные конструкторы IntArray::IntArray (int sz) { init(sz,0); } IntArray::IntArray (int *array, int array_size) { init (array_size,array); } IntArray::IntArray (const IntArray &rhs) |
class IntArray { |
IntArray array; |
#include int& IntArray::operator[] (int index) { assert (index >= 0 && index < _size); return ia[index]; |
template const Type& min( const Type *p, int size ) { Type minval = p[ 0 ]; for ( int ix = 1; ix < size; ++ix ) if ( p[ ix ] < minval ) minval = p[ ix ]; return minval;
| |
template < typename Type, bool (*Comp)(const Type&, const Type&)> const Type& min( const Type *p, int size, Comp comp ) { Type minval = p[ 0 ]; for ( int ix = 1; ix < size; ++ix ) if ( Comp( p[ ix ] < minval )) minval = p[ ix ]; return minval; |
Image im1("foreground.tiff"), im2("background.tiff"); // ... // вызывает Image AddImages::operator()(const Image1&, const Image2&); |
template < typename Type, typename Comp > const Type& min( const Type *p, int size, Comp comp ) { Type minval = p[ 0 ]; for ( int ix = 1; ix < size; ++ix ) if ( Comp( p[ ix ] < minval )) minval = p[ ix ]; return minval; |
catch ( const Excp &eObj ) { // ошибка: в классе Excp нет функции-члена value() cerr << "попытка поместить значение " << eObj.value() << " в полный стек\n"; |
// новые определения классов, включающие виртуальные функции class Excp { public: virtual void print( string msg ) { cerr << "Произошло исключение" << endl; } |
class stackExcp : public Excp { }; class pushOnFull : public stackExcp { public: virtual void print() { cerr << "попытка поместить значение " << _value << " в полный стек\n"; } // ... |
int main() { try { // iStack::push() возбуждает исключение pushOnFull } catch ( Excp eObj ) { eObj.print(); // хотим вызвать виртуальную функцию, // но вызывается экземпляр из базового класса } |
int main() { try { // iStack::push() возбуждает исключение pushOnFull } catch ( const Excp &eObj ) { eObj.print(); // вызывается виртуальная функция // pushOnFull::print() } |
// новый класс исключения: // он сохраняет значение, которое не удалось поместить в стек class pushOnFull { public: pushOnFull( int i ) : _value( i ) { } int value { return _value; } private: int _value; |
void iStack::push( int value ) { if ( full() ) // значение, сохраняемое в объекте-исключении throw pushOnFull( value ); // ... |
catch ( pushOnFull eObj ) { cerr << "trying to push value " << eObj.value() << " on a full stack\n"; |
enum EHstate { noErr, zeroOp, negativeOp, severeError }; enum EHstate state = noErr; int mathFunc( int i ) { if ( i == 0 ) { state = zeroOp; throw state; // создан объект-исключение } // иначе продолжается обычная обработка |
void calculate( int op ) { try { mathFunc( op ); } catch ( EHstate eObj ) { // eObj - копия сгенерированного объекта-исключения } |
void calculate( int op ) { try { mathFunc( op ); } catch ( EHstate &eObj ) { // eObj ссылается на сгенерированный объект-исключение } |
void calculate( int op ) { try { mathFunc( op ); } catch ( EHstate &eObj ) { // исправить ошибку, вызвавшую исключение eObj = noErr; // глобальная переменная state не изменилась } |
class Screen { public: // функции-члены private: string _screen; string:size_type _cursor; short _height; short _width; |
class Screen { // список членов }; int main() { Screen mainScreen; |
Screen bufScreen = myScreen; // bufScreen._height = myScreen._height; // bufScreen._width = myScreen._width; // bufScreen._cursor = myScreen._cursor; |
int main() { Screen myScreen, bufScreen[10]; Screen *ptr = new Screen; myScreen = *ptr; delete ptr; ptr = bufScreen; Screen &ref = *ptr; Screen &ref2 = bufScreen[6]; |
#include "Screen.h" bool isEqual( Screen& s1, Screen *s2 ) { // возвращает false, если объекты не равны, и true - если равны if (s1.height() != s2->height() || s2.width() != s2->width() ) return false; for ( int ix = 0; ix < s1.height(); ++ix ) for ( int jy = 0; jy < s2->width(); ++jy ) if ( s1.get( ix, jy ) != s2->get( ix, jy ) ) return false; return true; // попали сюда? значит, объекты равны |
class Screen { public: int height() { return _height; } int width() { return _width; } // ... private: short _heigh, _width; // ... |
class Screen; // объявление class StackScreen { int topStack; // правильно: указатель на объект Screen Screen *stack; void (*handler)(); |
class LinkScreen { Screen window; LinkScreen *next; LinkScreen *prev; |
string _name; |
Person( const string &n, const string &s ) : _name( n ), _address( a ) { } string name() { return _name; } |
// прочитать содержимое экрана в позиции (3,4) // Увы! Это не работает cs.move( 3, 4 ); |
inline void Screen::move( int r, int c ) { if ( checkRange( r, c ) ) { int row = (r-1) * _width; _cursor = row + c - 1; // модифицирует _cursor } |
class Screen { public: // функции-члены private: string _screen; mutable string::size_type _cursor; // изменчивый член short _height; short _width; |
// move() - константная функция-член inline void Screen::move( int r, int c ) const { // ... // правильно: константная функция-член может модифицировать члены // со спецификатором mutable _cursor = row + c - 1; // ... |
Screen myScreen; |
// взаимное расположение ключевых слов public и virtual // несущественно class Bear : public virtual ZooAnimal { ... }; |
extern void dance( const Bear* ); extern void rummage( const Raccoon* ); extern ostream& operator<<( ostream&, const ZooAnimal& ); int main() { Panda yin_yang; dance( &yin_yang ); // правильно rummage( &yin_yang ); // правильно cout << yin_yang; // правильно // ... |
#include #include class ZooAnimal; extern ostream& operator<<( ostream&, const ZooAnimal& ); class ZooAnimal { public: ZooAnimal( string name, bool onExhibit, string fam_name ) : _name( name ), _onExhibit( onExhibit ), _fam_name( fam_name ) {} virtual ~ZooAnimal(); virtual ostream& print( ostream& ) const; string name() const { return _name; } string family_name() const { return _fam_name; } // ... protected: bool _onExhibit; string _name; string _fam_name; // ...
| |
class Bear : public virtual ZooAnimal { public: enum DanceType { two_left_feet, macarena, fandango, waltz }; Bear( string name, bool onExhibit=true ) : ZooAnimal( name, onExhibit, "Bear" ), _dance( two_left_feet ) {} virtual ostream& print( ostream& ) const; void dance( DanceType ); // ... protected: DanceType _dance; // ... |
class Raccoon : public virtual ZooAnimal { public: Raccoon( string name, bool onExhibit=true ) : ZooAnimal( name, onExhibit, "Raccoon" ), _pettable( false ) {} virtual ostream& print( ostream& ) const; bool pettable() const { return _pettable; } void pettable( bool petval ) { _pettable = petval; } // ... protected: bool _pettable; // ... |
class Foo { void bar(); }; template class QueueItem { friend class foobar; friend void foo(); friend void Foo::bar(); // ...
| |
template class foobar { ... }; template void foo( QueueItem template class Queue { void bar(); // ... }; template class QueueItem { friend class foobar friend void foo friend void Queue // ...
| |
template class QueueItem { template friend class foobar; template friend void foo( QueueItem template friend class Queue // ... |
template class QueueItem { // любой экземпляр Queue является другом // любого экземпляра QueueItem template
| |
template class QueueItem { // для любого экземпляра QueueItem другом является // только конкретизированный тем же типом экземпляр Queue friend class Queue // ...
| |
// как задать аргумент типа Queue? |
template |
template ostream& operator<<( ostream &os, const Queue { os << "< "; QueueItem for ( p = q.front; p; p = p->next ) os << *p << " "; os << " >"; return os; |
template class Queue { friend ostream& operator<<( ostream &, const Queue // ... |
template ostream& operator<<( ostream &os, const QueueItem { os << qi.item; return os; |
template class QueueItem { friend class Queue friend ostream& operator<<( ostream &, const QueueItem // ... |
#include #include "Queue.h" int main() { Queue // конкретизируются оба экземпляра // ostream& operator<<(ostream &os, const Queue // ostream& operator<<(ostream &os, const QueueItem cout << qi << endl; int ival; for ( ival = 0; ival < 10; ++ival ) qi.add( ival ); cout << qi << endl; int err_cnt = 0; for ( ival = 0; ival < 10; ++ival ) { int qval = qi.remove(); if ( ival != qval ) err_cnt++; } cout << qi << endl; if ( !err_cnt ) cout << "!! queue executed ok\n"; else cout << "?? queue errors: " << err_cnt << endl; return 0; |
// объявление функции calc() // определение находится в другом файле void calc(int); int main() { int loc1 = get(); // ошибка: get() не объявлена calc(loc1); // правильно: calc() объявлена // ... |
type_specifier object_name; |
int var1 = 0; |
// заголовочный файл extern int obj1; extern int obj2; // исходный файл int obj1 = 97; |
extern const double pi = 3.1416; // определение |
class myClass { public: void f( double ); char f( char, char ); // перегружает myClass::f( double ) // ... |
class myClass { public: void mf(); double mf(); // ошибка: так перегружать нельзя // ... |
class myClass { public: void mf(); void mf(); // ошибка: повторное объявление // ... |
class myClass { public: void mcf( double ); static void mcf( int* ); // перегружает myClass::mcf( double ) // ... |
class String { public: typedef int index_type; // тип параметра - это на самом деле String::index_type char& operator[]( index_type ) |
class String { public: // ошибка: имя index_type не объявлено char &operator[]( index_type ); typedef int index_type; |
class String { public: typedef int index_type; char &operator[]( index_type elem ) { return _string[ elem ]; } private: char *_string; |
class Screen { public: // bkground относится к статическому члену, // объявленному позже в определении класса Screen& clear( char = bkground ); private: static const char bkground = '#'; |
class Screen { public: // ... // ошибка: bkground - нестатический член Screen& clear( char = bkground ); private: const char bkground = '#'; |
class String { public: typedef int index_type; char& operator[]( index_type ); private: char *_string; }; // в operator[]() есть обращения к index_type и _string inline char& operator[]( index_type elem ) { return _string[ elem ]; |
class Account: // ... private: static double _interestRate; static double initInterestRate(); }; // ссылается на Account::initInterest() |
class Account: // ... private: static const int nameSize = 16; static const char name[nameSize]; // nameSize не квалифицировано именем класса Account |
class Account { typedef double Money; //... private: static Money _interestRate; static Money initInterest(); }; // Money должно быть квалифицировано именем класса Account:: |
class ZooAnimal { public: ostream &print( ostream& ) const; // сделаны открытыми только ради демонстрации разных случаев string is_a; int ival; private: double dval; |
class Bear : public ZooAnimal { public: ostream &print( ostream& ) const; // сделаны открытыми только ради демонстрации разных случаев string name; int ival; |
Bear bear; |
int ival; int Bear::mumble( int ival ) { return ival + // обращение к параметру ::ival + // обращение к глобальному объекту ZooAnimal::ival + Bear::ival; |
int dval; int Bear::mumble( int ival ) { // ошибка: разрешается в пользу закрытого члена ZooAnimal::dval return ival + dval; |
int dval; int Bear::mumble( int ival ) { foo( dval ); // ... |
ostream& Bear::print( ostream &os) const { // вызывается ZooAnimal::print(os) ZooAnimal::print( os ); os << name; return os; |
class Endangered { public: ostream& print( ostream& ) const; void highlight(); // ... }; class ZooAnimal { public: bool onExhibit() const; // ... private: bool highlight( int zoo_location ); // ... }; class Bear : public ZooAnimal { public: ostream& print( ostream& ) const; void dance( dance_type ) const; // ... |
class Panda : public Bear, public Endangered { public: void cuddle() const; // ... |
int main() { Panda yin_yang; yin_yang.dance( Bear::macarena ); |
void Panda::mumble() { dance( Bear::macarena ); // ... |
// правильно: Bear::dance() |
int main() { // ошибка: неоднозначность: одна из // Bear::print( ostream& ) const // Endangered::print( ostream& ) const Panda yin_yang; yin_yang.print( cout ); |
int main() { // правильно, но не лучшее решение Panda yin_yang; yin_yang.Bear::print( cout ); |
class Base { public: void print( string ) const; // ... }; class Derived1 : public Base { public: void print( int ) const; // ... }; class Derived2 : public Base { public: void print( double ) const; // ... }; class MI : public Derived1, public Derived2 { public: void print( complex // ... |
MI mi; string dancer( "Nejinsky" ); |
inline void Panda::highlight() { Endangered::highlight(); } inline ostream& Panda::print( ostream &os ) const { Bear::print( os ); Endangered::print( os ); return os; |
class Base1 { public: // ... protected: int ival; double dval; char cval; // ... private: int *id; // ... }; class Base2 { public: // ... protected: float fval; // ... private: double dval; // ... }; class Derived : public Base1 { public: // ... protected: string sval; double dval; // ... }; class MI : public Derived, public Base2 { public: // ... protected: int *ival; complex // ... |
int ival; double dval; void MI:: foo( double dval ) { int id; // ... |
void MI:: bar() { int sval; // вопрос упражнения относится к коду, начинающемуся с этого места ... } (a) dval = 3.14159; (d) fval = 0; (b) cval = 'a'; (e) sval = *ival; |
int id; void MI:: foobar( float cval ) { int dval; // вопросы упражнения относятся к коду, начинающемуся с этого места ... |
#include #include // сравниваем s1 и s2 лексикографически int lexicoCompare( const string &sl, const string &s2 ) { ... } // сравниваем длины s1 и s2 int sizeCompare( const string &sl, const string &s2 ) { ... } typedef int ( PFI)( const string &, const string & ); // сортируем массив строк void sort( string *s1, string *s2, PFI compare =lexicoCompare ) { ... } string sl[10] = { "a", "light", "drizzle", "was", "falling", "when", "they", "left", "the", "school" }; int main() { // вызов sort() со значением по умолчанию параметра compare // s1 - глобальный массив sort( s1, s1 + sizeof(s1)/sizeof(s1[0]) - 1 ); // выводим результат сортировки for ( int i = 0; i < sizeof(s1) / sizeof(s1[0]); ++i ) cout << s1[ i ].c_str() << "\n\t";
| |
// следует читать: включая first и все последующие // элементы до last, но не включая сам last |
#include #include int ia[ 6 ] = { 0, 1, 2, 3, 4, 5 }; vector list // соответствующий заголовочный файл #include vector list #int *pia; // find() возвращает итератор на найденный элемент // для массива возвращается указатель ... pia = find( &ia[0], &ia[6], some_int_value ); liter = find( dlist.begin(), dlist.end(), some_double_value );
| |
int ia[] = { 1, 5, 34 }; int ia2[] = { 1, 2, 3 }; int ia3[] = { 6, 13, 21, 29, 38, 55, 67, 89 }; |
int ia[] = { 0, 1, 1, 2, 3, 5, 8, 13, 21, 55, 89 }; |
// читается так: включает первый и все последующие элементы, // кроме последнего |
template
| |
template
| |
template class list_item { public: list_item( elemType value, list_item *item = 0 ) : _value( value ) { if ( !item ) _next = 0; else { _next = item->_next; item->_next = this; } } elemType value() { return _value; } list_item* next() { return _next; } void next( list_item *link ) { _next = link; } void value( elemType new_value ) { _value = new_value; } private: elemType _value; list_item *_next;
| |
template class list { public: list() : _at_front( 0 ), _at_end( 0 ), _current( 0 ), _size( 0 ) {} 1ist( const list& ); list& operator=( const list& ); ~list() { remove_all(); } void insert ( list_item void insert_end( elemType value ); void insert_front( elemType value ); void insert_all( const list &rhs ); int remove( elemType value ); void remove_front(); void remove_all(); list_item list_item list_item void disp1ay( ostream &os = cout ); void concat( const list& ); void reverse (); int size() { return _size; } private: void bump_up_size() { ++_size; } void bump_down_size() { --_size; } list_item 1ist_item list_item int _size; |
namespace Primer_Third_Edition { template class list_item{ ... }; template class list{ ... }; // ... |
// наш заголовочный файл #include "list.h" // сделаем наши определения видимыми в программе using namespace Primer_Third_Edition; // теперь можно использовать наш класс list list< int > ilist; |
ilist_item::~ilist_item() { delete _next; |
void ilist::remove_end(); |
class ilist { public: // ... ilist_item* find( int value, ilist_item *start_at = 0 ); // ... |
void ilist:: insert( ilist_item *begin, int *array_of_value, |
ilist_item *it = mylist.find( 1 ); |
ilist ilist::reverse_copy(); |
while (( pos = word.find_first_of( filt_elems, pos )) |
void filter_text( vector { vector vector // Если filter не задан, зададим его сами if ( ! filter.size() ) filter.insert( 0, "\".," ); while ( iter != iter_end ) { string::size_type pos = 0; // удалим каждый найденный элемент while (( pos = (*iter).find_first_of( filter, pos )) != string::npos ) (*iter).erase(pos,1); iter++; }
| |
while (( pos = (*iter).find_first_of( filter, pos )) != string::npos ) { (*iter).erase(pos,1); ++ pos; // неправильно... |
string filt_elems( "\",.;:!?)(\\/" ); |
string sentence( "kind of" ); string s1 ( "whistle" ) |
int main() { try { // ... } catch ( Excp ) { // обрабатывает исключения popOnEmpty и pushOnFull } catch ( pushOnFull ) { // обрабатывает исключение pushOnFull |
catch ( pushOnFull ) { // обрабатывает исключение pushOnFull } catch ( Excp ) { // обрабатывает другие исключения |
catch ( pushOnFull eObj ) { // используется функция-член value() класса pushOnFull // см. раздел 11.3 cerr << "попытка поместить значение " << eObj.value() << " в полный стек\n"; } catch ( Excp ) { // используется функция-член print() базового класса Excp::print( "произошло исключение" ); |
void calculate( int parm ) { try { mathFunc( parm ); // возбуждает исключение divideByZero } catch ( mathExcp mExcp ) { // частично обрабатывает исключение // и генерирует объект-исключение еще раз throw; } |
class pushOnFull { public: pushOnFull( int i ) : _value( i ) { } int value() { return _value; } ~pushOnFull(); // вновь объявленный деструктор private: int _value; |
catch ( pushOnFull eObj ) { cerr << "попытка поместить значение " << eObj.value() << " в полный стек\n"; |
vector< int > vec0; const vector< int > vec1; vector< int >::reverse_iterator r_iter0 = vec0.rbegin(); |
// обратный итератор обходит вектор от конца к началу vector< type >::reverse_iterator r_iter; for ( r_iter = vec0.rbegin(); // r_iter указывает на последний элемент r_iter != vec0.rend(); // пока не достигли элемента перед первым r_iter++ ) // переходим к предыдущему элементу |
// сортирует вектор в порядке возрастания sort( vec0.begin(), vec0.end() ); // сортирует вектор в порядке убывания |
| Операция | Действие | ||
| empty() | Возвращает true, если очередь пуста, и false в противном случае | ||
| size() | Возвращает количество элементов в очереди | ||
| pop() | Удаляет первый элемент очереди, но не возвращает его значения. Для очереди с приоритетом первым является элемент с наивысшим приоритетом | ||
| front() | Возвращает значение первого элемента очереди, но не удаляет его. Применимо только к простой очереди | ||
| back() | Возвращает значение последнего элемента очереди, но не удаляет его. Применимо только к простой очереди | ||
| top() | Возвращает значение элемента с наивысшим приоритетом, но не удаляет его. Применимо только к очереди с приоритетом | ||
| push(item) | Помещает новый элемент в конец очереди. Для очереди с приоритетом позиция элемента определяется его приоритетом. |
class Account { friend class vector< Account >; public: explicit Account( const char*, double = 0.0 ); // ... private: Account(); // ... |
// стандартные заголовочные файлы С++ #include #include #include #include #include |
set ifstream infile( "exclusion_set" ); copy( default_excluded_words, default_excluded_words+25, |
Account acct( "Tina Lee" ); int swt; // ... switch( swt ) { case 0: return; case 1: // что-то сделать return; case 2: // сделать что-то другое return; // и так далее |
// переписано для обеспечения единственной точки выхода switch( swt ) { case 0: break; case 1: // что-то сделать break; case 2: // сделать что-то другое break; // и так далее } // единственная точка выхода |
class NoName { public: ~NoName(); // ... private: char *pstring; int ival; double dval; |
void mumble( const char *name, fouble balance, char acct_type ) { Account acct; if ( ! name ) return; if ( balance <= 99 ) return; switch( acct_type ) { case 'z': return; case 'a': case 'b': return; } // ... |
#include #include int main() { int ia[10] = {0,1,2,3,4,5,6,7,8,9}; vector int ix_vec = 0, ix_ia = 9; while ( ix_vec < 10 ) ivec[ ix_vec++ ] = ia[ ix_ia-- ]; int *pia = &ia[9]; vector while ( iter != ivec.end() ) assert( *iter++ == *pia-- );
| |
// неверно: ошибки с границами индексов в // обоих случаях int ix_vec = 0, ix_ia = 9; while ( ix_vec < 10 ) |
// правильно int ix_vec = -1, ix_ia = 8; while ( ix_vec < 10 ) |
int ival = 1024; |
ival = 2048; |
int value = 1024; |
const int array_size = 8; int ia[ array_size ] = { 0, 1, 2, 2, 3, 5, 8, 13 }; |
extern char next_char(); int main() { char ch = next_char(); while ( ch != '\n' ) { // сделать что-то ... ch = next_char(); } // ... |
extern char next_char(); int main() { char ch; while (( ch = next_char() ) != '\n' ) { // сделать что-то ... } // ... |
int main () { int ival, jval; ival = jval = 0; // правильно: присваивание 0 обеим переменным |
int main () { int ival; int *pval; ival = pval = 0; // ошибка: разные типы |
int main() { // ... int ival = jval = 0; // верно или нет? // ... |
int main() { // правильно: определение и инициализация int ival = 0, jval = 0; // ... |
int arraySum( int ia[], int sz ) { int sum = 0; for ( int i = 0; i < sz; ++i ) sum = sum + ia[ i ]; return sum; |
int arraySum( int ia[], int sz ) { int sum = 0; for ( int i =0; i < sz; ++i ) // эквивалентно: sum = sum + ia[ i ]; sum += ia[ i ]; return sum; |
int main() { float fval; int ival; int *pi; fval = ival = pi = 0; |
(a) if ( ptr = retrieve_pointer() != 0 ) (b) if ( ival = 1024 ) |
#inc1ude comp1ex< double > a; comp1ex< double > b; // ...
| |
double dval = 3.14159; |
int ival = 3; |
// ошибка: нет неявного преобразования // в арифметический тип |
double re = complex_obj.real(); |
double re = real(complex_obj); |
complex< double > complex0( 3.14159, -2.171 ); comp1ex< double > complex1( complexO.real() ); |
// допустимые форматы для ввода комплексного числа // 3.14159 ==> comp1ex( 3.14159 ); // ( 3.14159 ) ==> comp1ex( 3.14159 ); // ( 3.14, -1.0 ) ==> comp1ex( 3.14, -1.0 ); // может быть считано как // cin >> a >> b >> с // где a, b, с - комплексные числа |
#include inline complex operator+=( complex { return cval += complex |
#include #include // определения операций... int main() { complex< double > cval ( 4.0, 1.0 ); cout << cval << endl; cval += 1; cout << cval << endl; cval -= 1; cout << cval << endl; cval *= 2; cout << cval << endl; cout /= 2; cout << cval << endl; |
#include #include // определения операций... int main() { complex< double > cval( 4.0, 1.0 ); cout << cval << endl; ++cva1; cout << cval << endl; |
vector< string > svec; list< string > slist; string spouse( "Beth" ); slist.insert( slist.begin(), spouse ); |
string son( "Danny" ); list iter = find( slist.begin(), slist.end(), son );
| |
// эквивалентный вызов: slist.push_back( value ); |
vector string anna( "Anna" );
| |
svec.insert( svec.begin(), sarray, sarray+4 ); svec.insert( svec.begin() + svec.size()/2, |
// вставляем элементы svec // в середину svec_two svec_two.insert( svec_two.begin() + svec_two.size()/2, |
list< string > slist; // ... // вставляем элементы svec // перед элементом, содержащим stringVal list< string >::iterator iter = find( slist.begin(), slist.end(), stringVal ); |
| Символ операции | Значение | Использование | |||
| ! | Логическое НЕ | !expr | |||
| < | Меньше | expr1 < expr2 | |||
| <= | Меньше или равно | expr1 <= expr2 | |||
| > | Больше | expr1 > expr2 | |||
| >= | Больше или равно | expr1 >= expr2 | |||
| == | Равно | expr1 == expr2 | |||
| != | Не равно | expr1 != expr2 | |||
| && | Логическое И | expr1 && expr2 | |||
| || | Логическое ИЛИ | expr1 || expr2 | |||
| Примечание. Все операции в результате дают значение типа bool |
| vector while ( iter != ivec.end() ) { // эквивалентно: e1em_cnt = e1em_cnt + (*iter < some_va1ue) // значение true/false выражения *iter < some_va1ue // превращается в 1 или 0 e1em_cnt += *iter < some_va1ue; ++iter;
| |
| expr1 && expr2 |
while ( ptr != О && ptr->va1ue < upperBound && ptr->va1ue >= 0 && notFound( ia[ ptr->va1ue ] )) |
bool found = false; // пока элемент не найден // и ptr указывает на объект (не 0) while ( ! found && ptr ) { found = 1ookup( *ptr ); ++ptr; |
// Внимание! Порядок вычислений не определен! if ( ia[ index++ ] < ia[ index ] ) |
if ( ia[ index ] < ia[ index+1 ] ) // поменять местами элементы |
// Внимание! это не сравнение 3 переменных друг с другом if ( ival != jva1 != kva1 ) |
if ( ival != jva1 && ival != kva1 && jva1 != kva1 ) |
(a) ptr->iva1 != 0 (с) ptr != 0 && *ptr++ (e) vec[ iva1++ ] <= vec[ ival ]; |
void list::merge( list rhs ); template
| |
int array1[ 10 ] = { 34, 0, 8, 3, 1, 13, 2, 5, 21, 1 }; int array2[ 5 ] = { 377, 89, 233, 55, 144 }; list< int > ilist1( array1, array1 + 10 ); list< int > ilist2( array2, array2 + 5 ); // для объединения требуется, чтобы оба списка были упорядочены ilist1.sort(); ilist2.sort(); |
template < class Predicate > |
class Even { public: bool operator()( int elem ) { return ! (elem % 2 ); } }; |
void list::sort(); template
| |
void list::splice( iterator pos, list rhs ); void list::splice( iterator pos, list rhs, iterator ix ); void list::splice( iterator pos, list rhs, |
int array[ 10 ] = { 0, 1, 1, 2, 3, 5, 8, 13, 21, 34 }; list< int > ilist1( array, array + 10 ); |
// ilist2.end() указывает на позицию, куда нужно переместить элемент // элементы вставляются перед этой позицией // ilist1 указывает на список, из которого перемещается элемент // ilist1.begin() указывает на сам перемещаемый элемент |
list< int >::iterator first, last; first = ilist1.find( 2 ); last = ilist1.find( 13 ); |
list< int >::iterator pos = ilist2.find( 5 ); |
void list::unique(); template
| |
class EvenPair { public: bool operator()( int val1, val2 ) { return ! (val2 % val1 ); } }; |
class employee { public: virtual int salary(); }; class manager : public employee { public: int salary(); }; class programmer : public employee { public: int salary(); }; void company::payroll( employee *pe ) { // используется pe->salary() |
class employee { public: virtual int salary(); // çàðïëàòà virtual int bonus(); // ïðåìèÿ }; class manager : public employee { public: int salary(); }; class programmer : public employee { public: int salary(); int bonus(); }; void company::payroll( employee *pe ) { // èñïîëüçóåòñÿ pe->salary() è pe->bonus() |
class employee { public: virtual int salary(); }; class manager : public employee { public: int salary(); }; class programmer : public employee { public: int salary(); int bonus(); |
void company::payroll( employee *pe ) { programmer *pm = dynamic_cast< programmer* >( pe ); // åñëè pe óêàçûâàåò íà îáúåêò òèïà programmer, // òî dynamic_cast âûïîëíèòñÿ óñïåøíî è pm áóäåò // óêàçûâàòü íà íà÷àëî îáúåêòà programmer if ( pm ) { // èñïîëüçîâàòü pm äëÿ âûçîâà programmer::bonus() } // åñëè pe íå óêàçûâàåò íà îáúåêò òèïà programmer, // òî dynamic_cast âûïîëíèòñÿ íåóäà÷íî // è pm áóäåò ñîäåðæàòü 0 else { // èñïîëüçîâàòü ôóíêöèè-÷ëåíû êëàññà employee } |
void company::payroll( employee *pe ) { programmer *pm = dynamic_cast< programmer* >( pe ); // ïîòåíöèàëüíàÿ îøèáêà: pm èñïîëüçóåòñÿ áåç ïðîâåðêè çíà÷åíèÿ static int variablePay = 0; variablePay += pm->bonus(); // ... |
void company::payroll( employee *pe ) { // âûïîëíèòü dynamic_cast è ïðîâåðèòü ðåçóëüòàò if ( programmer *pm = dynamic_cast< programmer* >( pe ) ) { // èñïîëüçîâàòü pm äëÿ âûçîâà programmer::bonus() } else { // èñïîëüçîâàòü ôóíêöèè-÷ëåíû êëàññà employee } |
#include void company::payroll( employee &re ) { try { programmer &rm = dynamic_cast< programmer & >( re ); // èñïîëüçîâàòü rm äëÿ âûçîâà programmer::bonus() } catch ( std::bad_cast ) { // èñïîëüçîâàòü ôóíêöèè-÷ëåíû êëàññà employee } |
#include #include const int chunk = 16; class Foo { public: int val() { return _val; } FooQ(){ _val = 0; } private: int _val; }; // выделяем память, но не создаем объектов Foo char *buf = new char[ sizeof(Foo) * chunk ]; int main() { // создаем объект Foo в buf Foo *pb = new (buf) Foo; // проверим, что объект помещен в buf if ( pb.val() == 0 ) cout << "Оператор new сработал!" << endl; // здесь нельзя использовать pb delete[] buf; return 0;
| |
(a) const float *pf = new const float[100]; (b) double *pd = new doub1e[10] [getDim()]; (c) int (*pia2)[ 1024 ] = new int[ ][ 1024 ]; |
typedef int arr[10]; |
int globalObj; char buf[1000]; void f() { int *pi = &global0bj; double *pd = 0; float *pf = new float(O); int *pa = new(buf)int[20]; delete pi; // (a) delete pd; // (b) delete pf; // (c) de1ete[] pa; // (d) |
int ix = 1024; int *pi = & ix; int *pi2 = new int ( 2048 ); (a) auto_ptr (b) auto_ptr (c) auto_ptr (d) auto_ptr (e) auto_ptr (f) auto_ptr (9) auto_ptr |
int *pi0 = p2.get(); |
ps.get()->assign( "Danny" ); |
class Screen { public: void *operator new( size_t ); void *operator new( size_t, Screen * ); // ... |
void func( Screen *start ) { Screen *ps = new (start) Screen; // ... |
// определение интерфейса библиотеки #include "primer.h" // ошибка: нет объявления для matrix |
// определение интерфейса библиотеки #include "primer.h" class matrix { /* пользовательское определение */ }; // правильно: глобальный тип matrix найден |
#include const int max = 65000; const int lineLength = 12; void fibonacci( int max ) { if ( max < 2 ) return; cout << "0 1 "; int v1 = 0, v2 = 1, cur; for ( int ix = 3; ix <= max; ++ix ) { cur = v1 + v2; if ( cur > ::max ) break; cout << cur << " "; vl = v2; v2 = cur; if (ix % "lineLength == 0) cout << end"!; } |
#include void fibonacci( int ); int main() { cout << "Числа Фибоначчи: 16\n"; fibonacci( 16 ); return 0; |
sizeof ( type name ); sizeof ( object ); |
#include int ia[] = { 0, 1, 2 }; // sizeof возвращает размер всего массива size_t array_size = sizeof ia; // sizeof возвращает размер типа int
| |
int *pi = new int[ 3 ]; |
#include #include #include int main() { size_t ia; ia = sizeof( ia ); // правильно ia = sizeof ia; // правильно // ia = sizeof int; // ошибка ia = sizeof( int ); // правильно int *pi = new int[ 12 ]; cout << "pi: " << sizeof( pi ) << " *pi: " << sizeof( pi ) << endl; // sizeof строки не зависит от // ее реальной длины string stl( "foobar" ); string st2( "a mighty oak" ); string *ps = &stl; cout << " st1: " << sizeof( st1 ) << " st2: " << sizeof( st2 ) << " ps: sizeof( ps ) << " *ps: " << sizeof( *ps ) << endl; cout << "short :\t" << sizeof(short) << endl; cout << "shorf" :\t" << sizeof(short*) << endl; cout << "short& :\t" << sizeof(short&) << endl; cout << "short[3] :\t" << sizeof(short[3]) << endl;
| |
// char_size == 1 |
// правильно: константное выражение |
class ScreenPtr { // ... private: Screen *ptr; |
class ScreenPtr { public: ScreenPtr( const Screen &s ) : ptr( &s ) { } // ... |
ScreenPtr p1; // ошибка: у класса ScreenPtr нет конструктора по умолчанию Screen myScreen( 4, 4 ); |
// перегруженные операторы для поддержки поведения указателя class ScreenPtr { public: Screen& operator*() { return *ptr; } Screen* operator->() { return ptr; } // ... |
#include #include #include "Screen.h" void printScreen( const ScreenPtr &ps ) { cout << "Screen Object ( " << ps->height() << ", " << ps->width() << " )\n\n"; for ( int ix = 1; ix <= ps->height(); ++ix ) { for ( int iy = 1; iy <= ps->width(); ++iy ) cout << ps->get( ix, iy ); cout << "\n"; } } int main() { Screen sobj( 2, 5 ); string init( "HelloWorld" ); ScreenPtr ps( sobj ); // Установить содержимое экрана string::size_type initpos = 0; for ( int ix = 1; ix <= ps->height(); ++ix ) for ( int iy = 1; iy <= ps->width(); ++iy ) { ps->move( ix, iy ); ps->set( init[ initpos++ ] ); } // Вывести содержимое экрана printScreen( ps ); return 0; |
#include programmer pobj; employee &re = pobj; // ñ ôóíêöèåé name() ìû ïîçíàêîìèìñÿ â ïîäðàçäåëå, ïîñâÿùåííîì type_info // îíà âîçâðàùàåò C-ñòðîêó "programmer"
| |
int iobj; cout << typeid( iobj ).name() << endl; // ïå÷àòàåòñÿ: int |
class Base { /* нет виртуальных функций */ }; class Derived : public Base { /* íåò âèðòóàëüíûõ ôóíêöèé */ }; Derived dobj; Base *pb = &dobj; |
#include employee *pe = new manager; employee& re = *pe; if ( typeid( pe ) == typeid( employee* ) ) // èñòèííî // ÷òî-òî ñäåëàòü /* if ( typeid( pe ) == typeid( manager* ) ) // ëîæíî if ( typeid( pe ) == typeid( employee ) ) // ëîæíî if ( typeid( pe ) == typeid( manager ) ) // ëîæíî |
// вызов виртуальной функции |
typeid( *pe ) == typeid( manager ) // истинно |
typeid( re ) == typeid( manager ) // истинно typeid( re ) == typeid( employee ) // ложно typeid( &re ) == typeid( employee* ) // истинно |
#include int main() { cout << "сплетница Анна Ливия\n";
| |
#include #include int main() { cout << "Длина 'Улисс' равна:\t"; cout << strlen( "Улисс" ); cout << '\n'; cout << "Размер 'Улисс' равен:\t"; cout << sizeof( "Улисс" ); cout << endl;
| |
#include #include int main() { // операторы вывода можно сцеплять cout << "Длина 'Улисс' равна:\t"; << strlen( "Улисс" ) << '\n'; cout << "Размер 'Улисс' равен:\t" << sizeof( "Улисс" ) << endl;
| |
#include int main() { int i = 1024; int *pi = &i; cout << "i: " << i << "\t&i:\t" << &i << '\n'; cout << "*pi: " << *pi << "\tpi:\t" << pi << endl << "\t\t&pi:\t" << &pi << endl; |
#include const char *str = "vermeer"; int main() { const char *pstr = str; cout << "Адрес pstr равен: " << pstr << endl; |
#include inline void max_out( int val1, int val2 ) { cout << ( val1 > val2 ) ? val1 : val2; } int main() { int ix = 10, jx = 20; cout << "Большее из " << ix << ", " << jx << " равно "; max_out( ix, jx ); cout << endl; |
int main() { cout << "печать значений типа bool по умолчанию: " << true << " " << false << "\nи в виде строк: " << boolalpha() << true << " " << false << endl; |
#include #include #include string pooh_pals[] = { "Тигра", "Пятачок", "Иа-Иа", "Кролик" }; int main() { vector vector vector cout << "Это друзья Пуха: "; for ( ; iter != iter_end; iter++ ) cout << *iter << " "; cout << endl; |
#include #include #include #include string pooh_pals[] = { "Тигра", "Пятачок", "Иа-Иа", "Кролик" }; int main() { vector vector vector cout << "Это друзья Пуха: "; // копируем каждый элемент в cout ... ostream_iterator< string > output( cout, " " ); copy( iter, iter_end, output ); cout << endl; |
string sa[4] = { "пух", "тигра", "пятачок", "иа-иа" }; vector< string > svec( sa, sa+4 ); string robin( "кристофер робин" ); const char *pc = robin.c_str(); int ival = 1024; char blank = ' '; double dval = 3.14159; |
class absInt { public: int operator()( int val ) { int result = val < 0 ? -val : val; return result; } |
#include #include int main() { int ia[] = { -0, 1, -1, -2, 3, 5, -5, 8 }; vector< int > ivec( ia, ia+8 ); // заменить каждый элемент его абсолютным значением transform( ivec.begin(), ivec.end(), ivec.begin(), absInt() ); // ...
| |
typedef vector< int >::iterator iter_type; // конкретизация transform() // операция absInt применяется к элементу вектора int iter_type transform( iter_type iter, iter_type last, iter_type result, absInt func ) { while ( iter != last ) *result++ = func( *iter++ ); // вызывается absInt::operator() return iter; |
String entry( "extravagant" ); String mycopy; for ( int ix = 0; ix < entry.size(); ++ix ) |
#include inine char& String::operator[]( int elem ) const { assert( elem >= 0 && elem < _size ); return _string[ elem ];
| |
String color( "violet" ); |
int main() { // примеры оператора "запятая" // переменные ia, sz и index определены в другом месте ... int ival = (ia != 0) ? ix=get_va1ue(), ia[index]=ix : ia=new int[sz], ia[index]=0; // ... |
String car ("Volks"); |
class String { public: // оператор присваивания для char* String& operator=( const char * ); // ... private: int _size; char *string; |
String& String::operator=( const char *sobj ) { // sobj - нулевой указатель if (! sobj ) { _size = 0; delete[] _string; _string = 0; } else { _size = strlen( sobj ); delete[] _string; _string = new char[ _size + 1 ]; strcpy( _string, sobj ); } return *this; |
char ia[] = { 'd', 'a', 'n', 'c', 'e', 'r' }; String trap = ia; // trap._string ссылается на ia |
// сцепление операторов присваивания int iobj, jobj; |
String ver, noun; |
// набор перегруженных операторов присваивания String& operator=( const String & ); |
SmallInt si(98); int iobj = 65; |
SmallInt operator+ ( const SmallInt &, const SmallInt & ); int main() { SmallInt si(98); int iobj = 65; int res = si + iobj; // ::operator+() - функция-кандидат |
namespace NS { class SmallInt { /* ... */ }; SmallInt operator+ ( const SmallInt&, double ); } int main() { // si имеет тип SmallInt: // этот класс объявлен в пространстве имен NS NS::SmallInt si(15); // NS::operator+() - функция-кандидат int res = si + 566; return 0; |
namespace NS { class SmallInt { friend SmallInt operator+( const SmallInt&, int ) { /* ... */ } }; } int main() { NS::SmallInt si(15); // функция-друг operator+() - кандидат int res = si + 566; return 0; |
class myFloat { myFloat( double ); }; class SmallInt { public: SmallInt( int ); SmallInt operator+ ( const myFloat & ); }; int main() { SmallInt si(15); int res = si + 5.66; // оператор-член operator+() - кандидат |
int operator+( int, int ); double operator+( double, double ); T* operator+( T*, I ); |
namespace NS { class myFloat { myFloat( double ); }; class SmallInt { friend SmallInt operator+( const SmallInt &, int ) { /* ... */ } public: SmallInt( int ); operator int(); SmallInt operator+ ( const myFloat & ); // ... }; SmallInt operator+ ( const SmallInt &, double ); } int main() { // тип si - class SmallInt: // Этот класс объявлен в пространстве имен NS NS::SmallInt si(15); int res = si + 5.66; // какой operator+()? return 0; |
int operator+( int, int ); double operator+( double, double ); T* operator+( T*, I ); |
class ScreenPtr { public: // ... private: int size; // размер массива: 0, если единственный объект int offset; // смещение ptr от начала массива Screen *ptr; |
class ScreenPtr { public: ScreenPtr( Screen &s , int arraySize = 0 ) : ptr( &s ), size ( arraySize ), offset( 0 ) { } private: int size; int offset; Screen *ptr; |
Screen myScreen( 4, 4 ); ScreenPtr pobj( myScreen ); // правильно: указывает на один объект const int arrSize = 10; Screen *parray = new Screen[ arrSize ]; |
class ScreenPtr { public: Screen& operator++(); Screen& operator--(); // ... |
const int arrSize = 10; Screen *parray = new Screen[ arrSize ]; ScreenPtr parr( *parray, arrSize ); for ( int ix = 0; ix < arrSize; ++ix, ++parr ) // эквивалентно parr.operator++() } |
Screen& ScreenPtr::operator++() { if ( size == 0 ) { cerr << "не могу инкрементировать указатель для одного объекта\n"; return *ptr; } if ( offset >= size - 1 ) { cerr << "уже в конце массива\n"; return *ptr; } ++offset; return *++ptr; } Screen& ScreenPtr::operator--() { if ( size == 0 ) { cerr << "не могу декрементировать указатель для одного объекта\n"; return *ptr; } if ( offset <= 0 ) { cerr << "уже в начале массива\n"; return *ptr; } --offset; return *--ptr; |
class ScreenPtr { public: Screen& operator++(); // префиксные операторы Screen& operator--(); Screen& operator++(int); // постфиксные операторы Screen& operator--(int); // ... |
Screen& ScreenPtr::operator++(int) { if ( size == 0 ) { cerr << "не могу инкрементировать указатель для одного объекта\n"; return *ptr; } if ( offset == size ) { cerr << "уже на один элемент дальше конца массива\n"; return *ptr; } ++offset; return *ptr++; } Screen& ScreenPtr::operator--(int) { if ( size == 0 ) { cerr << "не могу декрементировать указатель для одного объекта\n"; return *ptr; } if ( offset == -1 ) { cerr << "уже на один элемент раньше начала массива\n"; return *ptr; } --offset; return *ptr--; |
const int arrSize = 10; Screen *parray = new Screen[ arrSize ]; ScreenPtr parr( *parray, arrSize ); for ( int ix = 0; ix < arrSize; ++ix) |
class ScreenPtr { // объявления не членов friend Screen& operator++( Screen & ); // префиксные операторы friend Screen& operator--( Screen & ); friend Screen& operator++( Screen &, int); // постфиксные операторы friend Screen& operator--( Screen &, int); public: // определения членов |
class Screen { public: void operator delete( void * ); |
class Screen { public: // заменяет // void operator delete( void * ); void operator delete( void *, size_t ); |
class Screen { public: void *operator new( size_t ); void operator delete( void *, size_t ); // ... private: Screen *next; static Screen *freeStore; static const int screenChunk; |
#include "Screen.h" #include // статические члены инициализируются // в исходных файлах программы, а не в заголовочных файлах Screen *Screen::freeStore = 0; const int Screen::screenChunk = 24; void *Screen::operator new( size_t size ) { Screen *p; if ( !freeStore ) { // связанный список пуст: получить новый блок // вызывается глобальный оператор new size_t chunk = screenChunk * size; freeStore = p = reinterpret_cast< Screen* >( new char[ chunk ] ); // включить полученный блок в список for ( ; p != &freeStore[ screenChunk - 1 ]; ++p ) p->next = p+1; p->next = 0; } p = freeStore; freeStore = freeStore->next; return p; |
void Screen::operator delete( void *p, size_t ) { // вставить "удаленный" объект назад, // в список свободных ( static_cast< Screen* >( p ) )->next = freeStore; freeStore = static_cast< Screen* >( p ); |
// Псевдокод на C++ ptr = Screen::operator new( sizeof( Screen ) ); |
// Псевдокод на C++ Screen::~Screen( ptr ); |
// вызывается Screen::operator new() |
// вызывается Screen::operator new[]() |
class Screen { public: void *operator new[]( size_t ); // ... |
class Screen { public: void operator delete[]( void * ); |
class Screen { public: // заменяет // void operator delete[]( void* ); void operator delete[]( void*, size_t ); |
void doit( Query *pq ) { // виртуальный вызов pq->eval(); // статический вызов Query::display() pq->display(); |
#include #include #include #include typedef pair< short, short > location; class Query { public: // конструкторы и деструктор обсуждаются в разделе 17.4 // копирующий конструктор и копирующий оператор присваивания // обсуждаются в разделе 17.6 // операции для поддержки открытого интерфейса virtual void eval() = 0; virtual void display () const; // функции доступа для чтения const set const vector static const vector protected: set static vector set vector }; inline const set Query:: solution() { return _solution ? _solution : _solution = _vec2set( &_loc ); |
// ---- primer.h ---- namespace cplusplus_primer { // первое вложенное пространство имен: // матричная часть библиотеки namespace MatrixLib { class matrix { /* ... */ }; const double pi = 3.1416; matrix operators+ ( const matrix &ml, const matrix &m2 ); void inverse( matrix & ); // ... } |
// ---- primer.C ---- #include "primer.h" // определение в глобальной области видимости cplusplus_primer::MatrixLib::matrix cplusplus_primer::MatrixLib::operator+ ( const matrix& ml, const matrix &m2 ) |
// ---- primer.C ---- #include "primer.h" cplusplus_primer::MatrixLib::matrix cplusplus_primer::MatrixLib::operator+ ( const matrix &ml, const matrix &m2 ) { // объявление локальной переменной типа // cplusplus_primer::MatrixLib::matrix matrix res; // вычислим сумму двух объектов matrix return res; |
// ---- primer.C -- #include "primer.h" namespace cplusplus_primer { MatrixLib::matrix MatrixLib::operator+ ( const matrix &ml, const matrix &m2 ) { /* ... */ } |
namespace cplusplus_primer { namespace MatrixLib { class matrix { /*...*/ }; // следующее объявление не может быть пропущено matrix operator+ ( const matrix &ml, const matrix &m2 ); // ... } |
NameQuery // Shakespeare NotQuery // ! Shakespeare OrQuery // Shakespeare || Marlowe |
AndQuery OrQuery NameQuery ("Alice") NameQuery ("Emma") |
// не объектно-ориентированное решение union op_type { // объединение не может содержать объекты классов с // ассоциированными конструкторами NotQuery *nq; OrQuery *oq; AndQuery *aq; string *word; }; enum opTypes { Not_query=1, O_query, And_query, Name_query }; class AndQuery { public: // ... private: /* * opTypes хранит информацию о фактических типах операндов запроса * op_type - это сами операнды */ op_type _lop, _rop; opTypes _lop_type, _rop_type; |
class AndQuery { public: // ... private: void * _lop, _rop; opTypes _lop_type, _rop_type; |
void AndQuery:: eval() { // не объектно-ориентированный подход // ответственность за разрешение типа ложится на программиста // определить фактический тип левого операнда switch( _lop_type ) { case And_query: AndQuery *paq = static_cast paq->eval(); break; case Or_query: OrQuery *pqq = static_cast poq->eval(); break; case Not_query: NotQuery *pnotq = static_cast pnotq->eval(); break; case Name_query: AndQuery *pnmq = static_cast pnmq->eval(); break; } // то же для правого операнда |
// объектно-ориентированное решение // ответственность за разрешение типов перекладывается на компилятор // примечание: теперь _lop и _rop - объекты типа класса // их определения будут приведены ниже void AndQuery:: eval() { _lop->eval(); _rop->eval(); |
// определить объект, не имея запроса пользователя UserQuery user_query; string text; vector // обработать запросы пользователя do { while( cin >> text ) query_text.push_back( text ); // передать запрос объекту UserQuery user_query.query( &query_text ); // вычислить результат запроса и вернуть // корень иерархии Query* Query *query = user_query.eval_query(); }
| |
#ifndef USER_QUERY_H #define USER_QUERY_H #include #include #include |
inline void UserQuery:: evalAnd() { Query *pop = _query_stack.top(); _query_stack.pop(); AndQuery *pq = new AndQuery( pop ); if ( _lparenOn ) { pq->lparen( _lparenOn ); _lparenOn = 0; } if ( _rparenOn ) { pq->rparen( _rparenOn ); _rparenOn = 0; } _current_op.push( pq ); } inline void UserQuery:: evalOr() { Query *pop = _query_stack.top(); _query_stack.pop(); OrQuery *pq = new OrQuery( pop ); if ( _lparenOn ) { pq->lparen( _lparenOn ); _lparenOn = 0; } if ( _rparenOn ) { pq->rparen( _rparenOn ); _rparenOn = 0; } _current_op.push( pq ); |
inline void UserQuery:: evalNot() { NotQuery *pq = new NotQuery; if ( _lparenOn ) { pq->lparen( _lparenOn ); _lparenOn = 0; } if ( _rparenOn ) { pq->rparen( _rparenOn ); _rparenOn = 0; } _current_op.push( pq ); |
inline void UserQuery:: evalRParen() { if ( _paren < _current_op.size() ) { Query *poperand = _query_stack.top(); _query_stack.pop(); Query *pop = _current_op.top(); _current_op.pop(); pop->add_op( poperand ); _query_stack.push( pop ); } |
inline void UserQuery:: evalWord( const string &query ) { NameQuery *pq; loc *ploc; if ( ! _word_map->count( query )) pq = new NameQuery( query ); else { ploc = ( *_word_map )[ query ]; pq = new NameQuery( query, *ploc ); } if ( _current_op.size() <= _paren ) _query_stack.push( pq ); else { Query *pop = _current_op.top(); _current_op.pop(); pop->add_op( pq ); _query_stack.push( pop ); } |
class Screen { /* ... */ }; |
class First { int memi; double memd; }; class Second { int memi; double memd; }; class First obj1; |
class employee; |
typedef pair typedef vector
| |
map allocator> // распределитель памяти по умолчанию
| |
#include |
// предпочтительный метод вставки одного элемента word_count.insert( map value_type( string("Anna"), 1 ) |
map< string,int >:: |
map< string, int > word_count; // ... заполнить map< string,int > word_count_two; // скопируем все пары ключ/значение |
// инициализируем копией всех пар ключ/значение |
(*word_map)[(*text_words)[ix]]-> |
// возьмем слово, которое надо обновить string word = (*text_words) [ix]; // возьмем значение из вектора позиций vector // возьмем позицию - пару координат loc = (*text_locs)[ix]; // вставим новую позицию |
int main() { // считываем файл и выделяем слова vector text_loc *text_locations = separate_words( text_file ); // обработаем слова // ... // построим отображение слов на векторы позиций map *text_map = build_word_map( text_locatons ); // ... |
// typedef для удобства чтения typedef pair< short,short > location; typedef vector< location > loc; typedef vector< string > text; typedef pair< text*,loc* > text_loc; extern map< string, loc* >* |
map vector |
register int elem_cnt = text_words->size(); for ( int ix=0; ix < elem_cnt; ++ix ) { string textword = ( *text_words )[ ix ]; // игнорируем слова короче трех букв // или присутствующие в списке стоп-слов if ( textword.size() < 3 || exclusion_set.count( textword )) continue; // определяем, занесено ли слово в отображение // если count() возвращает 0 - нет: добавим его if ( ! word_map->count((*text_words)[-ix] )) { loc *ploc = new vector ploc->push_back( (*text_locs) [ix] ); word_map->insert(value_type((*text_words)[ix],ploc)); } else // добавим дополнительные координаты (*word_map)[(*text_words)[ix]]-> push_back((*text_locs)[ix]); |
exclusion_set.insert( "the" ); |
typedef set< string >::difference_type diff_type; set< string > exclusion_set; ifstream infile( "exclusion_set" ); if ( ! infile ) { static string default_excluded_words[25] = { "the","and","but","that","then","are","been", "can"."can't","cannot","could","did","for", "had","have","him","his","her","its","into", "were","which","when","with","would" }; cerr << "предупреждение! невозможно открыть файл стоп-слов! -- " << "используется стандартный набор слов \n"; copy( default_excluded_words, default_excluded_words+25, inserter( exclusion_set, exclusion_set.begin() )); } else { istream_iterator copy( input_set, eos, inserter( exclusion_set, exclusion_set.begin() ));
| |
double salary; double wage; int month; int day; int year; |
int main() { |
int ival = 1024; |
int ival( 1024 ); |
double salary = 9999.99, wage = salary + 0.01; int month = 08; |
// ival получает значение 0, а dval - 0.0 |
// int() применяется к каждому из 10 элементов |
#include |
(a) int car = 1024, auto = 2048; (b) int ival = ival; (c) int ival( int() ); (d) double salary = wage = 9999.99; |
(a) extern string name; string name( "exercise 3.5a" ); (b) extern vector |
(a) int double = 3.14159; (b) vector< int > _; (c) string namespase; (d) string catch-22; |
string global_class; int global_int; |
typedef vector class NameQuery : public Query { public: // ... // переопределяет виртуальную функцию Query::eval()2 virtual void eval(); // функция чтения string name() const { return _name; } static const map protected: string _name; static map
| |
class NotQuery : public Query { public: // ... // альтернативный синтаксис: явно употреблено ключевое слово virtual // переопределение Query::eval() virtual void eval(); // функция доступа для чтения const Query *op() const { return _op; } static const vector< location > * all_locs() { return _all_locs; } protected: Query *_op; static const vector< location > *_all_locs; |
class OrQuery : public Query { public: // ... virtual void eval(); const Query *rop() const { return _rop; } const Query *lop() const { return _lop; } protected: Query *_lop; Query *_rop; |
class AndQuery : public Query { public: // конструкторы обсуждаются в разделе 17.4 virtual void eval(); const Query *rop() const { return _rop; } const Query *lop() const { return _lop; } static void max_col( const vector< int > *pcol ) { if ( !_max_col ) _max_col = pcol; } protected: Query *_lop; Query *_rop; static const vector< int > *_max_col; |
int min( int a, int b ) { return a < b ? a : b; } double min( double a, double b ) { return a < b ? a : b; |
min( 10, 20 ); |
#include #define min(a,b) ((a) < (b) ? (a) : (b)) const int size = 10; int ia[size]; int main() { int elem_cnt = 0; int *p = &ia[0]; // подсчитать число элементов массива while ( min(p++,&ia[size]) != &ia[size] ) ++elem_cnt; cout << "elem_cnt : " << elem_cnt << "\texpecting: " << size << endl; return 0;
| |
template Type min2( Type a, Type b ) { return a < b ? a : b; } int main() { // правильно: min( int, int ); min( 10, 20 ); // правильно: min( double, double ); min( 10.0, 20.0 ); return 0; |
template Glorp min2( Glorp a, Glorp b ) { return a < b ? a : b; |
template |
template Type min( const Type (&r_array)[size] ) { /* параметризованная функция для отыскания * минимального значения в массиве */ Type min_val = r_array[0]; for ( int i = 1; i < size; ++i ) if ( r_array[i] < min_val ) min_val = r_array[i]; return min_val; |
// size определяет размер параметра-массива и инициализирует // переменную типа const int template Type min( const Type (&r_array)[size] ) { const int loc_size = size; Type loc_array[loc_size]; // ... |
typedef double Type; template Type min( Type a, Type b ) { // tmp имеет тот же тип, что параметр шаблона Type, а не заданный // глобальным typedef Type tm = a < b ? a : b; return tmp; |
template Type min( Type a, Type b ) { // ошибка: повторное объявление имени Type, совпадающего с именем // параметра шаблона typedef double Type; Type tmp = a < b ? a : b; return tmp; |
// правильно: T1 представляет тип значения, возвращаемого min(), // а T2 и T3 – параметры-типы этой функции template |
// ошибка: неправильное повторное использование имени параметра Type template |
// правильно: повторное использование имени Type внутри шаблона template |
template |
// все три объявления min() относятся к одному и тому же шаблону функции // опережающие объявления шаблона template template // фактическое определение шаблона template |
#include // правильно: Type используется неоднократно в списке параметров шаблона template |
// правильно: ключевые слова typename и class могут перемежаться template T minus( T*, U ); // ошибка: должно быть // template |
template Parm minus( Parm* array, U value ) { Parm::name * p; // это объявление указателя или умножение? // На самом деле умножение |
template Parm minus( Parm* array, U value ) { typename Parm::name * p; // теперь это объявление указателя |
// правильно: спецификатор после списка параметров template inline Type min( Type, Type ); // ошибка: спецификатор inline не на месте inline template |
(a) template void foo( T, U, V ); (b) template T foo( int *T ); (c) template T1 foo( T2, T3 ); (d) inline template T foo( T, unsigned int* ); (e) template void foo( myT, myT ); (f) template foo( T, T ); (g) typedef char Ctype; template |
(a) template Type bar( Type, Type ); template Type bar( Type, Type ); (b) template void bar( T1, T2 ); template |
template class Queue { public: Queue(); ~Queue(); Type& remove(); void add( const Type & ); bool is_empty(); bool is_full(); private: // ... |
Queue Queue< complex |
template |
template |
// ошибка: должно быть // template |
template |
template class QueueItem { public: // ... private: // Type представляет тип члена Type item; QueueItem *next; |
typedef double Type; template class QueueItem { public: // ... private: // тип Item - не double Type item; QueueItem *next; |
template class QueueItem { public: // ... private: // ошибка: член не может иметь то же имя, что и // параметр шаблона Type typedef double Type; Type item; QueueItem *next; |
// ошибка: неправильное использование имени параметра шаблона Type template |
// правильно: повторное использование имени Type в разных шаблонах template class QueueItem; template |
// все три объявления QueueItem // относятся к одному и тому же шаблону класса // объявления шаблона template template // фактическое определение шаблона template |
template |
template |
// правильно: рассматриваются аргументы по умолчанию из обоих объявлений template |
template class QueueItem { public: QueueItem( const Type & ); private: Type item; QueueItem *next; |
template void display( QueueItem { QueueItem // ... |
Queue qObj; string str( "vivisection" ); qObj.add( 3.14159 ); // правильно: в очередь помещен объект 3 |
class cplusplus_primer_matrix { ... }; |
namespace cplusplus_primer { class matrix { /*...*/ }; void inverse ( matrix & ); |
void func( cplusplus_primer::matrix &m ) { // ... cplusplus_primer::inverse(m); return m; |
void func( DisneyFeatureAnimation::matrix &m ) { // ... DisneyFeatureAnimation::inverse(m); return m; |
namespace cplusplus_primer { class matrix { /* ... */ }; void inverse ( matrix & ); matrix operator+ ( const matrix &ml, const matrix &m2 ) {/* ... */ } const double pi = 3.1416; |
namespace cplusplus_primer { class matrix { /* ... */ }; const double pi = 3.1416; } namespace cplusplus_primer { void inverse ( matrix & ); matrix operator+ ( const matrix &ml, const matrix &m2 ) {/* ... */ } |
// Эта часть пространства имен // определяет интерфейс библиотеки namespace cplusplus_primer { class matrix { /* ... */ }; const double pi = 3.1416; matrix operator+ ( const matrix &ml, const matrix &m2 ); void inverse ( matrix & ); } // Эта часть пространства имен // определяет реализацию библиотеки namespace cplusplus_primer { void inverse ( matrix &m ) { /* ... */ } matrix operator+ ( const matrix &ml, const matrix &m2 ) { /* ... */ } |
// ---- primer.h ---- namespace cplusplus_primer { class matrix { /*... */ }; const double pi = 3.1416; matrix operator+ ( const matrix &m1, const matrix &m2 ); void inverse( matrix & ); } // ---- primer.C ---- #include "primer.h" namespace cplusplus_primer { void inverse( matrix &m ) { /* ... */ } matrix operator+ ( const matrix &m1, const matrix &m2 ) { /* ... */ } |
// ---- user.C ---- // определение интерфейса библиотеки #include "primer.h" void func( cplusplus_primer::matrix &m ) { //... cplusplus_primer: :inverse( m ); return m; |
#ifndef QUEUE_H #define QUEUE_H // объявление QueueItem template template class Queue { public: Queue() : front( 0 ), back ( 0 ) { } ~Queue(); Type& remove(); void add( const Type & ); bool is_empty() const { return front == 0; } private: QueueItem QueueItem };
| |
template class Queue { public: // ... private: // ошибка: список параметров для QueueItem неизвестен QueueItem
| |
(a) template class Container1; template
| |
(b) template
| |
(c) template
| |
(d) template
| |
(e) template
| |
(f) template class Container6; template
| |
template class ListItem; template class List { public: List : _at_front( 0 ), _at_end( 0 ), _current( 0 ), _size( 0 ) {} List List ~List(); void insert( ListItem *ptr, elemType value ); int remove( elemType value ); ListItem *find( elemType value ); void display( ostream &os = cout ); int size() { return _size; } private: ListItem *_at_front; ListItem *_at_end; ListItem *_current; int _size
| |
char ch; short sh;, int ival; /* в каждой операции один операнд * требует преобразования типа */ ch + ival; ival + ch; ch + sh; ch + ch; |
class SmallInt { friend operator+( const SmallInt &, int ); friend operator-( const SmallInt &, int ); friend operator-( int, const SmallInt & ); friend operator+( int, const SmallInt & ); public: SmallInt( int ival ) : value( ival ) { } operator+( const SmallInt & ); operator-( const SmallInt & ); // ... private: int value; |
SmallInt si( 3 ); |
class SmallInt { public: SmallInt( int ival ) : value( ival ) { } // конвертер // SmallInt ==> int operator int() { return value; } // перегруженные операторы не нужны private: int value; |
SmallInt si( 3 ); |
#include #include "SmallInt.h" int main() { cout << "Введите SmallInt, пожалуйста: "; while ( cin >> si1 ) { cout << "Прочитано значение " << si1 << "\nОно "; // SmallInt::operator int() вызывается дважды cout << ( ( si1 > 127 ) ? "больше, чем " : ( ( si1 < 127 ) ? "меньше, чем " : "равно ") ) << "127\n"; cout << "\Введите SmallInt, пожалуйста \ (ctrl-d для выхода): "; } cout <<"До встречи\n"; |
#include class SmallInt { friend istream& operator>>( istream &is, SmallInt &s ); friend ostream& operator<<( ostream &is, const SmallInt &s ) { return os << s.value; } public: SmallInt( int i=0 ) : value( rangeCheck( i ) ){} int operator=( int i ) { return( value = rangeCheck( i ) ); } operator int() { return value; } private: int rangeCheck( int ); int value; |
istream& operator>>( istream &is, SmallInt &si ) { int ix; is >> ix; si = ix; // SmallInt::operator=(int) return is; } int SmallInt::rangeCheck( int i ) { /* если установлен хотя бы один бит, кроме первых восьми, * то значение слишком велико; сообщить и сразу выйти */ if ( i & ~0377 ) { cerr << "\n*** Ошибка диапазона SmallInt: " << i << " ***" << endl; exit( -1 ); } return i; |
class PeekbackStack : private IntArray { public: // сохранить открытый уровень доступа using IntArray::size; // ... |
template class PeekbackStack : private IntArray { public: using intArray::size; // ... protected: using intArray::size; using intArray::ia; // ...
| |
template < class item, class container > class Unbounded_Queue: private Simple_List< item >, // ðåàëèçàöèÿ public Queue< item > // èíòåðôåéñ |
bool PeekbackStack:: |
#include "IntArray.h" class PeekbackStack : public IntArray { private: const int static bos = -1; public: explicit PeekbackStack( int size ) : IntArray( size ), _top( bos ) {} bool empty() const { return _top == bos; } bool full() const { return _top == size()-1; } int top() const { return _top; } int pop() { if ( empty() ) /* îáðàáîòàòü îøèáêó */ ; return _ia[ _top-- ]; } void push( int value ) { if ( full() ) /* îáðàáîòàòü îøèáêó */ ; _ia[ ++_top ] = value; } bool peekback( int index, int &value ) const; private: int _top; }; inline bool PeekbackStack:: peekback( int index, int &value ) const { if ( empty() ) /* îáðàáîòàòü îøèáêó */ ; if ( index < 0 || index > _top ) { value = _ia[ _top ]; return false; } value = _ia[ index ]; return true; |
extern void swap( IntArray&, int, int ); PeekbackStack is( 1024 ); // íåïðåäâèäåííîå îøèáî÷íîå èñïîëüçîâàíèå PeekbackStack swap(is, i, j); is.sort(); |
int sort( string*, string*, |
// Использование директивы typedef делает // объявление sort() более понятным typedef int ( *PFI2S )( const string &, const string & ); |
// значение по умолчанию для третьего параметра int lexicoCompare( const string &, const string & ); |
1 void sort( string *sl, string *s2, 2 PFI2S compare = lexicoCompare ) 3 { 4 // условие окончания рекурсии 5 if ( si < s2 ) { 6 string elem = *s1; 7 string *1ow = s1; 8 string *high = s2 + 1; 9 10 for (;;) { 11 while ( compare ( *++1ow, elem ) < 0 && low < s2) ; 12 while ( compare( elem, *--high ) < 0 && high > s1) 14 if ( low < high ) 15 1ow->swap(*high); 16 else break; 17 } // end, for(;;) 18 19 s1->swap(*high); 20 sort( s1, high - 1 ); 21 sort( high +1, s2 ); 22 } // end, if ( si < s2 ) |
#include #include // это должно бы находиться в заголовочном файле int lexicoCompare( const string &, const string & ); int sizeCompare( const string &, const string & ); typedef int (*PFI)( const string &, const string & ); void sort( string *, string *, PFI=lexicoCompare ); string as[10] = { "a", "light", "drizzle", "was", "falling", "when", "they", "left", "the", "museum" }; int main() { // вызов sort() с значением по умолчанию параметра compare sort( as, as + sizeof(as)/sizeof(as[0]) - 1 ); // выводим результат сортировки for ( int i = 0; i < sizeof(as)/sizeof(as[0]); ++i ) cout << as[ i ].c_str() << "\n\t"; |
// typedef представляет собой тип функции typedef int functype( const string &, const string & ); |
void sort( string *, string *, |
// Использование директивы typedef делает // объявления более понятными typedef int (*PF)( int*, int ); |
// typedef представляет собой тип функции typedef int func( int*, int ); |
// три эквивалентных объявления putValues() void putValues( int* ); void putValues( int[] ); |
void putValues( int[ 10 ] ); // рассматривается как int* int main() { int i, j [ 2 ]; putValues( &i ); // правильно: &i is int*; // однако при выполнении возможна ошибка putValues( j ); // правильно: j - адрес 0-го элемента - int*; |
void putValues( int[], int size ); int main() { int i, j[ 2 ]; putValues( &i, 1 ); putValues( j, 2 ); return 0; |
#include const lineLength =12; // количество элементов в строке void putValues( int *ia, int sz ) { cout << "( " << sz << " )< "; for (int i=0;i { if ( i % lineLength == 0 && i ) cout << "\n\t"; // строка заполнена cout << ia[ i ]; // разделитель, печатаемый после каждого элемента, // кроме последнего if ( i % lineLength != lineLength-1 && i != sz-1 ) cout << ", "; } cout << " >\n"; |
// параметр - ссылка на массив из 10 целых void putValues( int (&arr)[10] ); int main() { int i, j [ 2 ]; putValues(i); // ошибка: // аргумент не является массивом из 10 целых putValues(j); // ошибка: // аргумент не является массивом из 10 целых return 0; |
#include void putValues( int (&ia)[10] ) { cout << "( 10 )< "; for ( int 1 =0; i < 10; ++i ) { cout << ia[ i ]; // разделитель, печатаемый после каждого элемента, // кроме последнего if ( i != 9 ) cout << ", "; } cout << " >\n"; |
template void putValues( Type *ia, int sz ) { // так же, как и раньше |
class X; void manip( X *px ) { // проверим на 0 перед использованием if ( px != 0 ) // обратимся к объекту по адресу... |
class Type { }; void operate( const Type& p1, const Type& p2 ); int main() { Type obj1; // присвоим objl некоторое значение // ошибка: ссылка не может быть равной 0 Type obj2 = operate( objl, 0 ); |
Matrix a, b, c; |
Matrix // тип возврата - Matrix operator+( // имя перегруженного оператора Matrix m1, // тип левого операнда Matrix m2 // тип правого операнда ) { Matrix result; // необходимые действия return result; |
// реализация с параметрами-указателями operator+( Matrix *ml, Matrix *m2 ) { Matrix result; // необходимые действия return result; |
// а вот это не работает // &a + &b возвращает объект типа Matrix |
// правильно: работает, однако ... |
// реализация с параметрами-ссылками operator+( const Matrix &m1, const Matrix &m2 ) { Matrix result; // необходимые действия return result; |
#include // параметр-ссылка 'occurs' // содержит второе возвращаемое значение vector const vector int value, // искомое значение int &occurs ) // количество вхождений { // res_iter инициализируется значением // следующего за конечным элемента vector occurs = 0; for ( vector iter != vec.end(); ++iter ) if ( *iter == value ) { if ( res_iter == vec.end() ) res_iter = iter; ++occurs; } return res_iter;
| |
class Huge { public: double stuff[1000]; }; extern int calc( const Huge & ); int main() { Huge table[ 1000 ]; // ... инициализация table int sum = 0; for ( int ix=0; ix < 1000; ++ix ) // calc() ссылается на элемент массива // типа Huge sum += calc( tab1e[ix] ); // ... |
class X; extern int foo_bar( X& ); int foo( const X& xx ) { // ошибка: константа передается // функции с параметром неконстантного типа return foo_bar( xx ); |
extern int foo_bar( const X& ); |
int foo( const X &xx ) { // ... X x2 = xx; // создать копию значения // foo_bar() может поменять x2, // xx останется нетронутым return foo_bar( x2 ); // правильно |
void ptrswap( int *&vl, int *&v2 ) { int *trnp = v2; v2 = vl; vl = tmp; |
#include void ptrswap( int *&vl, int *&v2 ); int main() { int i = 10; int j = 20; int *pi = &i; int *pj = &j; cout << "Перед ptrswap():\tpi: " << *pi << "\tpj: " << *pj << endl; ptrswap( pi, pj ); cout << "После ptrswap():\tpi: " << *pi << "\tpj: " << pj << endl; return 0; |
const int input = 1; const int output = 2; |
bool open_file( string file_name, int open_mode); // ... |
// ошибка: 1 не является элементом перечисления open_modes |
open_modes om = input; // ... |
cout << open_modes_table[ input ] << " " |
// не поддерживается for ( open_modes iter = input; iter != append; ++inter ) |
// shape == 0, sphere == 1, cylinder == 2, polygon == 3 |
// point2d == 2, point2w == 3, point3d == 3, point3w == 4 |
void mumble() { Points pt3d = point3d; // правильно: pt2d == 3 // ошибка: pt3w инициализируется типом int Points pt3w = 3; // ошибка: polygon не входит в перечисление Points pt3w = polygon; // правильно: оба объекта типа Points pt3w = pt3d; |
const int array_size = 1024; // правильно: pt2w преобразуется int |
// swap() не меняет значений своих аргументов! void swap( int vl, int v2 ) { int tmp = v2; v2 = vl; vl = tmp; |
#include void swap( int, int ); int main() { int i = 10; int j = 20; cout << "Перед swap():\ti: " << i << "\tj: " << j << endl; swap( i, j ); cout << "После swap():\ti: " << i << "\tj: " << j << endl; return 0; |
// pswap() обменивает значения объектов, // адресуемых указателями vl и v2 void pswap( int *vl, int *v2 ) { int tmp = *v2; *v2 = *vl; *vl = tmp; |
// rswap() обменивает значения объектов, // на которые ссылаются vl и v2 void rswap( int &vl, int &v2 ) { int tmp = v2; v2 = vl; vl = tmp; |
int glob; int main() { // что угодно |
vector vector string word; while ( cin >> word ) { text.push_back( word ); // ... } // .... return text; |
#include void print( const string & ); void print( double ); // перегружает print() void fooBar( int ival ) { // отдельная область видимости: скрывает обе реализации print() extern void print( int ); // ошибка: print( const string & ) не видна в этой области print( "Value: "); print( ival ); // правильно: print( int ) видна
| |
#include namespace IBM { extern void print( const string & ); extern void print( double ); // перегружает print() } namespace Disney { // отдельная область видимости: // не перегружает функцию print() из пространства имен IBM extern void print( int );
| |
namespace libs_R_us { int max( int, int ); int max( double, double ); extern void print( int ); extern void print( double ); } // using-объявления using libs_R_us::max; using libs_R_us::print( double ); // ошибка void func() { max( 87, 65 ); // вызывает libs_R_us::max( int, int ) |
#include namespace libs_R_us { extern void print( int ); extern void print( double ); } extern void print( const string & ); // libs_R_us::print( int ) и libs_R_us::print( double ) // перегружают print( const string & ) using libs_R_us::print; void fooBar( int ival ) { print( "Value: "); // вызывает глобальную функцию // print( const string & ) print( ival ); // вызывает libs_R_us::print( int ) |
namespace libs_R_us { void print( int ); void print( double ); } void print( int ); using libs_R_us::print; // ошибка: повторное объявление print(int) void fooBar( int ival ) { print( ival ); // какая print? ::print или libs_R_us::print |
#include namespace libs_R_us { extern void print( int ); extern void print( double ); } extern void print( const string & ); // using-директива // print(int), print(double) и print(const string &) - элементы // одного и того же множества перегруженных функций using namespace libs_R_us; void fooBar( int ival ) { print( "Value: "); // вызывает глобальную функцию // print( const string & ) print( ival ); // вызывает libs_R_us::print( int ) |
namespace IBM { int print( int ); } namespace Disney { double print( double ); |
// using-директива // формируется множество перегруженных функций из различных // пространств имен using namespace IBM; using namespace Disney; long double print(long double); int main() { print(1); // вызывается IBM::print(int) print(3.1); // вызывается Disney::print(double) return 0; |
#include #include "WordCount.h" /* необходимо модифицировать определение класса WordCount, чтобы оператор ввода был другом class WordCount { friend ostream& operator<<( ostream&, const WordCount& ); friend istream& operator>>( istream&, const WordCount& ); */ istream& operator >>( istream &is, WordCount &wd ) { /* формат хранения объекта WordCount: * <2> строка * <7,3> <12,36> */ int ch; /* прочитать знак '<'. Если его нет, * перевести поток в ошибочное состояние и выйти */ if ((ch = is.get()) != '<' ) { // is.setstate( ios_base::badbit ); return is; } // прочитать длину int occurs; is >> occurs; // читать до обнаружения >; ошибки не контролируются while ( is && (ch = is.get()) != '>' ) ; is >> wd._word; // прочитать позиции вхождений; // каждая позиция имеет формат: < строка, колонка > for ( int ix = 0; ix < occurs; ++ix ) { int line, col; // извлечь значения while (is && (ch = is.get())!= '<' ) ; is >> line; while (is && (ch = is.get())!= ',' ) ; is >> col; while (is && (ch = is.get())!= '>' ) ; wd._occurList.push_back( Location( line, col )); } return is;
| |
// проверить, находится ли поток "is" в "хорошем" состоянии |
#include #include "WordCount.h" int main() { WordCount readIn; // operator>>( cin, readIn ) cin >> readIn; if ( !cin ) { cerr << "Ошибка ввода WordCount" << endl; return -1; } // operator<<( cout, readIn ) cout << readIn << endl; |
class WordCount { friend ostream& operator<<( ostream&, const WordCount& ); public: WordCount( string word, int cnt=1 ); // ... private: string word; int occurs; }; ostream& operator <<( ostream& os, const WordCount& wd ) { // формат: <счетчик> слово os << "< " << " > " > " << wd.word; return os; |
#include #include "WordCount.h" int main() { WordCount wd( "sadness", 12 ); cout << "wd:\n" << wd << endl; return 0;
| |
// структура перегруженного оператора вывода ostream& operator <<( ostream& os, const ClassType &object ) { // произвольный код для подготовки объекта // фактическое число членов os << // ... // возвращается объект ostream return os; |
#include class Location { friend ostream& operator<<( ostream&, const Location& ); private: short _line; short _col; }; ostream& operator <<( ostream& os, const Location& lc ) { // объект Loc выводится в виде: < 10,37 > os << "<" << lc._line << "," << lc._col << "> "; return os; |
#include #include #include #include "Location.h" class WordCount { friend ostream& operator<<( ostream&, const WordCount& ); public: WordCount() {} WordCount( const string &word ) : _word( word ) {} WordCount( const string &word, int ln, int col ) : _word( word ){ insert_location( ln, col ); } string word() const { return _word; } int occurs() const { return _occurList.size(); } void found( int ln, int col ) { insert_location( ln, col ); } private: void insert_location( int ln, int col ) { _occurList.push_back( Location( ln, col )); } string _word; vector< Location > _occurList; |
ostream& operator <<( ostream& os, const WordCount& wd ) { os << "<" << wd._occurList.size() << "> " << wd._word << endl; int cnt = 0, onLine = 6; vector< Location >::const_iterator first = wd._occurList.begin(); vector< Location >::const_iterator last = wd._occurList.end(); for ( ; first != last; ++first ) { // os << Location os << *first << " "; // форматирование: по 6 в строке if ( ++cnt >= onLine ) { os << "\n"; cnt = 0; } } return os; |
int main() { WordCount search( "rosebud" ); // для простоты явно введем 8 вхождений search.found(11,3); search.found(11,8); search.found(14,2); search.found(34,6); search.found(49,7); search.found(67,5); search.found(81,2); search.found(82,3); search.found(91,4); search.found(97,8); cout << "Вхождения: " << "\n" << search << endl; return 0; |
class Date { public: // ... private: int month, day, year; |
class CheckoutRecord { // запись о выдаче public: // ... private: double book_id; // идентификатор книги string title; // название Date date_borrowed; // дата выдачи Date date_due; // дата возврата pair vector pair |
#include class String; istream& operator>>( istream &, const String & ); ostream& operator<<( ostream &, const String & ); class String { public: // набор перегруженных конструкторов // для автоматической инициализации String( const char* = 0 ); String( const String & ); // деструктор: автоматическое уничтожение ~String(); // набор перегруженных операторов присваивания String& operator=( const String & ); String& operator=( const char * ); // перегруженный оператор взятия индекса char& operator[]( int ); // набор перегруженных операторов равенства // str1 == str2; bool operator==( const char * ); bool operator==( const String & ); // функции доступа к членам int size() { return _size; }; char * c_str() { return _string; } private: int _size; char *_string;
| |
// набор перегруженных операторов присваивания String& operator=( const String & ); |
String name; |
// перегруженный оператор взятия индекса |
if ( name[0] != 'S' ) |
// набор перегруженных операторов равенства // str1 == str2; bool operator==( const char * ); |
#include "String.h" int main() { String name1 "Sherlock"; String name2 "Holmes"; name1 += " "; name1 += name2; if (! ( name1 == "Sherlock Holmes" ) ) cout << "конкатенация не сработала\n"; |
class String { public: // набор перегруженных операторов += String& operator+=( const String & ); String& operator+=( const char * ); // ... private: // ... |
#include inline String& String::operator+=( const String &rhs ) { // Если строка, на которую ссылается rhs, непуста if ( rhs._string ) { String tmp( *this ); // выделить область памяти, достаточную // для хранения конкатенированных строк _size += rhs._size; delete [] _string; _string = new char[ _size + 1 ]; // сначала скопировать в выделенную область исходную строку // затем дописать в конец строку, на которую ссылается rhs strcpy( _string, tmp._string ); strcpy( _string + tmp._size, rhs._string ); } return *this; } inline String& String::operator+=( const char *s ) { // Если указатель s ненулевой if ( s ) { String tmp( *this ); // выделить область памяти, достаточную // для хранения конкатенированных строк _size += strlen( s ); delete [] _string; _string = new char[ _size + 1 ]; // сначала скопировать в выделенную область исходную строку // затем дописать в конец C-строку, на которую ссылается s strcpy( _string, tmp._string ); strcpy( _string + tmp._size, s ); } return *this; |
// определение шаблона класса Array // (см. раздел 2.4) template class Array( /* ... */ }; // три объявления шаблона функции min() template Type min( const Array template Type min( const Type*, int ); // #2 template
| |
#include int main() { Array int ia[1024]; // Type == int; min( const Array int ival0 = min( iA, 1024 ); // Type == int; min( const int*, int ) int ival1 = min( ia, 1024 ); // Type == double; min( double, double ) double dval0 = min( sqrt( iA[0] ), sqrt( ia[0] ) ); return 0;
| |
template
| |
int i; unsigned int ui; // правильно: для T выведен тип int min5( 1024, i ); // вывод аргументов шаблона заканчивается с ошибкой: // для T можно вывести два разных типа |
template
| |
// правильно: int min5( int, usigned int ) |
// ошибка: неоднозначность: две возможных конкретизации // из min5( T, T ) и min5( T, U ) |
// правильно: конкретизация из min5( T, U ) |
template Type sum( Type*, int ); template Type sum( Type, int ); int ia[1024]; // Type == int ; sum // Type == int*; sum |
catch ( pushOnFull ) { cerr << "trying to push value on a full stack\n"; return errorCode88; } catch ( popOnEmpty ) { cerr << "trying to pop a value on an empty stack\n"; return errorCode89; |
int main() { iStack stack( 32 ); try { stack.display(); for ( int x = 1; ix < 51; ++ix ) { // то же, что и раньше } } catch ( pushOnFull ) { cerr << "trying to push value on a full stack\n"; } catch ( popOnEmpty ) { cerr << "trying to pop a value on an empty stack\n"; } // исполнение продолжается отсюда return 0; |
void manip() { resource res; res.lock(); // захват ресурса // использование ресурса // действие, в результате которого возбуждено исключение res.release(); // не выполняется, если возбуждено исключение |
// управление попадает сюда при любом возбужденном исключении catch (...) { // здесь размещаем наш код |
void manip() { resource res; res.lock(); try { // использование ресурса // действие, в результате которого возбуждено исключение } catch (...) { res.release(); throw; } res.release(); // не выполняется, если возбуждено исключение |
try { stack.display(); for ( int ix = 1; ix < 51; ++x ) { // то же, что и выше } } catch ( pushOnFull ) { } catch ( popOnEmpty ) { } |
(a) class exceptionType { }; catch( exceptionType *pet ) { } (b) catch(...) { } (c) enum mathErr { overflow, underflow, zeroDivide }; catch( mathErr &ref ) { } (d) typedef int EXCPTYPE; |
#include
| |
cout << "2 в степени X\t"; |
#include int main() { // objects of type int int value = 2; int pow = 10; cout << value << " в степени " << pow << ": \t"; int res = 1; // оператор цикла: // повторить вычисление res // до тех пор пока cnt не станет больше pow for ( int cnt=1; cnt <= pow; ++cnt ) res = res * value; cout << res << endl; |
int pow( int val, int exp ) |
#include extern int pow(int,int); |
int v1, v2; // ... cout << "сумма v1 и v2 = "; cout << v1 + v2; |
string file_name; // ... cout << "Введите имя файла: "; |
string ifile, ofile; |
string word; |
#include #include int main () { string word; while ( cin >> word ) cout << "Прочитано слово: " << word << "\n"; cout << "Все слова прочитаны!"; |
Прочитано слово: riverrun, Прочитано слово: past Прочитано слово: Eve, Прочитано слово: and Прочитано слово: Adam's |
(a) const vector vector (b) const vector fill( ivec.begin(), ivec.end(), ival ); (c) sort( ivec.begin(), ivec.end() ); (d) list binary_search( ilist.begin(), ilist.end() ); |
| Символ операции | Значение | Использование | |||
| ~ | Побитовое НЕ | ~expr | |||
| << | Сдвиг влево | expr1 << expr2 | |||
| >> | Сдвиг вправо | expr1 >> expr2 | |||
| & | Побитовое И | expr1 & expr2 | |||
| ^ | Побитовое ИСКЛЮЧАЮЩЕЕ ИЛИ | expr1 ^ expr2 | |||
| | | Побитовое ИЛИ | expr1 | expr2 | |||
| &= | Побитовое И с присваиванием | expr1 &= expr2 | |||
| ^= | Побитовое ИСКЛЮЧАЮЩЕЕ ИЛИ с присваиванием | expr1 ^= expr2 | |||
| |= | Побитовое ИЛИ с присваиванием | expr1 |= expr2 | |||
| <<= | Сдвиг влево с присваиванием | expr1 <<= expr2 | |||
| >>= | Сдвиг вправо с присваиванием | expr1 >>= expr2 |
inline boo1 bit_on (unsigned int ui, int pos) { return u1 & ( 1 << pos ); |
enum students { Danny = 1, Jeffrey, Ethan, Zev, Ebie, // ... AnnaP = 26, AnnaL = 27 }; const int student_size = 27; // наш битовый вектор начинается с 1 boo1 has_passed_quiz[ student_size+l ]; for ( int index = 1; index <= student_size; ++-index ) |
Account oldAcct( "Anna Livia Plurabelle" ); |
class Account { public: // ... private: char *_name; unsigned int _acct_nmbr; double _balance; |
inline Account:: Account( const Account &rhs ) { _name = rhs._name; _acct_nmbr = rhs._acct_nmbr; _balance = rhs._balance; |
extern bool cash_on_hand( Account acct ); if ( cash_on_hand( oldAcct )) |
extern Account consolidate_accts( const vector< Account >& ) { Account final_acct; // выполнить финансовую операцию return final_acct; |
// вызывается пять копирующих конструкторов класса string |
inline Account:: Account( const Account &rhs ) { // решить проблему псевдонима указателя _name = new char[ strlen(rhs._name)+1 ]; strcpy( _name, rhs._name ); // решить проблему уникальности номера счета _acct_nmbr = get_unique_acct_nmbr(); // копирование этого члена и так работает _balance = rhs._balance; |
class Account { public: Account(); Account( const char*, double=0.0 ); // ... private: Account( const Account& ); // ... |
class Query { public: // ... protected: int _paren; set vector // ...
| |
inline NotQuery:: NotQuery( const NotQuery &rhs ) // вызывается Query::Query( const Query &rhs ) : Query( rhs ) |
#include "Query.h" int main() { NameQuery nm( "alice" ); NameQuery nm( "emma" ); NotQuery nq1( &nm ); cout << "notQuery 1: " << nq1 << endl; NotQuery nq2( nq1 ); cout << "notQuery 2: " << nq2 << endl; NotQuery nq3( &nm2 ); cout << "notQuery 3: " << nq3 << endl; nq3 = nq2; cout << "notQuery 3 присвоено значение nq2: " << nq3 << endl; AndQuery aq( &nq1, &nm2 ); cout << "AndQuery : " << aq << endl; AndQuery aq2( aq ); cout << "AndQuery 2: " << aq2 << endl; AndQuery aq3( &nm, &nm2 ); cout << "AndQuery 3: " << aq3 << endl; aq2 = aq3; cout << "AndQuery 2 после присваивания: " << aq2 << endl; |
Query& Query:: operator=( const Query &rhs ) { // предотвратить присваивание самому себе if ( &rhs != this ) { _paren = rhs._paren; _loc = rhs._loc; delete _solution; _solution = 0; } return *this; |
inline NotQuery& NotQuery:: operator=( const NotQuery &rhs ) { // предотвратить присваивание самому себе if ( &rhs != this ) { // вызвать копирующий оператор присваивания Query this->Query::operator=( rhs ); // скопировать операнд _op = rhs._op->clone(); } return *this; |
inline Account& Account:: operator=( const Account &rhs ) { _name = rhs._name; _balance = rhs._balance; _acct_nmbr = rhs._acct_nmbr; |
// общий вид копирующего оператора присваивания className& className:: operator=( const className &rhs ) { // не надо присваивать самому себе if ( this != &rhs ) { // здесь реализуется семантика копирования класса } // вернуть объект, которому присвоено значение return *this; |
Account& Account:: operator=( const Account &rhs ) { // не надо присваивать самому себе if ( this != &rhs ) { delete [] _name; _name = new char[strlen(rhs._name)+1]; strcpy( _name,rhs._name ); _balance = rhs._balance; _acct_nmbr = rhs._acct_nmbr; } return *this; |
inline Account& Account:: operator=( const Account &rhs ) { _balance = rhs._balance; _acct_nmbr = rhs._acct_nmbr; // этот вызов правилен и с точки зрения программиста name.string::operator=( rhs._name ); |
Account& Account:: operator=( const Account &rhs ) { // не надо присваивать самому себе if ( this != &rhs ) { // вызывается string::operator=( const string& ) _name = rhs._name; _balance = rhs._balance; } return *this; |
NotQuery *pnq; // установить pnq ... // оператор new вызывает // копирующий конструктор NotQuery ... |
const Query *pq = pnq->op(); |
class Query { public: virtual Query *clone() = 0; // ... |
class NameQuery : public Query { public: virtual Query *clone() // вызывается копирующий конструктор класса NameQuery { return new NameQuery( *this ); } // ... |
Query *pq = new NameQuery( "valery" ); |
NameQuery *pnq = new NameQuery( "Rilke" ); NameQuery *pnq2 = |
class NameQuery : public Query { public: virtual NameQuery *clone() { return new NameQuery( *this ); } // ... |
// Query *pq = new NameQuery( "Broch" ); Query *pq2 = pq->clone(); // правильно // NameQuery *pnq = new NameQuery( "Rilke" ); |
class NotQuery : public Query { public: virtual NotQuery *clone() { return new NotQuery( *this ); } // ... |
extern void manip( int ); int main() { manip( 'a' ); // тип char расширяется до int return 0; |
extern void print( unsigned int ); extern void print( int ); extern void print( char ); unsigned char uc; |
enum Stat ( Fail, Pass ); extern void ff( int ); extern void ff( char ); int main() { // правильно: элемент перечисления Pass расширяется до типа int ff( Pass ); // ff( int ) ff( 0 ); // ff( int ) |
#include string format( int ); string format( unsigned int ); int main() { format(a1); // вызывается format( int ) format(a2); // вызывается format( unsigned int ) return 0; |
extern void print( void* ); extern void print( double ); int main() { int i; print( i ); // соответствует print( double ); // i подвергается стандартному преобразованию из int в double print( &i ); // соответствует print( void* ); // &i подвергается стандартному преобразованию // из int* в void* return 0; |
int i; void calc( float ); int main() { calc( i ); // стандартное преобразование между целым типом и типом с // плавающей точкой потенциально опасно в зависимости от // значения i return 0; |
extern void manip( long ); |
int main() { manip( 3.14 ); // ошибка: неоднозначность // manip( float ) не лучше, чем manip( int ) return 0; |
extern void farith( unsigned int ); extern void farith( float ); int main() { // каждый из последующих вызовов неоднозначен farith( 'a' ); // аргумент имеет тип char farith( 0 ); // аргумент имеет тип int farith( 2uL ); // аргумент имеет тип unsigned long farith( 3.14159 ); // аргумент имеет тип double farith( true ); // аргумент имеет тип bool |
void set(int*); int main() { // преобразование указателя из 0 в int* применяется к аргументам // в обоих вызовах set( 0L ); set( 0x00 ); return 0; |
enum EN { zr = 0 }; |
void print( int ); void print( void * ); void set( const char * ); void set( char * ); int main () { print( 0 ); // вызывается print( int ); set( 0 ); // неоднозначность return 0; |
#include extern void reset( void * ); void func( int *pi, string *ps ) { // ... reset( pi ); // преобразование указателя: int* в void* /// ... reset( ps ); // преобразование указателя: string* в void* |
typedef int (*PFV)(); extern PFV testCases[10]; // массив указателей на функции extern void reset( void * ); int main() { // ... reset( textCases[0] ); // ошибка: нет стандартного преобразования // между int(*)() и void* return 0; |
int max( int, int ); double max( double, double ); int i1; void calc( double d1 ) { max( 56, i1 ); // точно соответствует max( int, int ); max( d1, 66.9 ); // точно соответствует max( double, double ); |
enum Tokens { INLINE = 128; VIRTUAL = 129; }; Tokens curTok = INLINE; enum Stat { Fail, Pass }; extern void ff( Tokens ); extern void ff( Stat ); extern void ff( int ); int main() { ff( Pass ); // точно соответствует ff( Stat ) ff( 0 ); // точно соответствует ff( int ) ff( curTok ); // точно соответствует ff( Tokens ) // ... |
int calc( int ); int main() { int lval, res; lval = 5; // lvalue: lval; rvalue: 5 res = calc( lval ); // lvalue: res // rvalue: временный объект для хранения значения, // возвращаемого функцией calc() return 0; |
int obj1; int obj2; int main() { // ... int local = obj1 + obj2; return 0; |
#include string color( "purple" ); void print( string ); int main() { print( color ); // точное соответствие: преобразование lvalue // в rvalue return 0; |
#include |
list int main() { // ... print( li ); // точное соответствие: нет преобразования lvalue в // rvalue return 0; |
int ai[3]; void putValues(int *); int main() { // ... putValues(ai); // точное соответствие: преобразование массива в // указатель return 0; |
int lexicoCompare( const string &, const string & ); typedef int (*PFI)( const string &, const string & ); void sort( string *, string *, PFI ); string as[10]; int main() { // ... sort( as, as + sizeof(as)/sizeof(as[0] - 1 ), lexicoCompare // точное соответствие // преобразование функции в указатель ); return 0; |
int a[5] = { 4454, 7864, 92, 421, 938 }; int *pi = a; bool is_equal( const int * , const int * ); void func( int *parm ) { // точное соответствие между pi и parm: преобразование спецификаторов if ( is_equal( pi, parm ) ) // ... return 0; |
extern void takeCI( const int ); int main() { int ii = ...; takeCI(ii); // преобразование спецификаторов не применяется return 0; |
extern void init( int *const ); extern int *pi; int main() { // ... init(pi); // преобразование спецификаторов не применяется return 0; |
extern void ff(int); |
// map
| |
int count = 0; if ( word_count.count( "wrinkles" )) |
int count = 0; map if ( it != word_count.end() )
| |
if ( exclusion_set.count( textword )) continue; |
// primer.h namespace cplusplus_primer { // ... void inverse( matrix & ); } // usel.C #include "primer.h" // объявление cplusplus_primer::inverse() в use1.C // use2.C #include "primer.h" |
// ---- primer.h ---- namespace cplusplus_primer { class matrix { /* ... */ }; // объявления функций extern matrix operator+ ( const matrix &m1, const matrix &m2 ); extern void inverse( matrix & ); // объявления объектов extern bool error_state; |
// ---- primer.C ---- #include "primer.h" namespace cplusplus_primer { // определения функций void inverse( matrix & ) { /* ... */ } matrix operator+ ( const matrix &ml, const matrix &m2 ) { /" ... */ } // определения объектов bool error_state = false; |
int main() { readIn(); sort(); compact(); print(); return 0; |
// readIn() возвращает количество прочитанных записей // возвращаемое значение имеет тип int int readIn() { ... } // ... int main() { int count = readIn(); // если количество записей больше 1, // то вызвать sort() и compact() if ( count > 1 ) { sort(); compact(); } if ( count == 0 ) cout << "Продаж не было\n"; else print(); return 0; |
int main() { int iterations = 0; bool continue_loop = true; while ( continue_loop != false ) { iterations++; cout << "Цикл был выполнен " << iterations << "раз\n"; if ( iterations == 5 ) continue_loop = false; } return 0; |
| class Character { ... }; // персонаж class BookCharacter : public Character { ... }; // литературный персонаж class ToyAnimal { ... }; // игрушка class TeddyBear : public BookCharacter, public Bear, public virtual ToyAnimal |
![]() |
![]() |
![]() |
![]() |

int index = iA.find( find_val ); |
#ifndef ARRAY_RC_H #define ARRAY_RC_H #include "Array.h" template class Array_RC : public virtual Array public: Array_RC( int sz = ArraySize ) : Array Array_RC( const Array_RC& r ); Array_RC( const Type *ar, int sz ); Type& operator[]( int ix ); };
| |
Array_RC( int sz = ArraySize ) |
// ошибка: Array - это не спецификатор типа |
#include "Array_RC.h" #include "Array.C" #include template Array_RC : Array template Array_RC : Array template Type &Array_RC assert( ix >= 0 && ix < Array return ia[ ix ]; |
#include "Array_RC.C" #include "try_array.C" int main() { static int ia[] = { 12,7,14,9,128,17,6,3,27,5 }; cout << "конкретизация шаблона класса Array_RC try_array( iA ); return 0; |
#ifndef ARRAY_S_H_ #define ARRAY_S_H_ #include "Array.h" template class Array_Sort : public virtual Array protected: void set_bit() { dirty_bit = true; } void clear_bit() { dirty_bit = false; } void check_bit() { if ( dirty_bit ) { sort( 0, Array clear_bit(); } } public: Array_Sort( const Array_Sort& ); Array_Sort( int sz = Array : Array { clear_bit(); } Array_Sort( const Type* arr, int sz ) : Array { sort( 0,Array Type& operator[]( int ix ) { set_bit(); return ia[ ix ]; } void print( ostream& os = cout ) const { check_bit(); Array Type min() { check_bit(); return ia[ 0 ]; } Type max() { check_bit(); return ia[ Array bool is_dirty() const { return dirty_bit; } int find( Type ); void grow(); protected: bool dirty_bit; };
| |
template Array_Sort |
template Array_Sort |
if ( as.is_dirty() ) |
// альтернативная реализация template Array_Sort Array_Sort( const Array_Sort : Array { dirty_bit = as.dirty_bit; clear_bit(); |
template void Array_Sort { Array sort( 0, Array clear_bit(); |
template int Array_Sort { int low = 0; int high = Array check_bit(); while ( low <= high ) { int mid = ( low + high )/2; if ( val == ia[ mid ] ) return mid; if ( val < ia[ mid ] ) high = mid-1; else low = mid+1; } return -1; |
#include "Array_S.C" #include "try_array.C" #include main() { static int ia[ 10 ] = { 12,7,14,9,128,17,6,3,27,5 }; static string sa[ 7 ] = { "Eeyore", "Pooh", "Tigger", "Piglet", "Owl", "Gopher", "Heffalump" }; Array_Sort Array_Sort cout << "êîíêðåòèçàöèÿ êëàññà Array_Sort << endl; try_array( iA ); cout << "êîíêðåòèçàöèÿ êëàññà Array_Sort << endl; try_array( SA ); return 0; |
#include #include #include #include #include /* * вход: * 23 109 45 89 6 34 12 90 34 23 56 23 8 89 23 * * выход: * 109 90 89 56 45 34 23 12 8 6 */ int main() { istream_iterator< int > input( cin ); istream_iterator< int > end_of_stream; vector copy ( input, end_of_stream, inserter( vec, vec.begin() )); sort( vec.begin(), vec.end(), greater ostream_iterator< int > output( cout, " " ); unique_copy( vec.begin(), vec.end(), output );
| |
catch ( exception eObj ) { if ( canHandle( eObj ) ) // обработать исключение return; else // повторно возбудить исключение, чтобы его перехватил другой // catch-обработчик throw; |
enum EHstate { noErr, zeroOp, negativeOp, severeError }; void calculate( int op ) { try { // исключение, возбужденное mathFunc(), имеет значение zeroOp mathFunc( op ); } catch ( EHstate eObj ) { // что-то исправить // пытаемся модифицировать объект-исключение eObj = severeErr; // предполагалось, что повторно возбужденное исключение будет // иметь значение severeErr throw; } |
catch ( EHstate &eObj ) { // модифицируем объект-исключение eObj = severeErr; // повторно возбужденное исключение имеет значение severeErr throw; |
#include
| |
int ival1 = 10, ival2 = 20; // эквивалентно int sum = ival1 + ival2; |
vector< string > svec; // ... |
class Int { public: Int( int ival = 0 ) : _val( ival ) {} int operator-() { return -_val; } int operator%(int ival) { return -_val % ival; } bool operator<(int ival) { return -_val < ival; } bool operator!() { return -_val == 0; } private: int _val; }; vector< string > svec; string sval1, sval2, sres; complex cval1, cval2, cres; int ival1, ival2, ires; Int Ival1, Ival2, Ires; |
template Type UnaryFunc( FuncObject fob, const Type &val ) { return fob( val ); } template Type BinaryFunc( FuncObject fob, const Type &val1, const Type &val2 )
| |
void print( unsigned int ); void print( const char* ); |
unsigned int a; print( 'a' ); // соответствует print( char ); print( "a" ); // соответствует print( const char* ); |
void ff( char ); |
// функции print() объявлены так же, как и выше int *ip; class SmallInt { /* ... */ }; SmallInt si; print( ip ); // ошибка: нет соответствия |
int ival = 0; // обычно компилируется с предупреждением |
double dva1 = 8.6; int iva1 = 5; |
// инструкция компилятору привести double к int |
class Base {}; template
| |
template
| |
template < typename Type > |
template < class Type > |
// ошибка: Base - это шаблон, // так что должны быть заданы его аргументы template < class Type > |
#ifndef ARRAY_H #define ARRAY_H #include // необходимо для опережающего объявления operator<< template template operator<<( ostream &, Array |