Динамическая идентификация и приведение типов
⇐ ПредыдущаяСтр 7 из 7
7.1. Ошибочные конструкции переведены в примечания. Лишние операции динамического приведения типа заменены операциями присваивания.
k = s; // Приведение производного указателя к базовому // s = dynamic_cast <S *>(k); // Тип К – не полиморфный // l = dynamic_cast <L *>(k); // Тип К – не полиморфный m = s; // Приведение производного указателя к базовому // p = dynamic_cast <P *>(l); // Тип L – не полиморфный q = dynamic_cast <Q *>(m); r = dynamic_cast <R *>(q); // s = dynamic_cast <S *>(p); // Тип P – не полиморфный
7.2. Вариант исправления функции f9() с использованием операции typeid (возможен также вариант исправления с использованием операции dynamic_cast):
void f9 (B & b, D & d, int n) { D * pd = (n > 0)? & d: (D *) & b; if (typeid (* pd) == typeid (d)) strcpy (pd -> y, “one_variant\n”); }
7.3. Вариант исправления функции putnull() с использованием операции typeid (возможен также вариант исправления с использованием операции dynamic_cast): void putnull (B * pb) { try { D d, * pd = (D *) pb; if (typeid (* pb) == typeid (d)) for (int i = 0; i < 30; i++) pd -> mas [i] = 0; } catch (bad_typeid) { cout << “NULL!\n”; } }
7.4. Вариант исправления функции puthi() с использованием операции typeid (возможен также вариант исправления с использованием операции dynamic_cast):
void puthi (B * pb, D * pd) { try { D d; int i = 10; if (typeid (* pb) == typeid (d)) { pd = (D *) pb; while (i) strcpy ((pd -> txt) [--i], “Hi!”); } } catch (bad_typeid) { cout << “NULL!\n”; } }
7.5. В языке Си++ имеются следующие операции преобразования типов:
1. Операция произвольного преобразования типа: int x = (int) 5.0; 2. Операция динамического приведения типа служит для преобразования указателей и ссылок в рамках полиморфных наследственных иерархий классов: class A {... }; class B: A {... }; A * pa, B * pb; pb = dynamic_cast <B *> (pa); 3. Операция статического приведения типа служит для преобразования указателей и ссылок родственных типов из одной иерархии классов (или из типа void *), либо арифметических типов (float => int, int => enum):
A * g (void * p) { A * pa = static_cast <A *>(p); } 4. Операция константного приведения типа отменяет константность или произвольную изменяемость объекта: const int * q =...; int * p = const_cast < int *>(q); volatile int * v =...; int * p = const_cast < int *>(v); 5. Операция reinterpret_cast присваивает указателю значение, относящееся к другой иерархии наследования, либо полученное из произвольного численного значения: int t = 0xf0; p = reinterpret_cast < int *>(t);
7.6. Вариант написания функции f():
B * f (A * p) { B* pb = dynamic_cast <B *> (p); if (pb) return pb; else exit (0); }
7.7. Вариант написания функции f():
C & f (A & ra) { try { C & rc = dynamic_cast <C &>(ra); return rc; } catch (bad_cast) { exit (0); } }
7.8. Вариант написания функции f():
B * f (void * p) { A * pa = static_cast <A *> (p); return dynamic_cast <B *>(pa); }
7.9. Вариант написания функции f():
C * f (B & rb) { try { C & rc = dynamic_cast <C &>(rb); return & rc; } catch (bad_cast) { exit (0); } }
7.10.
· Операция динамического приведения типа dynamic_cast используется для приведения типов указателей и ссылок на полиморфные классы, генерируется исключение bad_cast в случае невозможности приведения типа ссылки на базовый класс к ссылке на производный класс; · Операция определения типа typeid используется для определения типа во время выполнения программы для выражений произвольных типов, но наибольший интерес представляет определение типа объекта, адрес которого находится в указателе или ссылке на полиморфный базовый класс; генерируется исключение bad_typeid в случае разыменования нулевого указателя в качестве параметра операции. Во время работы программы, написанной на языке Си++, использовав операцию typeid, можно сравнить тип исследуемого объекта с типом известного объекта. Операция имеет смысл только для указателей и ссылок на полиморфные типы. Если операнд нужного типа имеет значение 0, операция возбуждает стандартную исключительную ситуацию bad_typeid. Пример программы с использованием операции typeid:
void f (A * pa) { try { B b; /*... */ if (typeid (* pa) == typeid (b)) /*... */ } catch (bad_typeid) { /*... */ } }
Шаблоны 8.2. В качестве параметра шаблона можно использовать либо тип (что показывается служебными словами class, typename, но не struct), либо параметр целочисленного, перечислимого, указательного, ссылочного типа, либо типа «указатель на функцию-член». Типы double, float, myclass, mystruct, struct к таковым не относятся. Ошибки в строках:
template < double f> void funcA (double d = f) { /*...*/ } template < float f> class A { /*...*/ }; template <myclass c> class E { /*...*/ }; template <mystruct a> void funcE (mystruct *p = &a) { /*...*/ } template <struct mystruct> void funcF (mystruct *p = 0) { /*...*/ }
8.3. Будет напечатано: constr constr constr template f operator double operator double c = re=2 im = 7 operator double ordinary f x = -2 template f i = 10 Выбор сделан!
8.4. Будет напечатано: z = 2.8 k = 12 z = 1.5 z = 2.8 s3 = abft Выбор сделан!
8.6. В приведённых вариантах решений применены три разных подхода к реализации операций: реализация методом класса, реализация независимым классом функций-друзей и реализация функциями-друзьями, инстанциируемыми с тем же типовым параметром, что и основной класс, описывающий рациональные дроби:
template < class T> class fr;
/* Предописания функций-друзей, связанных с классом fr */
template < class T> fr<T> & operator += (fr<T> &x, const fr<T> &y); template < class T> fr<T> & operator += (fr<T> &x, const T &y); template < class T> const fr<T> operator + (const fr<T> &x); template < class T> const fr<T> operator + (const fr<T> &x, const fr<T> &y); template < class T> const fr<T> operator + (const T &x, const fr<T> &y); template < class T> const fr<T> operator + (const fr<T> &x, const T &y); template < class T> const bool operator<= (const fr<T> &x, const fr<T> &y); template < class T> const bool operator<= (const T &x, const fr<T> &y); template < class T> const bool operator <= (const fr<T> &x, const T &y); template < class T> const bool operator == (const fr<T> &x, const T &y); template < class T> const bool operator!= (const fr<T> &x, const fr<T> &y); template < class T> const bool operator!= (const fr<T> &x, const T &y);
template < class T> class fr { T n; T d; public: fr (T x = 0, T y = 1): n (x), d (y) { Norm (); }
/* Заголовки методов, реализующих операции класса fr */
fr<T> & operator = (const T &x); fr<T> & operator = (const fr<T> &x); fr<T> & operator -= (const fr<T> &x);
const fr<T> operator - () const; const fr<T> operator * (const T &x) const; const fr<T> & operator ++ (); const fr<T> operator ++ (int p);
/* Заголовки функций-друзей, связанных с классом fr */
friend fr & operator +=<T> (fr &x, const fr &y); friend fr & operator +=<T> (fr &x, const T &y); friend const fr operator + <T> (const fr &x); friend const fr operator + <T> (const fr &x, const fr &y); friend const fr operator + <T> (const T &x, const fr &y); friend const fr operator + <T> (const fr &x, const T &y); friend const bool operator <=<T> (const fr &x, const fr &y); friend const bool operator <=<T>(const T &x, const fr &y); friend const bool operator <=<T>(const fr &x, const T &y); friend const bool operator ==<T>(const fr &x, const T &y); friend const bool operator!=<T>(const fr &x, const fr &y); friend const bool operator!=<T>(const fr &x, const T &y);
/* Заголовки функций-друзей, независящих от класса fr */
template < class T> const bool operator!= (const fr<T> &x, const T &y);
template < class F> friend const fr<F> operator - (const F &x, const fr<F> &y); template < class F> friend const fr<F> operator - (const fr<F> &x, const fr<F> &y); template < class F> friend const fr<F> operator - (const fr<F> &x, const F &y); template < class F> friend const fr<F> operator / (const fr<F> &x, const fr<F> &y); template < class F> friend const bool operator == (const F &x, const fr<F> &y); template < class F> friend const bool operator == (const fr<F> &x, const fr<F> &y); template < class F> friend const bool operator!= (const F &x, const fr<F> &y); template < class F> friend const fr<F>& operator -- (fr<F> &x); template < class F> friend const fr<F> operator -- (fr<F> &x, int);
private: T Nod (T m, T n) { if (m * n == 0) return 1; if (m < 0) m = - m; if (n < 0) n = - n; while (m!= n) m > n? m -= n: n -= m; return m; } void Norm () { T nd = Nod (n, d); if (d < 0) n = -n, d = -d; n /= nd, d /= nd; } };
/* Реализация операций методами класса */
complex (double r = 0, double i = 0)
template < class T> fr<T> & fr<T>:: operator =(const T & x) { n = x; d = 1; return * this; } template < class T> fr<T> & fr<T>:: operator =(const fr<T> & x) { n = x.n; d = x.d; return * this; } template < class T> fr<T> & fr<T>:: operator -=(const fr<T> & x) { n = n * x.d - d * x.n; d *= x.d; Norm (); return * this; } template < class T> const fr<T> fr<T>:: operator -() const { fr<T> w; w.n = - n; w.d = d; w.Norm (); return w; } template < class T> const fr<T> fr<T>:: operator *(const T & x) const { fr<T> w (n * x, d); w.Norm (); return w; } template < class T> const fr<T> & fr<T>:: operator ++ () { n += d; Norm (); return * this; }
template < class T> const fr<T> fr<T>:: operator ++ (int p) { fr<T> w; w = * this; n += d; w.Norm (); return w; }
/* Реализация операций шаблоннымифункциями-друзьями */
template < class T> fr<T> & operator += (fr<T> & x, const fr<T> & y) { x.n = x.n * y.d + x.d * y.n, x.d *= y.d; x.Norm (); return x; } template < class T> fr<T> & operator += (fr<T> & x, const T & y) { x.n += x.d * y; x.Norm (); return x; } template < class T> const fr<T> operator + (const fr<T> & x) { fr<T> w (x); w.Norm (); return w; } template < class T> const fr<T> operator + (const T & x, const fr<T> & y) { fr<T> w (x * y.d + y.n, y.d); w.Norm (); return w; } template < class T> const fr<T> operator + (const fr<T> & x, const T & y) { fr<T> w (x.n + y * x.d, x.d); w.Norm (); return w; } template < class T> const fr<T> operator + (const fr<T> & x, const fr<T> & y) { fr<T> w (x.n * y.d + x.d * y.n, x.d * y.d); w.Norm (); return w; } template < class T> const fr<T> operator - (const T & x, const fr<T> & y) { fr<T> w (x * y.d - y.n, y.d); w.Norm (); return w; } template < class T> const fr<T> operator - (const fr<T> & x, const T & y) { fr<T> w (x.n - y * x.d, x.d); w.Norm (); return w; } template < class T> const fr<T> operator - (const fr<T> & x, const fr<T> & y) { fr<T> w (x.n * y.d - x.d * y.n, x.d * y.d); w.Norm (); return w; } template < class T> const fr<T> operator / (const fr<T> & x, const fr<T> & y) { fr<T> w (x.n * y.d, x.d * y.n); w.Norm (); return w; } template < class T> const bool operator <=(const fr<T> & x, const T & y) { return x.n <= x.d * y; } template < class T> const bool operator <=(const T & x, const fr<T> & y) { return x * y.d <= y.n; } template < class T> const bool operator <=(const fr<T> & x, const fr<T> & y) { return x.n * y.d <= x.d * y.n; } template < class T> const bool operator ==(const T & x, const fr<T> & y) { return x * y.d == y.n; } template < class T> const bool operator ==(const fr<T> & x, const T & y) { return x.n == x.d * y; } template < class T> const bool operator ==(const fr<T> & x, const fr<T> & y) { return x.n * y.d == x.d * y.n; } template < class T> const bool operator!=(const T & x, const fr<T> & y) { return x * y.d!= y.n; } template < class T> const bool operator!=(const fr<T> & x, const T & y) { return x.n!= x.d * y; } template < class T> const bool operator!=(const fr<T> & x, const fr<T> & y) { return x.n * y.d!= x.d * y.n; } template < class T> const fr<T> & operator -- (fr<T> & x) { x.n -= x.d; x.Norm (); return x; } template < class T> const fr<T> operator -- (fr<T> & x, int p) { fr<T> w; w = x; x.n -= x.d; w.Norm (); return w; }
STL
9.1-9.4. Контейнер – это шаблон класса, объекты которого предназначены для хранения объектов других типов. Контейнеры-последовательности: вектор или динамический массив (vector), линейный список (list), двусторонняя очередь (deque). Ассоциативные контейнеры: ассоциативный массив (map), множественный ассоциативный массив (multimap), множества (set) и множества с одинаковыми ключами (multiset). Квазиконтейнеры: встроенный массив (array), строка (string), массив значений (valarray), битовый набор (bitset). Производные контейнеры: очередь (queue), стек (stack), очередь с приоритетами (priority_queue). Контейнер vector требует итераторы произвольного (прямого) доступа, контейнер list требует двунаправленный итератор. Для двунаправленных итераторов допустимы сравнения на равенство и неравенство. Для итераторов произвольного доступа допустимы все шесть видов сравнения (<, <=, ==,!=, >=, >).
9.5-9.10. Итератор – это шаблон класса, объекты которого играют роль указателей по отношению к содержимому контейнеров. В библиотеке определены пять категорий итераторов: ввода, вывода, однонаправленный, двунаправленный, прямого (произвольного) доступа. Они различаются по набору операций, которые должен поддерживать соответствующий класс. Обратные итераторы можно строить для двунаправленных итераторов и итераторов прямого (произвольного) доступа. Для двунаправленных итераторов допустимы сравнения на равенство и неравенство. Существуют прямые и обратные итераторы. Прямые итераторы позволяют перебирать элементы контейнера от первого к последнему. С помощью вызова begin() можно получить доступ к первому элементу контейнера, операция ‘++’ позволяет переходить к следующим за ним элементам. С помощью функции-члена end() определяется факт достижения последнего элемента контейнера (этой функцией выдаётся указатель «на место за последним элементом контейнера»). Обратные итераторы позволяют перебирать элементы контейнера от последнего к первому. С помощью вызова rbegin() можно получить доступ к последнему элементу контейнера, операция ‘++’ позволяет переходить к элементам, ему предшествующим. С помощью функции-члена rend() определяется факт достижения первого элемента контейнера (эта функция выдаёт указатель на место «перед первым элементом контейнера»). Ошибкой для однонаправленных итераторов first и last из следующего примера будет использование операций уменьшения, индексации, вычисления разности итераторов, прибавление к итератору, вычитания из него и любого сравнения на больше или меньше, например:
while (first >= last) first [n ++] = -- last;
Для двунаправленных итераторов определён следующий набор операций:
· …= * p // доступ к элементу контейнера · * p=… // запись элемента контейнера · ++ // продвижение к концу контейнера · -- // продвижение к началу контейнера · == // сравнение двух итераторов на равенство ·!= // сравнение двух итераторов на неравенство
Для итераторов произвольного доступа определён следующий набор операций:
· …= * p // доступ к элементу контейнера · * p=… // запись элемента контейнера · ++ // продвижение к концу контейнера · -- // продвижение к началу контейнера · == // сравнение двух итераторов на равенство ·!= // сравнение двух итераторов на неравенство · < // сравнение двух итераторов на меньше · <= // сравнение двух итераторов на меньше или равно · > // сравнение двух итераторов на больше · >= // сравнение двух итераторов на больше или равно · + // сложение со значением итератора · - // вычитание из значения итератора · += // увеличение значения итератора · -= // уменьшение значения итератора
Пример использования двунаправленного итератора:
# include < iostream > # include < list > using namespace std; void g (list < int > & lst) { list < int >::reverse_iterator rp = lst.rbegin (); while (rp!= lst.rend ()) { cout << *rp << ' '; ++ rp; } cout << endl; }
Пример ошибочного использования двунаправленного итератора:
# include <iostream> # include <list> using namespace std; int g (list < int > & lst) { int S=0; list< int >::iterator p = lst.begin(); for (list< int >::size_type i = 0; i < lst.size ()/2; ++ i) { S += *p; p += 2; } return S; }
Ошибка заключается в том, что итератор списка двунаправленный, а не прямого доступа, следовательно, операция ‘+=’ для этой категории итераторов не определена (то есть конструкция ‘p+=2’ ошибочна, однако, допустимо использование операции ‘++’).
Ошибкой для двунаправленных итераторов first и last будет использование операций индексации, вычисления разности итераторов, прибавление к итератору, вычитания из него и любого сравнения на больше или меньше, например,
while (first >= last) * (first + n ++) = -- last;
Многопроходные алгоритмы требуют прямого и обратного перемещения итераторов по элементам контейнера, поэтому для них допускается использовать только двунаправленные итераторы и итераторы произвольного (прямого) доступа. В дополнение к набору операций, разрешённых для однонаправленных итераторов, для двунаправленных итераторов можно применять итерации уменьшения итераторов (‘p--’ и ‘--p’).
Иерархия итераторов:
9.11. Основная ошибка: итератор для списка двунаправленный, а не прямого доступа, следовательно, операция ‘+=’ для этой категории итераторов не определена (то есть конструкция ‘p+=2’ ошибочна, однако, допустимо использование операции ‘++’). Дополнительная (алгоритмическая) ошибка состоит в том, что в приведённой программе выполняется «пропуск» каждого второго элемента без проверки достижения конца списка.
9.13.
void f (const list < int > & l) { int count = 0; list< int >::const_iterator p = l.begin (); while (p!= l.end ()) if (* p ++ > 0) count ++; cout << count << endl; }
9.14.
void f (const vector < bool > & v) { int count_true = 0; int count_false = 0; vector< bool >::const_iterator p = v.begin (); while (p!= v.end ()) if (* p ++) count_true ++; else count_false ++; cout << count_true << endl; cout << count_false << endl; }
9.15.
void f (const int x, const list < int > & l) { list< int >::const_iterator p = l.begin (); while (p!= l.end ()) if (* p == x) { printf (“Yes\n”); return; } printf (“No\n”); }
9.16.
void f (vector < char > & v) { vector< char >::iterator p = v.begin (); while (p!= v.end ()) { p ++; if (p!= v.end ()) v.erase (p); } vector< char >::const_reverse_iterator rp = v.rbegin (); while (rp!= v.rend ()) { cout << * rp << ‘ ‘; rp ++; } cout << endl; }
9.17.
void g (list < int > & lst) { list< int >::iterator p = lst.begin (); while (p!= lst.end ()) { lst.insert (p, * p); p ++; } list< int >::const_reverse_iterator rp = lst.rbegin (); while (rp!= lst.rend ()) { cout << * rp << ‘ ‘; rp ++; } cout << endl; }
9.18.
typedef vector< float > V; typedef list< float > L; L::size_type g (const V & vect, L & lst, const int step) { V::const_iterator vp = vect.begin (); L::reverse_iterator lp = lst.rbegin (); L::size_type t = 0; do { if (* lp * * vp < 0) * lp = -* lp; if (vect.end () - vp <= step) break; ++ lp; vp += step; } while (lp!= lst.rend ()); L::const_iterator rp = lst.begin (); while (rp!= lst.end ()) { cout << * rp << ‘ ‘; if (* rp >= 0) ++ t; ++ rp; } cout << endl; return t; }
9.19.
typedef vector< int > V; typedef list< int > L; L::size_type g (const V & vect, L & lst, const int step) { V::const_iterator vp = vect.begin (); L::iterator lp = lst.begin (); L::size_type t = 0; do { * lp = * vp; ++ t; if (vect.end () – vp <= step) break; ++ lp; vp += step; } while (vect.end () > vp && lp!= lst.end ()); L::const_reverse_iterator rp = lst.rbegin (); while (rp!= lst.rend ()) { cout << * rp << ‘ ‘; if (* rp >= 0) ++ t; ++ rp; } cout << endl; return t; }
9.20.
typedef vector< long int > VL; typedef list< long int > LL; VL::size_type g (VL & vect, const LL & lst, const int step) { VL::iterator vp = vect.begin (); LL::const_iterator lp = lst.begin (); VL::size_type t = 0; do { if (* lp < 0) * vp = * lp; ++ t; if (vect.end () – vp <= step) break; ++ lp; vp += step; } while (lp!= lst.end ()); VL::const_iterator rp = vect.begin (); while (rp!= vect.end ()); { cout << * rp << ‘ ‘; if (* rp >= 0) ++ t; ++ rp; } cout << endl; return t; }
9.21.
typedef vector< int > V; typedef list< int > L; L::size_type g (const V & vect, L & lst, const int step) { V::const_iterator vp = vect.begin (); L::iterator lp = lst.begin (); L::size_type t = 0; do { * lp = * vp; ++ t; if (vect.end () – vp <= step) break; ++ lp; vp += step; } while (vect.end () > vp && lp!= lst.end ()); L::const_reverse_iterator rp = lst.rbegin (); while (rp!= lst.rend ()) { cout << * rp << ‘ ‘; if (* rp >= 0) ++ t; ++ rp; } cout << endl; return t; }
9.22.
typedef vector< double > V; typedef list< double > L; L::size_type g (const V & vect, L & lst, const int step) { V::const_iterator vp = vect.begin (); L::iterator lp = lst.begin (); L::size_type t = 0; do { if (* lp!= * vp) lst.insert (lp, * vp); ++ t; if (vect.end () – vp <= step) break; ++ lp; vp += step; } while (lp!= lst.end ()); L::const_reverse_iterator rp = lst.rbegin (); while (rp!= lst.rend ()) { cout << * rp << ‘ ‘; if (* rp >= 0) ++ t; ++ rp; } cout << endl; return t; }
9.23.
typedef vector< int *> V; V::size_type g (V & vect) { V::size_type i = 0, j = vect.size () - 1; V::size_type count = 0; for (; i < j; ++ i, -- j) { V::value_type t = vect [i]; vect [i] = vect [j]; vect[j] = t; ++ count; } return count; }
9.24.
typedef vector< float *> V; V::size_type g (V & vect) { V::size_typecount = 0, vs = vect.size () - 1; for (V::size_type i = 0; i < vs; i += 2) if (* vect [i + 1] < 0) { * vect [i] = 0; ++ count; } for (V::size_type i = vs; i > 0; -- i) cout << * vect [i]; return count; }
9.26.
typedef list< int > L; typedef vector<L::value_type *> V; L::size_type g (V & vect, L & lst) { L::size_type count = 0; L::reverse_iterator lp = lst.rbegin (); for (V::size_type i = 0; i < vect.size () && lp!= lst.rend (); ++i, ++lp) { L::value_type t = * lp; * lp = * vect [i]; * vect [i] = t; ++ count; } L::const_iterator lq = lst.begin (); while (lq!= lst.end ()) { cout << * lq << ‘ ‘; ++ lq; } cout << endl; for (V::size_type i = 0; i < vect.size (); ++ i) cout << * vect [i] << ‘ ‘; cout << endl; return count; } 9.27. typedef vector< int > V; V::size_type g (V & vect) { V::size_type count = 0; for (V::size_type i = vect.size () – 1; i > 0; -- i) { V::value_type e_even, e_odd; e_even = vect [i]; -- i; e_odd = vect [i]; if (e_even >= e_odd) continue; vect [i + 1] = e_odd; vect [i] = e_even; ++ count; } for (V::size_type i = 0; i < vect.size (); ++ i) cout << vect [i] << ‘ ‘; cout << endl; return count; }
9.28.
typedef vector< int > V; V::size_type g (V & vect) { V::size_type count = 0; double s = 0.0; for (V::size_type i = 0; i < vect.size (); ++ i) s += vect [i]; s /= vect.size (); for (V::size_type i = vect.size () -1; i >=0; --i) { cout << vect [i] << ‘ ‘; if (vect [i] > s) ++ count; } return count; }
9.29.
template < class T> void f (const T & t) { if (t.size () < 2) return; typename T::const_reverse_iterator p = t.rbegin (); cout << * ++ p << endl; } int main () { list< int > lst; for (int i = 0; i < 5; ++ i) lst.push_back (i); f (lst); return 0; }
9.30.
template < class T> void f (const T & t) { if (t.size () < 3) return; typename T::const_reverse_iterator p = t.rbegin (); cout << * p + * ++ p + * ++ p << endl; } int main () { vector< int > vec; for (int i = 0; i < 5; ++ i) vec.push_back (i); f<vector< int > > (vec); return 0; }
9.31.
template < class T> void f (const T & t) { typename T::const_reverse_iterator p = t.rbegin (); for (typename T::size_type i = 0; i < t.size () / 2; ++ i) cout << * (p ++, p ++) << endl; }
int main () { list< int > lst; for (int i = 0; i < 5; ++ i) lst.push_back (i); f<list< int > > (lst); return 0; }
9.32.
typedef vector< int > V; struct Weight_t { V::size_type Index; float Weight; }; typedef list<Weight_t> L; float g (const V & vect, const L & lst) { L::const_iterator lp = lst.begin (); V::size_type t, n = 0; float vw, w = 0.0f; while (lp!= lst.end ()) { t = (* lp).Index; vw = (* lp).Weight; ++ lp; if (t < 0 || t >= vect.size ()) continue; cout << vect [t] << ‘ ‘ << vw << endl; w += vect [t] * vw; ++ n; } return n? w / n: 0.0f; }
9.33.
typedef vector< double > V; struct Signif_t { V::size_type Index; bool Signif; }; typedef list<Signif_t> S; double g (const V & vect, const S & lst) { S::const_iterator lp = lst.begin (); bool sg; V::size_type t; double w = 0.0; while (lp!= lst.end ()) { t = (* lp).Index; sg = (* lp).Signif; ++ lp; if (t < 0 || t >= vect.size ()) continue; if (sg) { cout << t << ‘ ’ << vect [t] << endl; w += vect [t]; } } return w; }
9.34.
typedef vector< bool > B; struct Value_t { B::size_type Index; // индекс элемента вектора int Value; // значение элемента }; typedef list<Value_t> T; int g (const B & vect, const T & lst) { T::const_reverse_iterator lp = lst.rbegin (); B::size_type t; int vl; int w = 0; while (lp!= lst.rend ()) { t = (* lp).Index; vl = (* lp ++).Value; if (t < 0 || t >= vect.size ()) continue; if (vect [t]) w += vl; cout << t << ‘ ‘ << vl << ‘ ‘ << vect [t] << endl; } return w; }
9.35.
struct Value_t { bool Signif; // значимость элемента (true – да) int Value; // значение элемента вектора }; typedef vector< Value_t> B; typedef list< B::size_type> T; int g (const B & vect, const T & lst) { T::const_reverse_iterator lp = lst.rbegin (); B::size_type t; int vl; bool bl; int w = 0; while (lp!= lst.rend ()) { t = * lp ++; if (t < 0 || t >= vect.size ()) continue; vl = vect [t].Value; bl = vect [t].Signif; if (bl) w += vl; cout << t << ‘ ‘ << vl << ‘ ‘ << bl << endl; } return w; } III. Литература
СОДЕРЖАНИЕ
I. Задачи и упражнения 1. Абстрактные типы данных (АТД). Классы Конструкторы и деструкторы 1 2. Перегрузка операций. Перегрузка функций 11 3. Наследование. Видимость и доступность имен 13 4. Виртуальные функции. Абстрактные классы 22 5. Аппарат исключений 29 6. Константные и статические члены класса 39 7. Динамическая идентификация и приведение типов 45 8. Шаблоны 47 9. STL 50
II. Ответы и решения 1. Абстрактные типы данных (АТД). Классы Конструкторы и деструкторы 56 2. Перегрузка операций. Перегрузкатфункций 59 3. Наследование. Видимость и доступность имен 60 4. Виртуальные функции. Абстрактные классы 64 5. Аппарат исключений 66 6. Константные и статические члены класса 67 7. Динамическая идентификация и приведение типов 69 8. Шаблоны 72 9. STL 76 III. Литература 86 [1] Везде, где это необходимо, предполагается наличие #include<iostream> и using namespace std.
Воспользуйтесь поиском по сайту: ©2015 - 2024 megalektsii.ru Все авторские права принадлежат авторам лекционных материалов. Обратная связь с нами...
|