Слайд 2
Конвертеры
Никитин Михаил Евгеньевич, 2015
Политехнический колледж имени П.А. Овчинникова
struct
vect {
double x,y;
};
class complex {
double re, im;
public:
complex(double r
= 0, double i = 0) :re(r), im(i) {};
complex& operator+= (complex);
complex& operator+= (double);
complex operator* (complex);
operator vect();
double real() const { return re;}
double imag() const { return im;}
friend istream& operator>>(istream& in, complex& c);
};
Слайд 3
Конвертеры
Никитин Михаил Евгеньевич, 2015
Политехнический колледж имени П.А. Овчинникова
complex::operator
vect(){
vect a;
a.x = re;
a.y = im;
return a;
}
Слайд 4
Конвертеры
Никитин Михаил Евгеньевич, 2015
Политехнический колледж имени П.А. Овчинникова
int
main()
{
complex a = complex(1, -1);
complex
b = 2.0f+a;
cin >> b;
vect d = (vect)b;
std::cout << a << " " << b << endl;
return 0;
}
Слайд 5
Разбиение на модули и интерфейсы
Никитин Михаил Евгеньевич, 2015
Политехнический
колледж имени П.А. Овчинникова
Любая реальная программа состоит из некоторого
количества отдельных частей.
Например, даже простая программа, такая как Hello, world!
Задача. Написать программу калькулятора, которая поддерживает четыре стандартных арифметических действия в качестве инфиксных операторов над числами с плавающей точкой. Кроме того, пользователь может определять переменные.
Слайд 6
Калькулятор
Никитин Михаил Евгеньевич, 2015
Политехнический колледж имени П.А. Овчинникова
Калькулятор
состоит из пяти частей:
Обработчика, выполняющего синтаксический анализ;
Лексического анализатора,
выделяющего лексемы из последовательности символов;
Таблицы символов, в которой хранятся пары (строка, значение);
Управляющей программы (драйвера) main ();
Обработчика ошибок.
Слайд 7
Калькулятор
Никитин Михаил Евгеньевич, 2015
Политехнический колледж имени П.А. Овчинникова
Слайд 8
Калькулятор
Никитин Михаил Евгеньевич, 2015
Политехнический колледж имени П.А. Овчинникова
Когда
один модуль пользуется другим, ему не надо знать все
подробности об используемом модуле.
В идеале большая часть деталей реализации модуля должна быть неизвестна его пользователям.
Следовательно, мы проводим различие между модулем и его интерфейсом.
Слайд 9
Калькулятор
Никитин Михаил Евгеньевич, 2015
Политехнический колледж имени П.А. Овчинникова
Слайд 10
Калькулятор
Никитин Михаил Евгеньевич, 2015
Политехнический колледж имени П.А. Овчинникова
Преимущества
такого подхода:
код будет «простым»;
код будет эффективным;
код будет понятным;
код будет
легким в сопровождении;
возможна параллельная разработка.
Слайд 11
Калькулятор
Никитин Михаил Евгеньевич, 2015
Политехнический колледж имени П.А. Овчинникова
Как
реализовать логически эту структуру?
Как реализовать физически данную структуру?
Какие для
этого есть возможности в С++?
Слайд 12
Пространства имен
Никитин Михаил Евгеньевич, 2015
Политехнический колледж имени П.А.
Овчинникова
Пространство имен является механизмом отражения логического группирования.
Например, объявления синтаксического
анализатора для калькулятора можно поместить в пространство имен Parser
namespace Parser {
double prim(bool get) {/*...*/}
double term(bool get) {/*...*/}
double expr(bool get) {/*...*/}
}
Слайд 13
Лексический анализатор
Никитин Михаил Евгеньевич, 2015
Политехнический колледж имени П.А.
Овчинникова
namespace Lexer {
enum Token_value {
NAME, NUMBER, END,
PLUS = '+',
MINUS = '-', MUL = '*', DTV = '/',
PRINT = ',' , ASSIGN = '=', LP = '(', RP = ')'};
Token_value curr_tok;
double number_value;
std::string string_value;
Token_value get_token() {/*...*/ }
}
Слайд 14
Пространства имен
Никитин Михаил Евгеньевич, 2015
Политехнический колледж имени П.А.
Овчинникова
namespace Parser {
double prim(bool get) {/*...*/}
double term(bool get) {/*...*/}
double
expr(bool get) {/*...*/}
}
Что плохого в текущем коде?
Слайд 15
Пространства имен
Никитин Михаил Евгеньевич, 2015
Политехнический колледж имени П.А.
Овчинникова
namespace Parser {
double prim(bool get);
double term(bool get);
double expr(bool get);
}
double
Parser::prim(bool get) {/*...*/ }
double Parser::term(bool get) {/* ... */ }
double Parser::expr(bool get) {/*... */ }
Слайд 16
Пространства имен
Никитин Михаил Евгеньевич, 2015
Политехнический колледж имени П.А.
Овчинникова
Члены пространства имен объявляются следующим образом:
namespace имя_пространства_имен {
// объявления
и определения
}
Нельзя объявить новый член пространства имен вне его определения. Например:
void Parser::logical(bool); // ошибка: в Parser нет logical ()
Слайд 17
Имена с квалификаторами
Никитин Михаил Евгеньевич, 2015
Политехнический колледж имени
П.А. Овчинникова
Пространство имен является областью видимости. Поэтому «пространство имен»
является фундаментальной и относительно простой концепцией.
double Parser::term(bool get){
double left = prim(get);
for (;;)
switch (Lexer::curr_tok) {
case Lexer::MUL:
left *= prim(true);
/* ... */
}
Слайд 18
Объявления using
Никитин Михаил Евгеньевич, 2015
Политехнический колледж имени П.А.
Овчинникова
double Parser::prim(bool get) // обработка первичных выражений
{
if
(get) Lexer::get_token();
switch (Lexer::curr_tok) {
case Lexer::NUMBER:
Lexer::get_token();
return Lexer::number_value; // константа с плавающей точкой
case Lexer::NAME:
double& v = Lexer::table[Lexer::string_value];
if (Lexer::get_token() == Lexer::ASSIGN) v = expr(true);
return v;
case Lexer::MINUS: // унарный минус
return -prim(true);
case Lexer::LP:
double e = expr(true);
if (Lexer::curr_tok = Lexer::RP) return Error::error("ожидалась )");
Lexer::get_token(); // пропустить скобки ')'
return e;
case Lexer::END:
return 1;
default:
return Error::error("ожидалось первичное выражение");
}
Слайд 19
Объявления using
Никитин Михаил Евгеньевич, 2015
Политехнический колледж имени П.А.
Овчинникова
Если имя часто используется вне пределов своего пространства имен,
довольно утомительно писать его каждый раз с квалификатором.
Слайд 20
Объявления using
Никитин Михаил Евгеньевич, 2015
Политехнический колледж имени П.А.
Овчинникова
double Parser::prim(bool get) // обработка первичных выражений
{
using
Lexer::get_token; // использовать get_token из Lexer
using Lexer::curr_tok; // использовать curr_tok из Lexer
using Error::error; // использовать error из Error
if (get) get_token();
switch (curr_tok) {
case Lexer::NUMBER:
get_token();
return Lexer::number_value; // константа с плавающей точкой
case Lexer::NAME:
double& v = Lexer::table[Lexer::string_value];
if (get_token() == Lexer::ASSIGN) v = expr(true);
return v;
case Lexer::MINUS: // унарный минус
return -prim(true);
case Lexer::LP:
double e = expr(true);
if (curr_tok = Lexer::RP) return Error::error("ожидалась )");
get_token(); // пропустить скобки ')'
return e;
case Lexer::END:
return 1;
default:
return Error::error("ожидалось первичное выражение");
}
Слайд 21
Объявления using
Никитин Михаил Евгеньевич, 2015
Политехнический колледж имени П.А.
Овчинникова
Такие синонимы следует делать как можно более локальными во
избежание конфликтов имен.
Можем поместить using-объявление в определение пространства имен Parser
namespace Parser {
double prim(bool get);
double term(bool get);
double expr(bool get);
using Lexer::get_token; // использовать get_token из Lexer
using Lexer::curr_tok; // использовать curr_tok из Lexer
using Error::error; // использовать error из Error
}
Слайд 22
Директивы using
Никитин Михаил Евгеньевич, 2015
Политехнический колледж имени П.А.
Овчинникова
using-директива делает доступными имена из пространства имен почти точно
так же, как если бы они были объявлены вне своих пространств
using namespace Lexer;
using namespace Error;
Слайд 23
Псевдонимы пространств имен
Никитин Михаил Евгеньевич, 2015
Политехнический колледж имени
П.А. Овчинникова
Короткие названия пространств имен могут войти в конфликт
друг с другом:
namespace А {
//...
}
Однако, длинные названия пространств имен непрактичны при написании реального кода:
namespace Russian_Telephone_Book{
//...
}
Слайд 24
Псевдонимы пространств имен
Никитин Михаил Евгеньевич, 2015
Политехнический колледж имени
П.А. Овчинникова
Можно создать короткий псевдоним длинного названия пространства имен:
namespace
RTB = Russian_Telephone_Book;
RTB::fio s3 = "Григ";
RTB::fio s4 = "Нильсен";
Слайд 25
Пространство имен
Никитин Михаил Евгеньевич, 2015
Политехнический колледж имени П.А.
Овчинникова
В идеале, пространство имен должно:
выражать логически связанный набор средств;
препятствовать
доступу пользователей к ненужным им средствам;
не требовать значительных дополнительных усилий при использовании.
Слайд 26
Обработка ошибок
Никитин Михаил Евгеньевич, 2015
Политехнический колледж имени П.А.
Овчинникова
При работе программ возникаю ошибки времени выполнения (runtime error),
когда дальнейшее нормальное выполнение приложения становится невозможным.
Причиной ошибок времени выполнения могут быть как ошибки в программе, так и неправильные действия пользователя, неверные данные и т.д.
Слайд 27
Обработка ошибок
Никитин Михаил Евгеньевич, 2015
Политехнический колледж имени П.А.
Овчинникова
Автор библиотеки может обнаружить ошибки времени выполнения, но, в
общем случае, не имеет ни малейшего представления, что с ними делать.
Пользователь библиотеки может знать, как бороться с такими ошибками, но не может их обнаружить — в противном случае, они бы обрабатывались в коде пользователя, и их обнаружение не было бы возложено на библиотеку.
Слайд 28
Обработка ошибок
Никитин Михаил Евгеньевич, 2015
Политехнический колледж имени П.А.
Овчинникова
Обработка ошибок должна быть разделена на две части:
генерация информации
о возникновении ошибочной ситуации, которая не может быть разрешена локально;
обработка ошибок, обнаруженных в других местах.
Слайд 29
Обработка ошибок
Никитин Михаил Евгеньевич, 2015
Политехнический колледж имени П.А.
Овчинникова
При обнаружении проблемы, которая не может быть решена локально,
функция может:
прекратить выполнение;
возвратить значение, означающее «ошибка»;
возвратить допустимое значение и оставить программу в ненормальном состоянии;
вызвать функцию, предназначенную для обработки «ошибочных» ситуаций.
Слайд 30
Обработка ошибок
Никитин Михаил Евгеньевич, 2015
Политехнический колледж имени П.А.
Овчинникова
Вариант 1 — «прекратить выполнение» — это то, что
происходит по умолчанию, когда не перехватывается исключение.
Вариант 2 — «возвратить значение, сигнализирующее об ошибке» — не всегда выполним, потому что часто нет приемлемого соответствующего значения.
Слайд 31
Обработка ошибок
Никитин Михаил Евгеньевич, 2015
Политехнический колледж имени П.А.
Овчинникова
Вариант 3 — «возвратить допустимое значение и оставить программу
в ненормальном состоянии» — имеет тот недостаток, что вызывающая функция может не заметить, что программа находится в ненормальном состоянии.
Обработка исключений не предназначена для решения проблем, для которых подходит вариант 4 «вызвать функцию обработки ошибок».
Слайд 32
Обработка ошибок
Никитин Михаил Евгеньевич, 2015
Политехнический колледж имени П.А.
Овчинникова
namespace Error {
int no_of_errors;
double error(const char* s)
{
std::cerr
<< "ошибка " << s << std::endl;
no_of_errors++;
return 1;
}
}
Слайд 33
Обработка ошибок
Никитин Михаил Евгеньевич, 2015
Политехнический колледж имени П.А.
Овчинникова
Для помощи в решении проблем возникновения и обработки ошибок
введено понятие исключения.
Фундаментальная идея состоит в том, что функция, обнаружившая проблему, но не знающая как ее решить, генерирует (throw) исключение в надежде, что вызвавшая ее (непосредственно или косвенно) функция сможет решить возникшую проблему.
Функция, которая хочет решать проблемы данного типа, может указать, что она перехватывает (catch) такие исключения.
Слайд 34
Исключения
Никитин Михаил Евгеньевич, 2015
Политехнический колледж имени П.А. Овчинникова
Механизм
обработки исключений предоставляет
альтернативу традиционным методам в тех случаях,
когда они не достаточны, не элегантны и подвержены ошибкам.
способ явного отделения кода обработки ошибок от «обычного» кода.
более регулярный способ обработки ошибок, упрощая в результате взаимодействие между отдельно написанными фрагментами кода.
Слайд 35
Исключения. Блок try-catch
Никитин Михаил Евгеньевич, 2015
Политехнический колледж имени П.А.
Овчинникова
Простейший формат защищенного блока имеет вид:
Полный формат защищенного блока
имеет вид:
try {операторы защищенного блока}
catch-блоки
Catch-блок имеет один из следующих форматов:
catch (тип) {обработчик ошибочной ситуации}
catch (тип идентификатор) {обработчик ошибочной ситуации}
catch (…) {обработчик ошибочной ситуации}
Слайд 36
Исключения. Блок try-catch
Никитин Михаил Евгеньевич, 2015
Политехнический колледж имени П.А.
Овчинникова
Простейший формат защищенного блока :
try
{операторы защищенного блока}
catch(...)
{обработчик
ошибочной ситуации}
Слайд 37
Никитин Михаил Евгеньевич, 2015
Политехнический колледж имени П.А. Овчинникова
int
main()
{
int x = 0;
try {
std::cout
<< 2 / x; //Здесь произойдет генерация исключения
// Последующие операторы выполняться не будут
}
catch (...) {
std::cout << "Division by zero" << std::endl;
}
}
Project Properties -> C/C++ -> Code Generation -> Modify the Enable C++ Exceptions to "Yes With SEH Exceptions"