Контрольные вопросы
1. Какова разница между шаблоном и макросом?
2. В чем состоит отличие параметра шаблона от параметра функции?
3. Чем отличается обычный дружественный шаблонный класс от дружественного шаблонного класса, специализированного по типу?
4. Можно ли обеспечить особое выполнение для определенного экземпляра шаблона?
5. Сколько статических переменных-членов будет создано, если в определение класса шаблона поместить один статический член?
6. Что представляют собой итераторы?
7. Что такое объект функции?
Упражнения
1. Создайте шаблон на основе данного класса List:
class List
{
public:
List():head(0),tail(0),theCount(0) { }
virtual ~List();
void insert( int value );
void append( int value );
int is_present( int value ) const;
int is_empty() const { return head == 0; }
int count() const { return theCount; }
private:
class ListCell
{
public:
ListCell(int value, ListCell *cell = ):val(value),next(cell){ }
int val;
ListCell *next;
};
ListCell *head;
ListCell *tail;
int theCount;
};
2. Напишите выполнение обычной (не шаблонной) версии класса List.
3. Напишите шаблонный вариант выполнения.
4. Объявите три списка объектов: типа Strings, типа Cat и типа int.
5. Жучки: что неправильно в приведенном ниже программном коде? (Предположите, что определяется шаблон класса List, а Cat — это класс, определенный на одном из предыдущих занятий.)
List<Cat> Cat_List;
Cat Felix;
CatList.append( Felix );
cout << "Felix is " << ( Cat_List.is_present( Felix ) ) ? "" : "not " << "presentn";
6. ПОДСКАЗКА (поскольку задание не из самых легких): подумайте, чем тип Cat отличается от типа int?
7. Объявите дружественный оператор operator== для класса List.
8. Напишите выполнение дружественного оператора operator== для класса List.
9. Грешит ли оператор operator== той же проблемой, которая существует в упражнении 5?
10. Напишите выполнение функции шаблона, осуществляющей операцию обмена данными, в результате чего две переменные должны обменяться содержимым.
11. Напишите выполнение класса SchoolClass, показанного в листинге 19.8, как списка. Для добавления в список четырех студентов используйте функцию push_back(). Затем пройдитесь по полученному списку и увеличьте возраст каждого студента на один год.
12. Измените код из упражнения 10 таким образом, чтобы для отображения данных о каждом студенте использовался объект функции.
День 20-й. Отслеживание исключительных ситуаций и ошибок
Программный код, представленный в этой книге, был создан в иллюстративных целях. Мы не упоминали о возможных ошибках, чтобы не отвлекать вас от основных моментов программирования, представленных в том или ином фрагменте программы. Реальные же программы должны обязательно предусматривать возможные аварийные ситуации. Сегодня вы узнаете:
• Что представляют собой исключительные ситуации
• Как перехватываются и обрабатываются исключения
• Что такое наследование исключений
• Как использовать исключения в общей структуре отслеживания и устранения ошибок
• Что представляет собой отладка программы
Ошибки, погрешности, ляпусы и "гнилой" код
К сожалению, все программисты допускают ошибки. Чем больше программа, тем выше вероятность возникновения в ней ошибок, многие из которых до поры до времени остаются незамеченными и попадают в конечный программный продукт, уже выпущенный на рынок. С этой печальной истиной трудно смириться, поэтому создание надежных, свободных от ошибок программ должно быть задачей номер один для каждого программиста, серьезно относящегося к своему делу.
Одна из наиболее острых проблем в индустрии создания программ — это нестабильный программный код, нафаршированный ошибками. Обычно самые большие расходы во многих работах, связанных с программированием, приходятся на тестирование программ и исправление ошибок. Тот, кто решит проблему создания добротных, надежных и безотказных программ за короткий срок и при низких затратах, произведет революцию во всей индустрии программных продуктов.
Все ошибки в программах можно разделить на несколько групп. Первый тип ошибок вызван недостаточно проработанной логикой алгоритма выполнения программы.
Второй тип — синтаксические ошибки, т.е. использование неправильной идиомы, функции или структуры. Эти два типа ошибок самые распространенные, поэтому именно на них сосредоточено внимание программистов.
Теория и практика неопровержимо доказали, что чем позже в процессе разработки обнаруживается проблема, тем дороже стоит ее устранение. Оказывается, что проблемы или ошибки в программах дешевле всего обойдутся компании в том случае, если своевременно принять меры по предупреждению их появления. Не слишком дорого обойдутся и те ошибки, которые распознаются компилятором. Стандарты языка C++ заставляют разработчиков создавать такие компиляторы, которые способны обнаруживать как можно больше ошибок на этапе компиляции программы.
Ошибки, которые прошли этап компиляции, но были выявлены при первом же тестировании и обнаруживались регулярно, также легко устранимы, чего не скажешь о "минах замедленного действия", проявляющих себя внезапно в самый неподходящий момент.
Еще большей проблемой, чем логические или синтаксические ошибки, является недостаточная устойчивость программ, т.е. программа сносно работает в том случае, если пользователь вводит данные, которые предусматривались, но дает сбой, если по ошибке, например, вместо числа будет введена буква. Другие программы внезапно зависают из-за переполнении памяти, или при извлечении из дисковода гибкого диска, или при потере линии модемом.
Чтобы повысить устойчивость программ, программисты стремятся предупредить все варианты непредвиденных ситуаций. Устойчивой считают программу, которая может справляться во время работы с любыми неожиданностями: от получения нестандартных данных, введенных пользователем, до переполнения памяти компьютера.
Важно различать ошибки, которые возникают вследствие некорректного синтаксиса программного кода, логические ошибки, которые возникают потому, что программист неправильно истолковал проблему или неправильно решил ее, и исключительные ситуации, которые возникают из-за необычных, но предсказуемых проблем, например связанных с конфликтами ресурсов (имеется в виду недостача памяти или дискового пространства).
Исключительные ситуации
Для выявления синтаксических ошибок программисты используют встроенные средства компилятора и добавляют в программы различные ловушки ошибок, которые подробнее обсуждаются на следующем занятии. Для обнаружения логических ошибок проводится критический анализ проектных решений и всестороннее тестирование программного продукта.
Однако ни в одной программе нельзя устранить возможность возникновения исключительных ситуаций. Единственное, что может сделать программист, это подготовить программу к их возникновению. Например, невозможно средствами программирования предупредить переполнение памяти компьютера во время выполнения программы, но от программиста зависит, как поведет себя программа в этой ситуации. Можно выбрать следующие варианты ответа программы:
• привести программу к аварийному останову;
• информировать пользователя о случившемся и корректно выйти из программы;
• информировать пользователя и позволить ему сделать попытку восстановить рабочее состояние программы и продолжить работу;
• выбрать обходной путь и продолжить работу программы, не беспокоя пользователя.
Последний вариант, т.е. выбор обходного пути, безусловно, предпочтительнее аварийного останова программы. Хотя этот вариант не является необходимым или даже желательным в каждой программе, все-таки стоит написать такой код, который бы самостоятельно, автоматически, без лишнего шума справлялся со всеми исключительными ситуациями и продолжал работу.
Язык C++ предоставляет безопасные интегрированные методы отслеживания всех возможных исключительных ситуаций, возникающих во время выполнения программы.
Несколько слов о "гнилом" коде
То, что программный продукт может портиться со временем, прямо как яблоко на вашем столе, — вполне доказанный факт. Это явление возникает не по вине злых бактерий или грибков и не из-за пыли на компьютере, а потому, что практически любой код содержит скрытые внутренние ошибки, к которым добавляется нарастающее несоответствие старой программы новому компьютерному обеспечению и программному окружению. Идеально написанная и хорошо отлаженная программа очень быстро может превратиться в безделицу, больше не привлекающую внимания пользователя.