Разработка функциональных замыканий с помощью наследования

На языке С# функциональное замыкание может быть реализовано несколькими способами. Первый способ - через наследование. Идея состоит в том, чтобы иметь базовый класс, "знающий" о функциональных замыканиях, и производный класс, выполняющий конкретную работу внутри замыкания. В качестве примера рассмотрим класс для отображения всплывающего окна. Создание абстрактного базового класса является здесь хорошей отправной точкой.

сlass Popup // абстрактный класс

{

Image region; //Область занимаемая окном

public:

Popup(Rectangle r)

{ /* сохранение координат и размеров открываемого всплывающего окна */};

virtual void Display(Graphics g)=0;

~Popup(){/* восстановление закрытой области */};

}

Если для отображения реального всплывающего окна породить класс от Popup, то компилятор автоматически будет вызывать конструктор и деструктор базового класса, которые сыграют роль вступления и заключения функционального замыкания.

class SetupPopupWindow: Popup

{

public:

SetupPopupWindow(): Popup(1, 10, 100, 100){ /* построение содержимого окна */ };

void Display()

{

// реализация функции базового класса для запоминания области экрана,

// занимаемой данным окном, и рисование самого окна

};

// Вызов деструктора базового класса, который восстановит изображение

// области экрана, закрытой окном

}

// использование всплывающего окна

main()

{

SetupPopupWindow help;

help.Display();

// …

};

Всякий раз, при создании объекта класса SetupPopupWindow, детали сохранения и восстановления экрана обрабатываются компилятором. Подобная процедура хорошо работает тогда, когда необходимо функциональное замыкание в специализированном классе, полученном через наследование. С помощью наследуемых функциональных замыканий можно решить много задач, но не все.

Разработка функциональных замыканий с помощью экземпляров класса

Альтернативный способ создания функциональных замыканий с помощью экземпляров класса заключается в использовании динамики создания объекта при выполнении программы. Это проще наследования, но имеет свои ограничения. Здесь, как и в технологии с использованием наследования, используется автоматический вызов конструкторов и деструкторов. При создании экземпляра класса компилятор вызывает конструктор класса. Когда экземпляр разрушается, то компилятор вызывает деструктор класса. Конструктор и деструктор могут вновь сыграть роль вступления и заключения. И действительно, конструктор отводит ресурсы, функции - члены манипулируют ими, а деструктор освобождает их. Поскольку компилятор гарантирует обязательный вызов деструктора при разрушении объекта, то можете быть уверены в том, что ресурсы не будут по ошибке "болтаться" в системе.

Рассмотрим следующую реализацию всплывающего окна.

class Popup

{

Rectangle region;

public:

Popup(Rectangle r){ /* сохранение области экрана закрываемое окном */ };

...

~Popup(){ /* восстановление закрытой области */ };

}

// использование всплывающего окна

main()

{

Popup window;

// …

}

Функциональные замыкания являются очень важным элементом системы обработки исключительных ситуаций в языке С#. Если во время выполнения программы возникает исключительная ситуация, то программа переходит за пределы локальной области видимости. В результате, система автоматически вызывает деструкторы для тех объектов, которые, в результате перехода, выходят из области видимости. Не используя надлежащим образом концепцию функционального замыкания, можно легко ввести ошибки в свою программу.