Идея функционального замыкания заключается в реализации кода типа.
Инициализация Выполнение Деинициализация
Данный тип встречается часто особенно. Например, открыть записать закрыть файл. Или открыть контекст устройства вывести в контекст закрыть. Данный тип кода встречается на каждом шагу. Мы постоянно отрываем потом используем а потом. вот в последних действиях может и быть ошибка. Забыть закрыть что то это нормально. Для программиста, а для системы болезненно. Вот мы с Вами и посмотрим, какими методами можно этого избежать. Первый метод это использовать конструктор и деструктор класса. В конструкторе мы открываем, а в деструкторе закрываем. Давайте посмотрим, как можно из хотя из этой идеи создать класс для доступа к COM порту на основе функций API. Слабое место в работе с портом, что после его открытия и использования нужно его закрыть, обязательно. Итак, создаем конструктор с параметрами. Никакого конструктора по умолчанию не будет.
class CComPort { public: CComPort(LPCTSTR PortName,DWORD dwDesiredAccess,DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition,DWORD dwFlagsAndAttributes, HANDLE hTemplateFile); virtual ~CComPort(); private: HANDLE ComPort; };
Код к конструктору и деструктору.
CComPort::CComPort(LPCTSTR PortName,DWORD dwDesiredAccess, DWORD dwShareMode,LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition,DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) { ComPort=CreateFile(PortName,dwDesiredAccess,dwShareMode, lpSecurityAttributes,dwCreationDisposition, dwFlagsAndAttributes,hTemplateFile); if(ComPort==INVALID_HANDLE_VALUE) throw CString("Error Open"); } CComPort::~CComPort() { CloseHandle(ComPort); }
Все что нам осталось определить некоторую виртуальную функцию для того, чтобы ее переопределить и встраивать код для работы с портом.
class CComPort { public: virtual void WorkForPort(); // для работы с портом CComPort(LPCTSTR PortName,DWORD dwDesiredAccess, DWORD dwShareMode,LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition,DWORD dwFlagsAndAttributes, HANDLE hTemplateFile); virtual ~CComPort(); private: HANDLE ComPort; };
Соответственно для использования этого класса нам нужно создать свой класс как наследник, переопределить эту функцию и все можно использовать. Обратите внимание на throw. Другого способа сообщить о неудачах в конструкторе вреда как нет.
#include "stdafx.h" #include "ComPort.h" #include "iostream.h" class CMyCom : public CComPort { public: CMyCom(LPCTSTR PortName,DWORD dwDesiredAccess,DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes,DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes,HANDLE hTemplateFile); void WorkForPort(); }; CMyCom::CMyCom(LPCTSTR PortName,DWORD dwDesiredAccess,DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes,DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes,HANDLE hTemplateFile) :CComPort(PortName,dwDesiredAccess,dwShareMode,lpSecurityAttributes, dwCreationDisposition,dwFlagsAndAttributes,hTemplateFile) { } void CMyCom::WorkForPort() { } void main() { try { CMyCom cm("LPT1",GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,0,NULL); cm.WorkForPort(); } catch(...) { cout << "Error" << endl; return; } }
При разрушении класса пройдет закрытие указателя. Это может произойти при выходе за область видимости например из функции в которой он объявлен или при удалении динамического объекта.