Динамическая идентификация и приведение типов
7.1. Укажите лишние и ошибочные операции динамического приведения типа, если таковые имеются в функции main(). Дайте необходимые пояснения своим исправлениям. class K { public: void g () { cout << "K::g"; } }; class L: public K { public: void f () { cout << "L::f"; } }; class M: public K { public: virtual void h () { cout << "M::h"; } }; class P: public L { public: void f () { cout << "P::f"; } }; class Q: public M { public: virtual void h () { cout << "Q::h"; } }; class R: public P { public: virtual void f () { cout << "R::f"; } virtual void h () { cout << "R::h"; } }; class S: public Q { public: virtual void f () { cout << "S::f"; } virtual void h () { cout << "S::h"; } }; int main (){ S os, * s = & os; K * k; L * l; M * m; P * p; Q * q; R * r; int a, b; k = dynamic_cast <K *>(s); s = dynamic_cast <S *>(k); l = dynamic_cast <L *>(k); m = dynamic_cast <M *>(s); p = dynamic_cast <P *>(l); q = dynamic_cast <Q *>(m); r = dynamic_cast <R *>(q); s = dynamic_cast <S *>(p); return 0; }
7.2. Добавить в функцию f9() использование механизма приведения типов так, чтобы ее выполнение всегда завершалось нормально.
struct B { virtual void g () {} }; struct D: B { char y [100]; }; void f9 (B & b, D & d, int n) { D * pd = (n > 0)? & d: (D *) & b; strcpy (pd -> y, “one_variant\n”); }
7.3. Добавить в функцию putnull() использование механизма приведения типов так, чтобы ее выполнение всегда завершалось нормально.
struct B { virtual void empty () {} }; struct D: B { int mas [30]; }; void putnull (B * pb){ D * pd = (D *) pb; if (! pb) return; for (int i = 0; i < 30; i++) pd -> mas [i] = 0; }
7.4. Добавить в функцию puthi() использование механизма приведения типов, так, чтобы ее выполнение всегда завершалось нормально.
struct B { virtual void hi () { cout << “Hi!” << endl; } }; struct D: B { char txt [10] [4]; }; void puthi (B * pb, D * pd) { int i = 10; if (! pb) return; pd = (D *) pb; while (i) strcpy ((pd -> txt) [--i], ”Hi!”); }
7.5. Какие виды операций преобразования типов имеются в языке Си++? Укажите назначение каждого вида, приведите пример записи каждой из перечисленных операций.
7.6. Для приведённой ниже программы описать функцию f(), которая, получая в качестве параметра указатель типа A*, возвращает его значение, наиболее безопасным образом преобразованное к типу B*, а в случае невозможности преобразования корректно завершает работу программы.
struct A { virtual void z () {} }; struct B: A { int x; B (int y = 5) { x = y; } }; B * f (A * pa); int main (){ try { B b, * pb = f (& b); cout << pb -> x << endl; A a; pb = f (& a); cout << pb -> x << endl; } catch (...) { } return 0; }
7.7. Для приведённой ниже программы описать функцию f(), которая, получая в качестве параметра ссылку на объект базового класса A, возвращает ссылку на объект производного класса C, полученную наиболее безопасным образом, а в случае невозможности приведения типов корректно завершает программу.
struct A { virtual void z () {} }; struct B: A { }; struct C: B { int x; C (int n = 3) { x = n; } }; C & f (A & ra); int main () { C c, & pc = f (& c); cout << pc.x << endl; return 0; }
7.8. Для приведённой ниже программы описать функцию f(), которая, получая в качестве параметра ссылку на объект типа void *, возвращает ссылку на объект производного класса B, полученную наиболее безопасным образом, а в случае невозможности приведения типов корректно завершает программу.
struct A { virtual void z () {} }; struct B: A { int x; B (int n = 7) { x = n; } }; B * f (void * p); int main () { B b, * pb = f (& b); cout << pb -> x << endl; return 0; } 7.9. Для приведённой ниже программы описать функцию f(), которая, получая в качестве параметра ссылку на объект класса B, возвращает указатель на объект класса C, полученный наиболее безопасным образом, а в случае невозможности приведения типов корректно завершает программу.
struct A { int x; virtual void z () {} }; struct B: A { int x; }; struct C: B { int x; C (int n = 4) { x = n; } }; C * f (B & rb); int main () { C c, * pc = f (c); cout << pc -> x << endl; return 0; }
7.10. Можно ли получить информацию о типе объекта во время работы программы на Си++? Какие операции языка Си++ используются в подобных случаях?
Для объектов каких типов эти операции имеют смысл? Какие стандартные исключения генерируются в результате выполнения этих операций? Привести пример программы, в которой используются эти операции.
Шаблоны
8.1. Привести пример использования параметрического полиморфизма в Си++.
8.2. Есть ли ошибки в следующих заголовках шаблонов? Если есть, поясните, в чём они заключаются.
template < double f> void funcA (double d = f) { /*...*/ } template < float f> class A { /*...*/ }; template < int n> class B { /*...*/ }; template < int n> void funcB (int t = n) { /*...*/ } template < class Cs> class C { /*...*/ }; template < class Cs> struct D { /*...*/ }; template < class Cs> void funcC (const Cs& ref) { /*...*/ } class myclass { public: myclass() {} }; template <myclass c> class E { /*...*/ }; struct mystruct { int a, b; }; template < class mystruct> void funcD (mystruct *p = 0) { /*...*/ } template <mystruct a> void funcE (mystruct *p = &a) { /*...*/ } template < struct mystruct> void funcF (mystruct *p = 0) { /*...*/ }
8.3. Есть ли ошибки в приведенном фрагменте программы на Си++? Если есть, то объясните, в чем они заключаются. Ошибочные конструкции вычеркните из текста программы. Что будет напечатано при вызове функции main ()? class complex { double re, im; public: complex (double r = 0, double i = 0) { re = r; im = i; cout << “constr” << endl; } operator double () { cout << “ operator double ” << endl; return re; } double get_re () { return re; } void print() const { cout << "re=" << re << " im=" << im << endl; } };
template < class T> T f (T& x, T& y) { cout << " template f" << endl; return x > y? x: y; }
double f (double x, double y) { cout << "ordinary f" << endl; return x > y? –x: –y; }
int main () { complex a(2, 5), b(2, 7), c; double x = 3.5, y = 1.1; int i, j = 8, k = 10; c = f (a, b); cout << "c = "; c.print (); x = f (a, y); cout << "x = " << x <<endl; i = f (j, k); cout << "i = " << i <<endl; cout << "Выбор сделан!" << endl; return 0; }
8.4. Есть ли ошибки в приведенном фрагменте программы? Если есть, то объясните, в чем они заключаются. Ошибочные конструкции вычеркните из текста программы. Что будет напечатано при вызове функции main ()? Перегрузите шаблонную функцию max так, чтобы сравнение строк осуществлялось лексикографически (то есть в соответствии с кодировкой символов).
template < class T> T max (T& x, T& y) { return x > y? x: y; } int main () { double x = 1.5, y = 2.8, z; int i = 5, j = 12, k; char * s1 = "abft"; char * s2 = "abxde", * s3; z = max (x, y); cout << "z = "<< z << endl;
k = max < int >(i, j); cout << "k = "<< k << endl; z = max (x, (double &) i); cout << "z = "<< z << endl; z = max (y, (double &) j); cout << "z = "<< z << endl; s3 = max (s1, s2); cout << "s3 = "<< s3 << endl; cout << "Выбор сделан!" << endl; return 0; }
8.5. Какие из следующих утверждений являются верными, а какие – ошибочными? Объясните, в чем заключаются эти ошибки.
8.6. Для класса рациональных дробей с числителями и знаменателями некоторого интегрального типа
template < class T> class fr { T n; T d;... };
описать два варианта (методом класса и функцией-другом этого класса) реализации вне класса операций, либо объяснить, почему какой-либо из вариантов невозможен:
· ‘+’, выполняющей сокращение числителя и знаменателя рациональной дроби, если они имеют общие множители (унарный ‘+’). · ‘+’, выполняющей сложение двух рациональных дробей, либо рациональной дроби и значения соответствующего интегрального типа. · ‘-’, выполняющей изменение знака рациональной дроби (унарный ‘-’). · ‘-’, выполняющей вычитание двух рациональных дробей, либо рациональной дроби и значения соответствующего интегрального типа. · ‘*’, выполняющей умножение одной рациональной дроби на другую, либо рациональной дроби на значение соответствующего интегрального типа. · ‘/’, выполняющей деление одной рациональной дроби на другую, либо рациональной дроби на значение соответствующего интегрального типа. · ‘=’, выполняющей присваивание рациональной дроби значения другой рациональной дроби, либо значения соответствующего интегрального типа. · ‘+=’, выполняющей увеличение рациональной дроби на рациональное значение, либо на значение соответствующего интегрального типа. · ‘-=’, выполняющей уменьшение рациональной дроби на рациональное значение, либо на значение соответствующего интегрального типа.
· ‘*=’, выполняющей присваивание с умножением рациональных дробей, либо с умножением рациональной дроби на значение соответствующего интегрального типа. · ‘/=’, выполняющей присваивание с делением рациональных дробей, либо с делением рациональной дроби на значение соответствующего интегрального типа. · ‘==’, выполняющей сравнение двух рациональных дробей, либо сравнение рациональной дроби со значением соответствующего интегрального типа. · ‘!=’, выполняющей сравнение двух рациональных дробей, либо сравнение рациональной дроби со значением соответствующего интегрального типа. · ‘<’, выполняющей сравнение двух рациональных дробей, либо сравнение рациональной дроби со значением соответствующего интегрального типа. · ‘>’, выполняющей сравнение двух рациональных дробей, либо сравнение рациональной дроби со значением соответствующего интегрального типа. · ‘<=’, выполняющей сравнение двух рациональных дробей, либо сравнение рациональной дроби со значением соответствующего интегрального типа. · ‘>=’, выполняющей сравнение двух рациональных дробей, либо сравнение рациональной дроби со значением соответствующего интегрального типа. · увеличения ‘++’, выполняющей увеличение на 1 значения рациональной дроби. · уменьшения ‘--’, выполняющей уменьшение на 1 значения рациональной дроби. · ‘<<’, выполняющей вывод в текстовый поток значения рациональной дроби в виде “числитель/знаменатель”. · других операций, представляющихся полезными при работе с рациональными дробями.
STL
9.1. Дать определение контейнера. Каково назначение контейнеров?
9.2. Перечислить основные контейнеры библиотеки STL.
9.3. Какие виды итераторов допускают контейнеры vector и list?
9.4. Какие виды операций сравнения итераторов допустимы для этих контейнеров?
9.5. Дать определение итератора.
9.6. Какие категории итераторов определены в STL? Чем отличаются друг от друга итераторы разных категорий?
9.7. Чем различаются прямые и обратные итераторы? Привести пример использования обратного итератора. Какие виды итераторов допускают обратные итераторы?
9.8. Какие виды операций сравнения итераторов допустимы для двунаправленных итераторов? Привести пример ошибочного использования двунаправленного итератора.
9.9. Сравнить возможности, предоставляемые двунаправленным итератором и итератором произвольного доступа.
9.10. Перечислить типы итераторов библиотеки STL, допускающих использование в многопроходных алгоритмах. Сравнить наборы операций, предоставляемые одно- и двунаправленными итераторами.
Привести по одному примеру ошибочного использования одно- и двунаправленных итераторов.
9.11. Верно ли решена задача: «Описать функцию, суммирующую значения элементов списка, стоящих на нечетных местах, считая, что элементы списка нумеруются с 1»? Если есть ошибки, объясните, в чем они заключаются и как их исправить.
# include <iostream> # include <list> using namespace std;
int main () int g (list < int > & lst){ int S=0; list< int >:: iterator p = lst.begin(); while (p!= lst.end()) { S += * p; p += 2; } return S; };
9.12. Описать функцию, которая добавляет после каждого элемента заданного контейнера-списка list < int > еще один такой же элемент, но с обратным знаком, а затем исключает из списка все отрицательные элементы и распечатывает результат.
9.13. Описать функцию, которая считает количество положительных элементов заданного контейнера-списка list< int >, а затем распечатывает это значение (выдает в стандартный поток cout).
9.14. Описать функцию, которая, не возвращая никакого значения, по заданному контейнеру vector< bool > считает количество истинных и ложных элементов в нем, а затем выдаёт эти значения в стандартный поток cout.
9.15. Описать функцию, которая печатает «Yes» или «No» в зависимости от того, содержится ли заданное целое число x в заданном контейнере-списке list< int >.
9.16. Описать функцию, которая удаляет каждый второй элемент заданного контейнера-вектора vector< char >, а затем распечатывает его элементы в обратном порядке.
9.17. Описать функцию, которая удваивает (добавляет еще один такой же) каждый элемент заданного контейнера-списка list < int >, а затем распечатывает его элементы в обратном порядке.
9.18. Описать функцию g() с тремя параметрами: непустой и неизменяемый контейнер-вектор типа vector< float >, непустой контейнер-список типа list< float >, целое число – шаг по первому контейнеру. Функция должна исследовать элементы списка, выбираемые от его конца с шагом, равным 1, и элементы вектора, выбираемые от его начала с шагом, равным третьему параметру. Если обнаруживаются пары элементы разных знаков, то у текущего элемента списка должен меняться знак. Изменённый список распечатывается в прямом порядке. Функция возвращает общее количество неотрицательных элементов списка.
9.19. Описать функцию g() с тремя параметрами: непустой контейнер-вектор типа vector< int >, непустой контейнер-список типа list< int >, целое число – шаг по первому контейнеру. Функция должна, последовательно проходя по списку от начала к концу, перезаписывать на место очередного его элемента соответствующий очередному шагу элемент вектора (сам вектор при этом не изменяется), а затем распечатывать элементы списка в обратном порядке. Функция возвращает количество изменённых элементов списка.
9.20. Описать функцию g() с тремя параметрами: непустой и неизменяемый контейнер-список типа list< longint >, непустой контейнер-вектор типа vector< longint >, целое число – шаг по второму контейнеру. Функция должна копировать отрицательные элементы списка с шагом, равным 1, в уже имеющийся контейнер-вектор, от его начала к концу с шагом, равным третьему параметру, а затем распечатывать элементы вектора в прямом порядке. Функция возвращает количество измененных элементов вектора.
9.21. Описать функцию g() с тремя параметрами: непустой контейнер-вектор типа vector< int >, непустой контейнер-список типа list< int >, целое число – шаг по первому контейнеру. Функция должна, последовательно проходя по списку от начала к концу, перезаписывать на место очередного его элемента соответствующий очередному шагу элемент вектора (сам вектор при этом не изменяется), а затем распечатывать элементы списка в обратном порядке. Функция возвращает количество изменённых элементов списка.
9.22. Описать функцию g() с тремя параметрами: непустой и неизменяемый контейнер-вектор типа vector< double >, непустой контейнер-список типа list< double >, целое число – шаг по первому контейнеру. Функция должна сравнивать элементы списка, выбираемыми от его начала с шагом, равным 1, с элементами вектора, выбираемыми от начала с шагом, равным третьему параметру. Если обнаруживается несовпадение очередной выбранной пары, то в список в текущем месте вставляется отсутствующий элемент. Изменённый список распечатывается в обратном порядке. Функция возвращает количество элементов, вставленных в список.
9.23. Описать функцию g() с параметром, представляющим собой контейнер-вектор элементов целого типа. Функция должна менять местами значения элементов вектора, одинаково удалённых от начала и конца вектора (первого с последним, второго с предпоследним и т. д.). Функция возвращает число сделанных перестановок.
9.24. Описать функцию g() с параметром, представляющим собой контейнер-вектор указателей на элементы вещественного типа. Считая от начала контейнера, функция должна обнулять значения, на которое указывают указатели с четными номерами, если значения, на которые указывают указатели с нечетными номерами, отрицательны, а затем распечатывать значения, на которые указывают элементы контейнера в обратном порядке. Функция возвращает число измененных значений.
9.25. Описать функцию g() с параметром, представляющим собой контейнер-список указателей на элементы длинного целого типа. Функция, просматривая контейнер от конца к началу, меняет знак значения, на которое указывает указатель с четным номером, если значение, на которое указывает указатель с нечетным номером, отрицательно, а затем распечатывать значения, на которые указывают элементы контейнера в прямом порядке. Функция возвращает число измененных элементов.
9.26. Описать функцию g() с параметрами, представляющими собой контейнер-список целых элементов и контейнер-вектор указателей на элементы такого же типа. Функция должна, последовательно проходя по элементам контейнеров от начала к концу вектора и от конца к началу списка, менять местами элементы контейнеров, а затем распечатывать целые значения элементов контейнеров в прямом порядке (сначала весь список, затем вектор). Функция возвращает количество переставленных элементов контейнеров.
9.27. Описать функцию g() с параметром, представляющим собой контейнер-вектор элементов целого типа. Функция должна менять местами значения соседних элементов с четным и нечетным номерами, считая от конца контейнера, если четный элемент меньше нечетного, а затем распечатывать значения элементов контейнера в прямом порядке. Функция возвращает число измененных значений.
9.28. Описать функцию g() с параметром, представляющим собой контейнер-вектор элементов целого типа. Функция должна считать число элементов, значения которых превосходят среднее значение элементов вектора, и распечатывать элементы контейнера в обратном порядке. Функция возвращает число измененных значений.
9.29. Описать функцию-шаблон (от одного параметра, который может быть контейнером STL, например, вектором целых чисел), которая для любого последовательного контейнера STL распечатывает его предпоследний элемент, если таковой имеется, а также функцию main(), которая формирует контейнер-список из 5 целых чисел и применяет к нему описанную функцию-шаблон.
9.30. Описать функцию-шаблон (от одного параметра, который может быть контейнером STL, например, вектором целых чисел), которая для любого последовательного контейнера STL распечатывает сумму его трёх последних элементов, если таковые имеются, а также функцию main(), которая формирует контейнер-вектор из 5 целых чисел и применяет к нему описанную функцию-шаблон.
9.31. Описать функцию-шаблон (от одного параметра, который может быть контейнером STL, например, списком целых чисел), которая для любого последовательного контейнера STL распечатывает каждый второй элемент, начиная с конца, а также функцию main(), которая формирует контейнер-список из 5 целых чисел и применяет к нему описанную функцию-шаблон.
9.32. Даны описания:
typedef vector< int > V; struct Weight_t { V::size_type Index; // индекс элемента вектора float Weight; // вес элемента вектора }; typedef list<Weight_t> L;
Описать функцию g(), которая по заданному вектору типа V и соответствующему ему списку типа L, просматривая список от начала к концу, вычисляет средневзвешенное значение обнаруженных элементов вектора (средний результат умножения элементов на их веса), выдавая в выходной поток значения и веса элементов.
9.33. Даны описания:
typedef vector< double > V; struct Signif_t { V::size_type Index; // индекс элемента вектора bool Signif; // значимость элемента (true – да) }; typedef list<Signif_t> S;
Описать функцию g(), которая по заданному вектору типа V и соответствующему ему списку типа S, просматривая список от начала к концу, вычисляет сумму обнаруженных значащих элементов вектора, выдавая в выходной поток индексы и значения суммируемых элементов.
9.34. Даны описания:
typedef vector< bool > B; struct Value_t { B::size_type Index; // индекс элемента вектора int Value; // значение элемента }; typedef list<Value_t> T;
Описать функцию g(), которая по заданному вектору значимости типа B и соответствующему ему списку типа T, просматривая список от конца к началу, выдаёт в выходной поток значения целочисленных полей элементов списка, сопровождаемое их значимостью, вычисляет сумму значимых целочисленных полей списка и возвращает это значение.
9.35. Даны описания:
struct Value_t { bool Signif; // значимость элемента (true – да) int Value; // значение элемента вектора }; typedef vector< Value_t> B; typedef list< B::size_type> T;
Описать функцию g(), которая по заданному вектору типа B и соответствующему ему списку типа T, просматривая список от конца к началу, вычисляет сумму значимых целочисленных полей элементов вектора, и возвращает это значение, одновременно выдавая в выходной поток значения всех целочисленных полей элементов вектора, сопровождаемые их значимостью.
II. Ответы и решения
Воспользуйтесь поиском по сайту: ©2015 - 2024 megalektsii.ru Все авторские права принадлежат авторам лекционных материалов. Обратная связь с нами...
|