1 / 37

Д.з.

Д.з. 1. Задача 1 : Стек фиксированного размера. class stack { int stk[100]; int size; public: stack() : size(0) {} void push(int i) { stk[size++] = i; }. int pop() { return stk[--size]; } }; stack s; s.push(5); s.push(10); s.push(2); cout << s.pop();

denton
Download Presentation

Д.з.

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Д.з. 1

  2. Задача 1: Стек фиксированного размера class stack { int stk[100];int size; public: stack() : size(0) {}void push(int i){ stk[size++] = i;} int pop(){ return stk[--size];} }; stack s; s.push(5); s.push(10); s.push(2); cout << s.pop(); int i = s.pop() – s.pop(); // В последней строчке // результат не определен! 2

  3. Задача 2: динамический стек class dynstack { int size;// Количество элементов int maxsize;// Макс. количество int* p; // Отведенная память public: dynstack() : size(0), maxsize(10) { p = new int[maxsize]; } ~dynstack() { delete [] p; // Многие забыли.. } void push(int val) { if (size == maxsize) {// Нет места? auto newp = new int[maxsize*2]; // Копируем for (int i=0; i<size; i++) { newp[i] = p[i]; } maxsize *= 2; delete [] p; p = newp; // Переставляем } // указатель p[size++] = val; } int pop() { return p[--size]; } }; 3 3

  4. Не забывайте про delete.. • Если в классе где-то есть new, то, скорее всего, где-то должен быть и delete (в деструкторе?) • И, скорее всего, delete должно быть столько же, cколько new • Но в С++11 часто вместо деструкторов используют умные указатели (unique_ptr, shared_ptr) – об этомпозже… 4 4

  5. class stack { … int & top() { return stk[size-1]; } … }; // Пример вызова: stack s; … s.top() = 5; s.top()++; Задача 3: top 5

  6. Задача 5: сравнение строк // Oдин из многих возможных способов решения.. bool compare(const char* s1, const char* s2) { while (*s1==*s2) { if (*s1=='\0') // Конец обеих строк? returntrue; s1++; s2++; } // Раз мы здесь, то строки не равны return false; } • Типичная ошибка: нет const

  7. Еще про константы

  8. Иногда пишут: void f(const int i){…} Замечание Нет особого смысла..

  9. Константы и указатели - продолжение • const int* p;означает: «Обещаем не менять *p с помощью p». int i; const int* p = &i;// ОК? *p = 5; // Так ошибка i = 5; // А так? // OK! • А так можно писать? const int i = 100; int* p = &i; Нет! (Иначе *p = 5; - плохо, испортим константу) На константные переменные могут указывать только constуказатели. 9

  10. Замечание про константы и указатели в параметрах функций const int a[] = {3, 7, 11};void myfunc1(int* p){ …}myfunc1(a); // Ошибка // Авдруг вы в myfunc1 поменяете массив ?! • Если объекты константные • то параметры функции, которая с ними работает тоже д.б. const(если это - указатель или ссылка) 10

  11. Замечания • Если не писать правильно const в параметрах • товаши функции м.б. потом будет сложно вызывать То есть • const лучше сразу писать правильно • трудно добавлять понемногу / по частям..) const ‘цепляются’ друг за друга.

  12. Наследование

  13. sec = 0; inc(); } } void time_with_sec::print() { time::print(); cout << "." << sec; } // использование time_with_sec time_with_sec ts(12, 30, 45); ts.inc(); ts.inc_sec(); ts.print(); Пример – время с секундами class time_with_sec : public time { int sec; public: time_with_sec(int h, int m, int s); void inc_sec(); void print(); }; time_with_sec::time_with_sec(int h,int m,int s): time(h, m), sec(s) {} void time_with_sec::inc_sec() { sec++; if ( sec == 60 ) {

  14. Замечания • public наследование (другие почти не встречаются) • Слова: базовый класс / производный класс • Можем использовать поля и методы базового класса, как будто они наши собственные • Можем доопределять поля и методы (sec, inc_sec) • конструктор базового класса вызывается в списке инициализации • time::print() – указываем, что нас интересует именно метод базового класса • Самое главное – можно переопределять методы • Переопределяемые методы надо определять, как виртуальные (практически всегда)

  15. protected поля и методы Такие методы доступны из производных классов. Например, м.б. лучше в time :class time {protected: int hour, min;// Можно использовать в time // и в производных классах …

  16. Виртуальные функции (!!!) • Правило: Если вы собираетесь переопределить функцию в производном классе, то в базовом классе вы должны описать ее, как виртуальную. class time {virtual void print(); …

  17. Разница между виртуальными и не виртуальными функциями. Динамическое связывание. time* p;if ( …какое-то условие… ) {p = new time(8, 50);} else { p = new time_with_sec (11, 30, 15);} // на что указывает p ?? // - неизвестно.. p->print(); // Какой print// будет вызван? • Если функция виртуальная, то будет вызываться «правильный» print: time::print() илиtime_with_sect::print()в зависимости от типа p • Называется: динамическое связывание (dynamic binding) или позднее связывание (late binding)

  18. Почему это важно? void my_print(time& p) // а лучше, кстати, void my_print(const time& p) { cout << "Московское время:"; p.print();} time t1(8, 50);time_with_sec t2(11, 30, 15); my_print(t1);my_print(t2); Будут вызваны разные print ! • Виртуальные функции позволяют писать код, который умеет работать с разными типами! Называется: полиморфизм

  19. Чисто виртуальные функции, абстрактные базовые классы

  20. Пример: фигуры Рассмотрим набор классов для геометрических фигур: квадраты, ромбы, круги, треугольники и т.д. class shape { protected: int x, y; public: virtual void draw() = 0; shape(int x_, y_) : x(x_), y(y_) {} … еще методы (площадь, периметр и т.д.) …};

  21. Чисто виртуальные функции • В описании стоит =0;- функция называется чисто виртуальной (pure virtual). Это значит: • Можно не задавать ее определения • Ее обязательно надопереопределить в одном из производных классов.

  22. Абстрактные базовые классы • Если в классе есть хотя бы одна чисто виртуальная функция: • Такой класс называется абстрактным (abstract base class) • Нельзя создавать объекты абстрактного класса shape s; // Ошибка: нельзя создать объект // абстрактного класса • Все это относится и к производным классам, если в базовом классе была чисто виртуальная функция, и ее еще не определили.

  23. Исключения

  24. int pop() { return stk[--size];//А если стек }// пуст?! // Вариант с проверкойif (size == 0) {... сообщить об ошибке …}return stk[--size]; cout << "Oшибка!"; return 0; // Взводим глобальную переменнуюerr = true; Еще один параметр Еще проблемы: Как сообщать об ошибках в конструкторах? Хорошо бы поменьше проверок.. Проблемы с обработкой ошибок:

  25. Обработка ошибок с помощью исключений int stack::pop() { if ( size<= 0 ) throw "Стек пуст"; return stk[--size]; } // Потом где-то в другом месте: try { … s.pop(); … } catch ( char * s ) { cout << “Oшибка: " << s; } • throw выражение; - сообщить об ошибке • try { операторы (try блок)}catch (тип переменная) { операторы обработки ошибки (catch блок)}

  26. Что можно бросать как исключение? • Выражение может быть любого типа • throw "Ошибка!"; • throw 56; • throwtime(14, 30); • Обычно используют специальные классы. • throw my_exception(…какая-то информация об ошибке…); • Есть стандартные классы (#include <stdexcept>) • Например, throw std::bad_alloc(); • Или throw std::exception("Стек пуст");

  27. catch блоков может быть несколько try { … } catch (const char* s) {… обработка ошибок для строк …}catch (int i) { … обработка ошибок для int …} Порядок имеет значение!try { … } catch (time* p1) {… }catch (time_with_sec* p2) { … никогда не будет выполняться ! …} catch (…) - ловит все catch (…) { здесь обрабатываем все ошибки } Подробнее о том, как ловить исключения (catch блоки)

  28. throw умеет выходить из нескольких функций int stack::pop() { if ( size<= 0 ) throw "Стек пуст";… } void f() { …stack s;…s.pop();… } void g() { …f(); … } try { … g(); … } catch ( char * s ) { cout << “Oшибка: " << s; } 28

  29. Что происходит в момент вызова throw? • Выходим из функций и блоков, в которых мы находимся … • … пока не найдем try блок с подходящим нам catch блоком • После этого выполняется catch блок • (Если вообще не нашли подходящего try блока – аварийное завершение программы). • Важно:При выходе из функций и блоков вызываются все необходимые деструкторы

  30. Более сложные возможности • throw; void f() { try { … } catch (…) { … какая-то обработка … // Хотим снова бросить исключение для // дальнейшей обработки throw; } }

  31. Константы в классах 31

  32. Константные поля class abc { const int n; … abc::abc() : n(100)// Задавать можно только здесь { … abc::abc() { n = 100; // Тут уже задавать n нельзя Используются довольно редко.. 32

  33. Константные методы class abc { int i; void f() const { i++; // ошибка } … Нельзя менять поля Из f можно вызывать только константные методы Зачем? Ловим ошибки в программе Смысл метода становится понятнее (удобнее пользоваться) Техническая причина: к константным объектам можно применять только такие методы const time lunch_time(12,50); lunch_time.print(); // Только если у print - // константный метод 33

  34. Д.з.

  35. Д.з.-1 • a. Определить класс «равнобедренный треугольник» (с основанием, параллельным оси X). Для него определить конструктор и метод draw. (В методе draw вместо рисования можно просто печатать координаты отрезков).б. Определить какой-нибудь класс, производный от класса «равнобедренный треугольник»(например, «заштрихованный вертикально равнобедренный треугольник» или «зашьтрихованный горизонтально» или «треугольник с медианами» и т.д.) • Написать абстрактный класс shape и какие-нибудь два производных от него класса (Например, треугольник и ромб или прямоугольник или круг и т.д.). Для этих классов определить конструкторы и функции- методы area (площадь) и perim (периметр). (Метод draw в этой задаче определять не надо).

  36. Д.з.-2 • Определить структуру (или класс) «односвязный список». а. Ввести число n и создать список из чисел n, n-1, n-2, … 3, 2, 1.б. Напечатать все числа в списке.(Если не очень понятно, как это делать или о чем вообще речь – на сайте есть документ list.doc с пояснениями и подказками.) • Проверять в конструкторе time корректность параметров. (Например, time t(25, 1); -параметры неправильные). • Об ошибке сообщать с помощью исключения. • Привести пример обработки этого исключения (Т.е. попытаться создать «неправильный» объект, и поймать возникшее исключение.)

  37. Д.з. - 3 • Пусть есть функция:void f(stack& s){int* p = new int[1000]; // … тут, допустим, мы что-то делаем с p и scout << s.pop(); // … а тут еще что-то делаем с p и s delete [] p; // Потенциальная утечка памяти: delete может и не вызваться! } При выполнении может происходить утечка памяти (если в pop() вызывается исключение). Изменить функцию, чтобы выполнялиcьте же действия, в том же порядке (new  pop  delete), но чтобы при исключении память не терялась 37

More Related