|
Программирование >> Унарные и бинарные операторы
ДЛЯ объекта класса myclock (см. о нем в разделе Богатые и бедные классы главы 8). Листинг 13.3 #1 nclude <iostream> #1 nclude <assert.h> using namespace std: #include myc1ock4.h void insptime (myclock &a){ int s-a.gets(): assert(0< s && s < 60): } int main(){ myclock 3(10.59.65): insptime(a): for(int i=0: i<1000:i++) cout ++a; return 0: } После создания объекта a, принадлежащего классу myclock, в программе из листинга 13.3 вызывается функция insptimeO, Проверяющая правильность задания времени. По идее, эта функция должна быть собственной в классе myclock, тогда бы ей легче было добраться до значений времени. Но у нас она для наглядности сделана независимой. В этой функции проверяются только секунды. Следующее условие означает, что значение секунд, вькодящее за указанные пределы (0,59), прервет работу программы: assert(0< s && s < 60): Программа в этом случае аварийно завершится, показав на экране сообп1ение: Assertion failed: s<60. file clockl.cpp. line 8 Чтобы программа могла продолжить работу, в С++ существует другой, гораздо более сложный механизм Чтобы функция assertO заработала, необходимо включить заголовочный файл assert.h. функция ТОЛЬКО читает данные - снабдите ее словом const. Работа над ошибками Профамма, свободная от ошибок, есть абстрактное теоретическое понятие. Д. Ван Тассел, Стиль, разработка, эффективность, отладка и испытание программа До СИХ пор мы почти не обращали внимание на вшмож-иые ошибки в программе. Между тем, в программировании, как нигде, справедливо изречение человеку свойственно ошибаться . Если бы хирурги ошибались так же часто, как программисты, операционные превратились бы в морги. То, что безошибочных программ не бывает, знают все, кто работает на компьютере. Быть может, это происходит потому, что борьба с ошибками - крайне нудное занятие, требующее нечеловеческого педантизма. Между программой, работаюн1ей только па одном компьютере, и программой, способной работать на всех компьютерах, лежит пропасть. Как же бороться с ошибками? Первое средство нам уже известно - это проверка значений, возвращаемых собственными функциями, такими как fai 1 () или eofO. Второе средство под названием assert() очень удобно при отладке программ, потому что сигнализирует о выходе параметров за допустимые границы. Внутри круглых скобок помещается булево выражение, которое для успешного выполнения программы должно быть истинным. Рассмотрим в качестве примера программу (листинг 13.3), где проверяется правильность задания времени обнаружения и исправления о1пибок, связанный с созданием налету спсциалышх объектов и передачей их функциям, которые анализируют ошибку и принимают решения о далы1ейшей сукьбе программы. В листинге 13.4 показана npoi-рамма, использующая этог механизм для исправления неправильно заданного времени. Листинг 13.4 #inc1ude <stdexcept> #inc1ude <iostream> #inc1ude <excpt.h> using namespace std; #include n]yclock4.h void insptime (myclock &a){ int s=a.gets(); if(s >60){ a.puts(59); throw range error( Секунды исправлены ); int main(){ myclock 3(10.59.65); try{ insptime(a); catch(runtime error& r){ cout r.whatO endl; fordnt i=0; i<lOOO;i++) cout ++a; return 0; } В этой программе функция insptime О, преж;1е чем сообщить об ошибке, исправляет неправильно заданные секунды. Сообщение об ошибке - это, по сути, создание обьскта стандартного класса range error: throw range error( Секунды исправлены ); При создании объекта стандартного класса rangejarror вызывается конструктор, принимающий сообщение об ошибке. Объекты enum и typedef примитивные (неполноценные) объекты, создаваемые с помоп1ью ключевых слов enum и typedef, пришли в С++ из С. Несмотря на примитивность, а может быть, Но одного создания объекта недостаточно для правильной работы программы. Подозрительную область, где ошибка может встретиться, нужно пометить конструкцией try{}. В нашем случае помечается вы.зов функции insptimeO. И наконец, третий .элемент системы - функция catch(), стояща>1 неносредствеппо за блоком try{}. В нашем случае catch принимает ссылку на объект класса runtimeerror, а не класса rangeerror, создаваемого инструкцией throw rangeerrorO. Но range error - loiacc, производный от runtimeerror, поэтому компилятор воспринимает его без возраженит!. То, что функция catcho принимает ссылку на объект базового класса, позволяет ей о 1слеживат1> разные ошибки. О том, какие классы гюрож;1ает класс runtimeerror, можно узнать в заголовочном ()айле stdexcept.h. Действует вся эта система очень просто: функция insptime() исправляет неверно за;1аипые секунды, затем на экране появляется предупреждение Секунды ис-Н1)авлены , и часы начинают отсчет в1)емепи. Если нужно, выполнение программы можно прервать, поместив внутрь блока catchO соответствующую инструкцию, например exit (1). Напоследок подчеркнем, что стандартные классы runtimeerror и rangeerror использовать совсем не обязательно. Можно Создать собственные классы, если программа того требует. Применение троицы try, throw и catch может быть голово.чомно сложным, по об этом лучше прочитать в какой-нибудь другой книге. благодаря ей, слова enum и typedef часто используются в С++. Начнем с ключевого слова enum, позволяющего создать новый объект, принимающий ряд целочисленных значений. Например, масти в карточной игре (см. раздел Карты в главе 7) можно определить с помощью enum: enum su1ts{diamonds.hearts.spades.clubs}: Здесь suits - название нового типа. Объекть[ типа enum способны принимать всего четыре значения: 0,1,2 и 3. Каждое значение имеет имя. Так, значению О соответствует имя diamonds (бубны), а значению 3 - имя clubs (трефы). Численные значения, принимаемые переменными enum, можно изменить, для этого они указываются явно: enum sults{diamonds-1.hearts.spades.clubs}: В этом случае значение hearts будет равным 2, значение spades - 3 и т. д. Различные варианты использования перечислений (так еще называют тип, задаваемый с помощью ключевого слова enum) показаны в листинге 13.5. Листинг 13.5 #include<iostream> enum sui ts{di amends.hea rts.spades.clubs}: void f(suits s){ switch(s){ case diamonds:{ cout Бубны endl:break; case hearts:{ cout Черви endl;break: ) case spades:{ cout Пики endl: break: ) case clubs:{ cout Трефы endl:break: default:{ cout Неверная масть endl: break; int main(){ suits m: f (clubs): m=hearts: cout m endl -.III m-suits(clubs): cout m endl; 3 return 0: Как видите, все созданное с помощью ключевого слова enum можно формально рассматривать как новый объект. Объявление suits m говорит о том, что создается новая переменная m типа suits, которая принимает четыре значения: diamonds, hearts, spades и clubs. Функция f (suits s), показывающая на экране русскоязычное название масти, объявлена как принимающая параметр s типа suits. Более того, компилятор отвергнет целочисленный аргумент функции f (З) вместо f (clubs). Но, в то же время, легко проходит присваивание целочисленной переменной отдельных значений масти: int i=hearts: i=l Задача 13.2. Перепишите класс card из раздела Карты главы 7, используя слово enum. Если ключевое слово enum создает хоть жалкое, но все же подобие нового типа, то ключевое слово typedef только иначе называет г/же а/ществующий тип. Но это простое средство способно чудесным образом преобразить программу, сделать ее простой и понятной. Основное правило, позволяющее понять работу typedef, очень простое: указав ключевое слово typedef слева от
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |