С++, ООП Семинар 2 Рябова Анна Сергеевна
Задание 2 Реализовать шаблон класса для хранения динамического контейнера – очереди (FIFO) / стека(LIFO) / дека(двунаправленной очереди) элементов типа T template class Deque { … public: push_back(const T& Element)//Add element at the end push_front(const T& Element)//Insert element at beginning pop_back()//Delete last element pop_front()//Delete first element … }; Необходимо реализовать: на тройку: Операцию вставки (push, pop) в начало (стек, дек) или конец (дек, очередь) контейнера Операцию удаления из начала (стек, очередь, дек) или из конца(дек) Деструктор, освобождающий всю выделенную память ! Программу, демонстрирующую все вышеперечисленное на четверку Операцию объединения с контейнером того же типа Deque& addAll(const Deque& additional) Запрет использования конструктора копирования и оператора присваивания Программу, демонстрирующую эти возможности на пятерку Класс-итератор, перебирающий элементы контейнера при вызове ++, для которого определены операторы * и -> Программу, демонстрирующую работу итератора
Шаблоны (templates) Перегрузка функций int max(int x, int y) { return x>y ? x : y ; } double max(double x, double y) { return x>y ? x : y ; } Одинаковая реализация, отличие лишь в типе аргументов Используем шаблон template T max(T x, T y) { return x>y ? x : y; } Ключевое слово typename или class template... //всегда будут использоваться классы template... //могут появиться типы int, char Если в программе появится вызов max() c двумя аргументами одного типа, то транслятор создаст для него по шаблону соответсвующую функцию (если он это не сделал раньше). max('c','d'); // instantiate max(char,char) max(1.0,2.0); // instantiate max(double,double) max('c','d'); // max(char,char) already exists
Шаблоны (templates) Похоже на макроподстановки, но текстовая замена формального параметра шаблона на реальный тип происходит не в месте, где max() используется, а в теле автоматически созданной по заданному образцу функции. Шаблону можно указать несколько параметров- типов. template int maxsize(T1 a, T2 b) { int size_a = sizeof(a); int size_b = sizeof(b); return size_a>size_b ? size_a : size_b; }
Шаблоны (templates): подводные камни Транслятор создает по шаблону тела функций, точно соответсвующие сигнатуре вызова. Можно было обойтись одной функцией с сигнатурой, совместимой сразу с несколькими вызовами. Программа "распухает" - код автоматически сгенерированных функций занимает необоснованно много места в памяти. Текстовая замена формального типа на фактический в теле шаблона порой приводит к весьма причудливым конструкциям, которые могут давать ошибки при трансляции, или работать совсем не так, как замышлялось разработчиком шаблона. Старые компиляторы могут плохо поддерживать шаблоны
Шаблоны классов template class Vector { private: T arr[2]; public: Vector(T a, T b) { arr[0] = a; arr[1] = b; } T operator[](int index) const { if (index = 2) throw "error"; return arr[index]; } }; Vector v1(1, 2); Vector v1(1.5, 2.2);
Исключения (exceptions) С++-механизм для обработки ошибок Когда какая-нибудь функция обнаруживает ошибку, она сообщает об этом вызывающему коду, посылая исключение. unsigned factorial(unsigned val) { if (val > 22) throw "Argument too large"; return (val == 0 ? 1 : val*factorial(val-1)); } Ключевое слово throw + объект, который содержит информацию об ошибке (строка, переменная, структура, класс) объект несет двоякую информацию - тип исключения (const char*, текстовая строка), и описание конкретного случая (само содержимое этой строки). Оператор throw приводит к немедленному прекращению работы функции.
exceptions: 1 вариант обработки 1. Никаких проверок в вызывающем коде не делается: main() { unsigned result; result = factorial(25); cout
exceptions: 2 вариант обработки 2. Вызывающий код обрабатывает исключения код, который может генерировать исключения, обертывается в try-блок и назначая обработчик для нужного типа исключения с помощью catch- блока: main() { unsigned result; try { result = factorial(25); cout
exceptions: 2 вариант обработки Если исключения не возникает, то catch-блок не получает управления. Так что после вызова factorial() печатается результат и сразу после этого сообщение Goodbye. Если factorial() взводит исключение, то остальные операторы блока try не выполняются (в примере не печатается результат), и просматриваются catch-блоки, относящиеся к данному блоку try. Если удается отыскать подходящий по типу исключения, то его код и выполняется, причем в параметр "шапки" блока засылается тот объект, который пришел с исключением. Мы в нашем примере получаем строку с описанием ошибки в параметре msg блока catch, которую и печатаем. Если подходящего блока catch нет, конструкция try-catch не перехватывает исключение и реализуется первый сценарий. … try { result = factorial(25); cout
Исключения (exceptions) catch-блоков может быть несколько, каждый ловит свой тип исключений. При генерации исключения программа будет просматривать их один за другим, в том порядке, как они написаны, и выполнит код первого же подходящего по типу catch-блока: try {... } catch (const char *msg) { cerr
Пример программы #include using namespace std; class ZeroDenominatorException {}; class TooLargeNumeratorException { public: int value; TooLargeNumeratorException(int value) { this->value = value; } }; double calculateFraction(int num, int denom) { if(num > 50) throw TooLargeNumeratorException(num); if(denom == 0) throw ZeroDenominatorException(); return (double)num/denom; } int main(void) { int num, denom; cout >num; cout > denom; try { double result = calculateFraction(num, denom); cout