Можно также пойти с Приложением. Событие ThreadException.
, Как только я разрабатывал приложение.NET, работающее в COM, основывал приложение; это событие было очень полезным как AppDomain. CurrentDomain. UnhandledException не работал в этом случае.
Иногда общее применение так называемого правила DRY ( Don't Repeat Yourself , для тех, кто не знаком) - не лучший подход. Особенно, если вы новичок в языке (C ++ и итераторы) и самом ООП (методологии), мало пользы от попытки минимизировать объем кода, который вам нужно написать прямо сейчас .
Я бы хотел реализовать два итератора, используя соответствующий код для каждого из них. Возможно, после того, как у вас будет больше опыта работы с языком, инструментами и методами, , затем вернитесь и посмотрите, можно ли уменьшить объем кода, исключив общий код.
Сделайте итератор производным от const_iterator, а не наоборот. Используйте const_cast
надлежащим образом (как деталь реализации, не раскрываемую для пользователей). Это очень хорошо работает в простых случаях и моделях, в которых «итераторы являются const_iterators» напрямую.
Когда этот запускается , чтобы требовать поясняющих комментариев в вашем коде, затем напишите отдельные классы. Вы можете использовать локализованные макросы для генерации аналогичного кода, чтобы избежать повторения логики:
struct Container {
#define G(This) \
This& operator++() { ++_internal_member; return *this; } \
This operator++(int) { This copy (*this); ++*this; return copy; }
struct iterator {
G(iterator)
};
struct const_iterator {
G(const_iterator)
const_iterator(iterator); // and other const_iterator specific code
};
#undef G
};
Макрос имеет ограниченную / локализованную область видимости, и, конечно же, используйте его только в том случае, если он действительно помогает вам - если это приводит к меньшему читаемый код для вас, введите его явно.
А насчет обратных итераторов: вы можете использовать std :: reverse_iterator
, чтобы обернуть ваш "нормальный" итераторы во многих случаях вместо их перезаписи.
struct Container {
struct iterator {/*...*/};
struct const_iterator {/*...*/};
typedef std::reverse_iterator<iterator> reverse_iterator;
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
};
На самом деле это очень просто.
Прежде всего, взгляните на библиотеку Boost.Iterator .
Во-вторых: вам нужно объявить базовый класс (в примере хорошо объяснено, как действовать), который будет похож на этот.
template <class Value>
class BaseIterator: boost::iterator_adaptor< ... > {};
Вы реализуете операции для перемещения указателя туда. Обратите внимание: поскольку это адаптация к уже существующему итератору, вы можете реализовать его всего несколькими штрихами. Это действительно впечатляет.
В-третьих, вы просто набираете его с константной и неконстантной версиями:
LinkedList
Как выглядит ваш метод begin? Изучая STL, вы можете увидеть, что контейнеры определяют два таких метода со следующими сигнатурами:
const_iterator begin() const;
iterator begin();
У вас не должно возникнуть проблем с получением итератора
из объекта, квалифицированного как const. Я не думаю, что здесь применяется DRY.
Когда-то я использовал следующий подход:
Для" итератора "дополнительный конструктор заменит конструктор копирования по умолчанию, в моем случае он был эквивалентен конструктору копирования по умолчанию.
Для" const_iterator "это будет дополнительный конструктор, который позволяет построить" const_iterator " из "итератора"