|
Программирование >> Разработка устойчивых систем
Внутренние классы также отчасти напоминают замыкания, сохраняющие контекст вызова функции для его последующего воспроизведения. Идиома внутреннего класса Перед нами ситуация, в которой мы (фактически) должны выполнить повышающее преобразование к нескольким типам, но в данном случае требуется предоставить несколько разных реализаций одного базового типа. Решение, позаимствованное нами из Java, развивает концепцию вложенных классов С++. В Java имеется встроенная поддержка внутренних классов, которые напоминают вложенные классы С++, но обладают доступом к нестатическим данным вмещающего класса; для этого неявно используется указатель this объекта класса, в котором они были созданы. Чтобы реализовать идиому внутреннего класса в С++, необходимо получить и использовать указатель на вмещающий объект. Пример: : C10:InnerClassIdiom.cpp Идиома внутреннего класса . #1 nclude <1ostream> #1 nclude <str1ng> using namespace std: class Poingable { public: virtual void poingO = 0: void callPoing(PoingableS p) { p.poingO: class Bingable { public: virtual void bingO = 0: void callBing(Bingable& b) { b.bingO: class Outer { string name; Определение первого внутреннего класса: class Innerl: friend class Outer::Innerl: class Innerl : public Poingable { Outer* parent: public: InnerKOuter* p) : parent(p) {} void poingO { cout poing called for parent->name endl: Обращение к данным объекта внешнего класса } innerl; Определение второго внутреннего класса: class 1ппег2: friend class Outer::Inner2; class Inner2 : public Bingable { Outer* parent: public: Inner2(0uter* p) : parent(p) {} void bingO { cout bing called for parent->name endl: } inner2: public: OuterCconst strings nm) : name(nm). innerl(this). inner2(this) {} Возвращение ссылки на интерфейсы. реализованные внутренними классами: operator PoingableSO { return innerl: } operator BingableSO { return inner2: } int mainO { Outer xCPing Pong ): Выглядит как повышающее преобразование к разным базовым типам! callPoing(x); callBingCx): } III:- Этот пример (предназначенный для демонстрации простейшего синтаксиса идиомы; пример реального использования будет приведен далее) начинается с интерфейсов Poingable и Bingable, каждый из которых содержит всего одну функцию. Обслуживание, предоставляемое функциями callPoing() и callBing(), требует, чтобы получаемый ими объект реализовывал соответственно интерфейсы Poingable и Bingable, но для достижения максимальной гибкости другие требования к объекту не предъявляются. Обратите внимание на отсутствие виртуальных деструкторов в обоих интерфейсах - это сделано для того, чтобы уничтожение объектов никогда не выполнялось через интерфейс. Конструктор Outer содержит закрытые данные (name). Мы хотим, чтобы он предоставлял интерфейсы Poingable и Bingable, чтобы его можно было использовать с функциями callPoingO и callBing() (в этой ситуации можно прибегнуть к множественному наследованию, но для простоты мы обходимся без него). Чтобы предоставить объект Poingable без объявления Outer производным от Poingable, мы задействуем идиому внутреннего класса. Сначала объявление class Inner указывает на то, что где-то существует вложенный класс с указанным именем. Это позволяет объявить класс дружественным в следующей строке. Наконец, после предоставления вложенному классу доступа ко всем закрытым элементам Outer можно переходить к определению класса. Обратите внимание: в классе хранится указатель на создавший его объект Outer, и этот указатель должен инициализироваться в конструкторе, В завершение реализуется функция poing() из класса Poingable. Затем процесс повторяется для второго внутреннего класса, реализующего Bingable. Каждый внутренний класс создается в одном закрытом экземпляре, инициализируемом в конструкторе Outer. Создание вложенных объектов и возвращение ссылок на них решает проблемы с жизненным циклом объектов. Следует помнить, что оба внутренних класса определяются закрытыми, и клиентский код не получает доступа к деталям реализации, потому что функции доступа operator Poingable&() и operator Bingable&() возвращают только ссылку на интерфейс, получаемый в результате повыщающего преобразования, но не на объект, его реализующий. Более того, из-за закрытости внутренних классов клиентский код даже не может выполнить понижающее преобразование к классам реализации; таким образом, интерфейс полностью изолируется от реализации. Мы также определили функции автоматического преобразования типов operator Poingable&() и operator Bingable&(). Как видно из функции main(), это позволяет использовать конструкции, выглядящие так, словно Outer порождается множественным наследованием от Poingable и Bingable. Различие состоит в том, что преобразования являются односторонними: вы можете добиться эффекта повышающего преобразования к Poingable и Bingable, но не сможете выполнить обратное понижающее преобразование к Outer. В следующем примере продемонстрирован более типичный подход: доступ к объектам внутренних классов осуществляется с помощью обычных функций вместо автоматических функций преобразования типа. Пример Вооружившись заголовочными файлами Observer и Observable, а также идиомой внутреннего класса, мы переходим к рассмотрению паттерна Наблюдатель: : C10:0bservedFlower.cpp Паттерн Наблюдатель. #i nclude <algorithm> #1nclude <1ostream> #include <string> #i nclude <vector> #1 nclude Observable.h using namespace std: class Flower { bool isOpen: public: FlowerO : isOpen(false). openNotifier(this). closeNotifier(this) {} void openO { Цветок открывает лепестки isOpen = true: openNoti fi er.noti fyObservers(): closeNotifier.openO: void closeO { Цветок закрывает лепестки isOpen = false: closeNotifier.notifyObservers(): openNotifier.close(): Применение идиомы внутреннего класса class OpenNotifier: friend class Flower::OpenNotifier: class OpenNotifier : public Observable { Flower* parent: bool alreadyOpen: publi с: OpenNotifier(Flower* f) : parent(f). alreadyOpen(false) {} void notifyObservers(Argument* arg = 0) { if(parent->isOpen && lalreadyOpen) {
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |