|
Программирование >> Инициализация объектов класса, структура
class ilist item { public: ilist item( int value, ilist -item *item to link to = 0 ); inline ilist item:: ilist item( int value, ilist item *item ) : value( value ) if ( item ) next = 0; else { next = item-> next; item-> next = this; Операция insert() в общем случае работает с двумя параметрами - значением и адресом элемента, после которого производится вставка. Наш первый вариант inline void ilist:: insert( ilist item *ptr, int value ) { new ilist item( value, ptr ); ++ size; реализации имеет два недочета. Сможете ли вы их найти? Одна из проблем заключается в том, что указатель не проверяется на нулевое значение. Mi обязаны распознать и обработать такую ситуацию, иначе это приведет к краху программе! во время исполнения. Как реагировать на нулевой указатель? Можно аварийно закончить выполнение, вызвав стандартную функцию abort() , объявленную в #include <cstdlib> ... if ( ! ptr ) заголовочном файле cstdlib: abort() ; Кроме того, можно использовать макрос assert() . Это также приведет к аварийному #include <cassert> ... завершению, но с выводом диагностического сообщения: assert( ptr != 0 ); Третья возможность - возбудить исключение: if ( ! ptr ) throw Panic: ilist::insert(): ptr == O ; В общем случае желательно избегать аварийного завершения программы: в такой ситуации мы заставляем пользователя беспомощно сидеть и ждать, пока служба поддержки обнаружит и исправит ошибку. Если мы не можем продолжать выполнение там, где обнаружена ошибка, лучшим решением будет возбуждение исключения: оно передает управление вызвавшей программе в надежде, что та сумеет выйти из положения. Мы же поступим совсем другим способом: рассмотрим передачу нулевого указателя как if ( ! ptr ) запрос на вставку элемента перед первым в списке: insert front( value ); Второй изъян в нашей версии можно назвать философским. Мы реализовали size() и size как пробный вариант, который может впоследствии измениться. Если мы преобразуем функции size() таким образом, что она будет просто пересчитывать элементы списка, член size перестанет быть нужным. Написав: ++ size; мы тесно связали реализацию insert() с текущей конструкцией алгоритма пересчета элементов списка. Если мы изменим алгоритм, нам придется переписывать эту функцию, как и insert front() , insert end() и все операции удаления из списка. Вместо того чтобы распространять детали текущей реализации на разные функции класса, лучше inline void ilist::bump up size() { ++ size; } инкапсулировать их в паре: inline void ilist::bump down size() { -- size; } Поскольку мы объявили эти функции встроенными, эффективность не пострадала. Вот inline void ilist:: insert( ilist item *ptr, int value ) if ( !ptr ) insert front( value ); else { bump up size(); new ilist item( value, ptr ); окончательный вариант insert() : inline void ilist:: insert front( int value ) { ilist item *ptr = new ilist item( value ); if ( ! at front ) at front = at end = ptr; else { ptr->next( at front ); at front = ptr; bump up size(); inl-ine void ilist:: insert end( int value ) { if ( ! at end ) at end = at front = new ilist item( value ); else at end = new ilist item( value, at end ); bump up s-ize(); из них мы должны предусмотреть случай, когда список пуст. find() ищет значение в списке. Если элемент с указанным значением найден, ilist item* ilist:: find( int value ) { ilist item *ptr = at front; while ( ptr ) { if ( ptr->value() == value ) break; ptr = ptr->next(); return ptr; возвращается его адрес, иначе find () возвращает 0. Реализация find() выглядит так: ilist item *ptr = mylist.find( 8 ); Функцию find() можно использовать следующим образом: mylist.insert( ptr, some value ); или в более компактной записи: Реализация функций insert front() и insert end() достаточно очевидна. В каждой
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0.001
При копировании материалов приветствуются ссылки. |