Главная | Обратная связь | Поможем написать вашу работу!
МегаЛекции

Динамическая идентификация и приведение типов




 

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. Литература

 

  1. Standard for the C++ Programming Language ISO/IEC 14882, 1998.
  2. Страуструп Б. Язык программирования C++. Специальное изд./Пер. с англ. - М.: "Бином", 2005.
  3. Волкова И.А, Иванов А.В., Карпов Л.Е. Основы объектно-ориентированного программирования. Язык программирования Си++. М.: МГУ, МАКС Пресс, 2011.-112с.

СОДЕРЖАНИЕ

 

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 Все авторские права принадлежат авторам лекционных материалов. Обратная связь с нами...