Скачиваний:
316
Добавлен:
28.03.2021
Размер:
378.53 Кб
Скачать

61. Причины использования многофайловых программ. Библиотеки классов. Реализация библиотек классов.

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

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

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

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

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

62. Создание многофайловой программы. Директории в многофайловой программе.

Допустим, у вас имеется библиотечный файл THEIRS.OBJ (работа с .LIB-файлами, впрочем, ничем не отличается от работы с .OBJ). К нему, соответственно, прилагается заголовочный файл THEIRS.H. В написанной вами программе MINE.CPP используются библиотечные классы. Как теперь прицепить одно к другому, соединить все три файла в одну исполняемую программу?

Убедитесь, что все компоненты — THEIRS.OBJ, THEIRS.H и MINE.CPP, — находятся в одном каталоге. Вообще говоря, лучше всего создавать для каждого проекта свой каталог, дабы избежать путаницы. Каждый компилятор хранит свои собственные библиотечные файлы (такие, как IOSTREAM.H, CONIO.H) в определенном каталоге, часто называемом INCLUDE каталогом. Этот каталог может быть «закопан» довольно глубоко, но компилятор всегда знает, где его искать.

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

63. Проекты в IDE Visual Studio. Взаимодействие исходных файлов. Заголовочные файлы. Межфайловые переменные. Межфайловые функции. Межфайловые классы. Ошибка повторения включений. Предупреждение ошибок повторения включений.

Директива #include работает, как функция ВСТАВИТЬ в текстовых редакторах, то есть указанный после этой директивы файл просто вставляется в исходный. В очень многих примерах мы видели включения библиотечных файлов типа IOSTREAM. Можно также и самостоятельно написать заголовочный файл и включить его в свою программу.

Общая информация

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

Межфайловые переменные.

Начнем с простых переменных. Для этого вспомним разницу между объявлением и определением. Мы объявляем, декларируем какую-то простую переменную, задавая ее тип и имя. Это не означает, что для нее сразу же резервируется место в памяти. Объявление переменной просто сообщает компилятору о том, что где либо там, в программе, может встретиться переменная с таким-то именем и такого-то типа. Переменная определяется, когда под нее в памяти резервируется место, которое способно содержать любое ее значение. Определение, так сказать, создает реальную переменную. Большинство объявлений являются также и определениями. Точнее, единственным объявлением простой переменной, не являющимся определением, является объявление с использованием зарезервированного слова extern (без инициализации).

Межфайловые функции.

Мы все помним, что объявление функции задает ее имя, тип возвращаемых данных и типы всех аргументов. Определение функции — это объявление плюс тело функции (тело функции — код, содержащийся внутри фигурных скобок). Когда компилятор генерирует вызов функции, ему, в общем-то, незачем знать, как она работает. Все, что нужно знать, это ее имя, тип и типы ее аргументов. Все это есть в объявлении функции. Поэтому запросто можно определить функцию в одном файле, а создавать ее вызовы из другого. Никаких дополнительных разрешений (типа слова extern) не требуется. Нужно только объявить функцию в том файле, откуда будет производиться вызов.

Межфайловые классы.

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

Предупреждение ошибок повторения включения.

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

Если не определяем: # if !defined(HEADCOM) ( HEADCOM - любой идентификатор)

Если определяем: # define HEADCOM

Ошибка повторения включений.

Мы упоминали, что нельзя определять функцию или переменную в заголовочном файле, который будет использован несколькими исходными файлами. Это приводит к ошибкам повторных определений. Подобная проблема возникает и тогда, когда по ошибке включают один и тот же заголовочный файл дважды. Как такое может случиться? Да запросто:

//файл app.cpp

#include "headone.h"

#include "headone.h"

Но это еще ничего. Представьте себе, что у вас есть исходный файл app.cpp и два заголовочных — headone.h и headtwo.h. К тому же headone.h включает в себя headtwo.h К сожалению, про это обстоятельство забывают и включают оба файла в app.cpp:

//файл headtwo.h

int globalVar;

//файл headone.h

#include "headtwo.h"

//файл app.cpp

#include "headone.h"

#include "headtwo.h"