Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
inf_otvety_24-40.docx
Скачиваний:
71
Добавлен:
11.05.2015
Размер:
136.35 Кб
Скачать

39. Создание и уничтожение динамических объектов.

Объявление объектов с использованием конструкторов создает данные, которые существуют до выхода из блока, в котором они появились. Однако иногда объекты могут потребоваться на более короткое время. Такие объекты можно создавать и уничтожать во время работы программы с помощью операторов new и delete:

class A {...}; //объявление класса

..............

A *ps=new A; //объявление указателя и создание объекта типа A

A* *pa=new A[20]; //объявление указателя и создание массива объектов

...............

delete ps; //удаление объекта по указателю ps

delete [] pa; //удаление массива объектов по указателю pa

Фактически, выполнение оператора new эквивалентно вызову конструктора класса, а обращение к оператору delete на автомате означает вызов деструктора. Создание одиночных объектов может быть совмещено с инициализацией объекта, если в классе предусмотрен соответствующий конструктор:

A *ptr1=new A(5);//создание объекта и вызов конструктора инициализации

Массив создаваемых объектов проинициализировать таким же образом нельзя.

В ранних версиях C++ для создания и уничтожения динамических объектов использовали обращения к функциям malloc (запрос памяти ) и free ( освобождение памяти ). Неудобство применения этих функций по сравнению с операторамиnew/delete заключается в том, что для запроса памяти нужно знать количество байт, занимаемых объектом в оперативной памяти. Конечно, это не так уж и сложно – существует функция sizeof, с помощью которой длину объекта можно определить. Второе неудобство заключается в том, что функция malloc выдает указатель типа void* и его еще надо преобразовать к типу указателя на объект класса.

Довольно распространенная ситуация, которая может оказаться потенциальным источником ошибок, возникает в процессе создания и удаления динамических объектов. Она заключается в том, что после уничтожения объекта, связанного, например, с указателем ps, этот указатель не чистится. Если после удаления объекта сделать попытку что-то прочитать или записать по этому указателю, то поведение программы предсказать трудно. Поэтому достаточно разумным правилом является засылка нуля в указатель разрушаемого объекта:

delete ps;

ps=NULL; //или ps=0;

40. Динамические библиотеки (dll).

DLL (Dynamic-Link Library) - динамически загружаемые библиотеки. Существуют два типа DLL

  • Обычные DLL MFC - библиотеки (MFC regular DLL)

  • Расширенные DLL MFC - библиотеки (MFC extension DLL)

Динамически подключаемая библиотека - это специального вида исполняемый файл с расширением .dll, используемый для хранения классов, функций и ресурсов отдельно от исполняемого файла.

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

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

Применение DLL позволяет реконструировать и сопровождать функцию (или класс) только в одном экземпляре и все внесенные в нее изменения будут немедленно учтены любыми использующими ее приложениями без предварительной их перекомпиляции. Можно считать, что DLL является источником кода, а все упакованные в нее функции и классы - экспортируемыми функциями и классами.

Создание программ с использованием объектно-ориентированного подхода - это практика программирования, в основу которой положены те же принципы, что используются при любом техническом проектировании

Достоинства DLL

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

  2. Если интерфейс DLL не изменяется, то ее можно заменить более новой, причем сами приложения обновлять не придется

  3. При надлежащем выборе типа DLL ее можно использовать в приложениях, написанных на других языках программирования для Windows

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

Приложение может вызывать код из DLL двумя способами:

  1. По таблице определяется местоположение нужной функции, создается указатель на найденную функцию, с помощью указателя вызывается сама функция

  2. Приложение линкуется с обычным библиотечным LIB-файлом, в котором содержатся фиктивные модули программного кода (заглушки). При запуске приложения фиктивный псевдокод замещается реальным кодом из DLL

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

Второй способ значительно проще. Библиотечный LIB-файл при компиляции DLL создается автоматически. Для его создания не приходится предпринимать каких-либо особых действий. При использовании LIB-файлов все используемые в приложении DLL загружаются в память в момент запуска приложения и если некоторые из них отсутствуют, то Windows автоматически предупреждает об этом и приложение не выполняется.

Когда используется первый способ, разработчику приложения необходимо самостоятельно организовывать загрузку DLL в память и обрабатывать все ошибочные ситуации при отсутствии нужных DLL.

DLL создаются с помощью оболочки Visual Studio специальным мастером DLL Wizard.

MFC extension DLL

MFC extension DLL - это динамически загружаемые библиотеки, расширяющие библиотеку базовых классов MFC. Такой тип DLL легче всего создавать и кодировать. Чтобы сделать класс экспортируемым DLL, нужно при его объявлении указать макрос AFX_EXT_CLASS примерно так

class AFX_EXT_CLASS MyClass // Объявление класса

{

..................

};

Далее в приложении, использующем класс, достаточно будет включить этот макрос, и при запуске приложения будет импортирование из DLL нужный класс.

Одним из недостатков MFC extension DLL является то, что их нельзя использовать в программах, написанных на других языках программирования или в программахC++, компиляторы которых не поддерживают MFC. Но компиляторы фирмы Borland и Symantec поддерживают MFC extension DLL.

MFC regular DLL

MFC regular DLL - это обычные динамически загружаемые библиотеки. Этот тип DLL поддерживает стандартные функции, а не классы, поэтому планировать их приходится несколько тщательнее, чем MFC extension DLL. Внутри самой DLL классы можно использовать, но вызов кода внешним приложением нужно организовать через функцию.

Для обеспечения возможности экспорта функции библиотекой следует эту функцию объявить экспортируемой по такому синтаксису

extern "C" тип_возвращаемого_значения PASCAL EXPORT объявление_функции

Необходимо включить все эти дополнительные слова как в заголовочный файл прототипа функции, так и в исходный код ее реализации.

  • Выражение extern "C" объявляет, что это вызов стандартной функции C, поэтому корректировщик имен C++ не должен корректировать имя функции

  • Ключевое слово PASCAL сообщает компилятору, что все параметры функции передаются в порядке, принятом в языке PASCAL, т.е. параметры в стеке размещаются в порядке, обратном обычному

  • Ключевое слово EXPORT информирует компилятор о том, что эта функция будет экспортироваться динамически загружаемой библиотекой во внешние приложения

Для создания DLL применяется специальный тип проекта оболочки Visual Studio. Чтобы сделать функции экспортируемыми DLL, следует добавить их имена в файл определений DEF.lib этого проекта. Файл DEF.lib представляет собой библиотечный (т.е. с расширением LIB) файл заглушек и таблицу экспортируемых функций, содержащихся в DLL. В него включается имя DLL, ее краткое описание и имена всех экспортируемых библиотекой функций. Файл DEF проекта DLLавтоматически создается мастером "DLL Wizard" и имеет определенный формат. Формат файла изменять нельзя, в него можно только добавлять имена экспортируемых функций.

Примерный вид файла определений DEF.lib

LIBRARY "mydll"

DESCRIPTION 'mydll Windows Dynamic Link Library'

EXPORTS

; Explicit exports can go here

MyFun1

MyFun2

MyFun3

Если в MFC regular DLL используются классы из MFC, то первой строчкой тела всех экспортируемых функций должен быть вызов макроса AFX_MANAGE_STATE. Это диктуется необходимостью обеспечить многопоточную поддержку в функциях, благодаря которой можно вызывать функции класса одновременно несколькими потоками процесса. Макрос AFX_MANAGE_STATE имеет единственный аргумент - указатель на структуру AFX_MANAGE_STATE, который можно получить в результате вызова функции AfxGetStaticModuleState(). Типичная экспортируемая функция, использующая библиотеку MFC, имеет следующий вид

extern "C" void PASCAL EXPORT MyFun(список_аргументов)

{

AFX_MANAGE_STATE(AfxGetStaticModuleState());

// Далее идет обычное тело функции

.....................

}

При проектировании функций для DLL нужно соблюдать правила:

  1. Поскольку некоторые функции могут одновременно вызываться несколькими потоками процесса, то следует в них предусмотреть поддержку многопоточности

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

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]