Слайд 3Содержание лекции
Многофайловые программы
Причины использования многофайловых программ
Взаимодействие между файлами
Примеры
Вопросы из теста
![Содержание лекции Многофайловые программы Причины использования многофайловых программ Взаимодействие между файлами Примеры Вопросы из теста](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/893620/slide-2.jpg)
Слайд 4Причины использования
Разделение кодовой базы
Разделение работы над проектом на несколько разработчиков
Удобство организации архитектуры
![Причины использования Разделение кодовой базы Разделение работы над проектом на несколько разработчиков](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/893620/slide-3.jpg)
программы
Сокращение кодовой базы
Упрощение внесения правок
Слайд 5Взаимодействие между файлами
Взаимодействие между скомпилированными по отдельности, но скомпонованными вместе исходными файлами
![Взаимодействие между файлами Взаимодействие между скомпилированными по отдельности, но скомпонованными вместе исходными](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/893620/slide-4.jpg)
(.cpp)
Взаимодействие с заголовочными файлами (.h)
Слайд 6Взаимодействие исходных файлов
Три основных элемента исходных файлов:
Переменные
Функции
Классы
Для каждого типа элементов есть свои
![Взаимодействие исходных файлов Три основных элемента исходных файлов: Переменные Функции Классы Для](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/893620/slide-5.jpg)
правила межфайлового взаимодействия.
Слайд 7Межфайловые переменные
Объявление переменной – декларация её типа и имени.
Переменная определяется, когда происходит
![Межфайловые переменные Объявление переменной – декларация её типа и имени. Переменная определяется,](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/893620/slide-6.jpg)
резервация места под не в памяти.
int some_var;
extern int some_var;
Слайд 8Межфайловые переменные
// File A
int global_var;
// File B
global_var = 3; // Error!
![Межфайловые переменные // File A int global_var; // File B global_var = 3; // Error!](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/893620/slide-7.jpg)
Слайд 9Межфайловые переменные
// File A
int global_var;
// File B
extern int global_var; // Declaration in
![Межфайловые переменные // File A int global_var; // File B extern int](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/893620/slide-8.jpg)
File B
global_var = 3; // Good!
// But:
extern int global_var = 27; // extern will be ignored!
Слайд 10Статические переменные
// File A
static int global_var; // Only visible in A
// File
![Статические переменные // File A static int global_var; // Only visible in](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/893620/slide-9.jpg)
B
static int global_var; // Only visible in B
В этом случае статическая переменная имеет внутреннее связывание. Нестатические глобальные переменные имеют внешнее связывание.
Для сужения области видимости можно использовать также пространства имен.
Полезно: Внутренняя и внешняя линковка в C++
Слайд 11Совет
Не использовать глобальных переменных
Если очень хочется, и по логике программы переменная используется
![Совет Не использовать глобальных переменных Если очень хочется, и по логике программы](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/893620/slide-10.jpg)
только в текущем файле, то лучше сделать переменную статической.
В контексте глобальных переменных слово static просто сужает область видимости до одного файла.
Слайд 12Константы
Переменная, определенная с помощью const, в общем случае не видна за пределами
![Константы Переменная, определенная с помощью const, в общем случае не видна за](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/893620/slide-11.jpg)
одного файла.
Но если очень нужно:
// File A
extern const int const_var = 99;
// File B
extern const int const_var;
Слайд 13Межфайловые функции
Объявление функции задает ее имя, тип возвращаемых данных и типы всех
![Межфайловые функции Объявление функции задает ее имя, тип возвращаемых данных и типы](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/893620/slide-12.jpg)
аргументов.
Определение функции — это объявление плюс тело функции (тело функции — код, содержащийся внутри фигурных скобок).
Всё, что нужно знать при вызове – это имя, тип и типы аргументов. Все это есть в объявлении функции.
Слайд 14Пример
// File A
int add(int a, int b) {
return a + b;
}
//
![Пример // File A int add(int a, int b) { return a](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/893620/slide-13.jpg)
File B
int add(int, int);
int main() {
cout << add(10, 10) << endl;
return 0;
}
Слайд 15Заголовочные файлы
Указанный после директивы #include файл просто вставляется в исходный (например, iostream).
Пример:
#include
![Заголовочные файлы Указанный после директивы #include файл просто вставляется в исходный (например,](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/893620/slide-14.jpg)
#include "add.h"
Слайд 16Заголовочные файлы
// sum.h
extern int not_found = 404;
int sum(int, int);
// sum.cpp
int sum(int a,
![Заголовочные файлы // sum.h extern int not_found = 404; int sum(int, int);](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/893620/slide-15.jpg)
int b) { return a + b; }
// main.cpp
#include "sum.h"
int main() {
cout << sum(10, 10) << endl;
cout << not_found << endl;
// 20
// 404
}
Слайд 17Заголовочные файлы
В заголовочном файле можно хранить объявления, но не определения переменных или
![Заголовочные файлы В заголовочном файле можно хранить объявления, но не определения переменных](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/893620/slide-16.jpg)
функций.
В противном случае, использование этого файла в других (если только данные не static или const) приведет к ошибке компоновщика «повторные определения».
Слайд 18Ошибка повторения включений
// example.h
#if !defined(EXAMPLE_H)
#define EXAMPLE_H
int global_var;
int sum(int a, int b) {
![Ошибка повторения включений // example.h #if !defined(EXAMPLE_H) #define EXAMPLE_H int global_var; int](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/893620/slide-17.jpg)
return a + b;
}
#endif
Слайд 19Пространства имен
Пространства имен предоставляют более гибкий подход к вопросу управления видимостью переменных
![Пространства имен Пространства имен предоставляют более гибкий подход к вопросу управления видимостью](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/893620/slide-18.jpg)
и функций.
Пространство имен — это некая именованная область файла.
Слайд 20Пример
namespace geo {
const double PI = 3.14159;
double L(double radius) {
![Пример namespace geo { const double PI = 3.14159; double L(double radius)](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/893620/slide-19.jpg)
return 2 * PI * radius;
}
}
int main() {
cout << geo::PI << endl;
cout << geo::L(10) << endl;
// 3.14159
// 62.8318
}
Слайд 21Пример: using
namespace geo {
const double PI = 3.14159;
double L(double radius)
![Пример: using namespace geo { const double PI = 3.14159; double L(double](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/893620/slide-20.jpg)
{
return 2 * PI * radius;
}
}
L(100); // Not works!
using namespace geo;
L(100); // Works!
Слайд 22Неоднократное определение пространств имен
namespace geo {
const double PI = 3.14159;
}
// Other
![Неоднократное определение пространств имен namespace geo { const double PI = 3.14159;](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/893620/slide-21.jpg)
code ...
namespace geo {
double L(double radius) {
return 2 * PI * radius;
}
}
Слайд 23Пример
// geo.h
namespace geo {
const double PI = 3.14159;
double L(double radius);
}
//
![Пример // geo.h namespace geo { const double PI = 3.14159; double](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/893620/slide-22.jpg)
geo.cpp
#include "geo.h«
double geo::L(double radius) { return 2 * PI * radius; }
// main.cpp
#include "geo.h«
int main() {
cout << geo::PI << endl;
cout << geo::L(10) << endl;
}
Слайд 24Статические и динамические библиотеки
Библиотека — это фрагмент кода, который можно многократно использовать
![Статические и динамические библиотеки Библиотека — это фрагмент кода, который можно многократно](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/893620/slide-23.jpg)
(переиспользовать) в разных программах.
Библиотека в C++ состоит из:
Заголовочный файл, который объявляет функционал библиотеки.
Предварительно скомпилированный бинарный файл, содержащий реализацию функционала библиотеки.
Есть 2 типа библиотек: статические и динамические.
Слайд 25Статическая библиотека
Статическая библиотека состоит из подпрограмм, которые непосредственно компилируются и линкуются с
![Статическая библиотека Статическая библиотека состоит из подпрограмм, которые непосредственно компилируются и линкуются](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/893620/slide-24.jpg)
разрабатываемой программой.
При компиляции программы, которая использует статическую библиотеку, весь необходимый функционал статической библиотеки становится частью исполняемого файла.
В Windows статические библиотеки имеют расширение .lib (library), в Linux .a (archive).
Слайд 26Статическая библиотека
Преимущество:
Всего лишь один (исполняемый) файл, чтобы пользователи могли запустить и использовать
![Статическая библиотека Преимущество: Всего лишь один (исполняемый) файл, чтобы пользователи могли запустить](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/893620/slide-25.jpg)
программу. Статические библиотеки становятся частью программы
Недостатки:
Копия библиотеки становится частью каждого исполняемого файла, что может привести к увеличению размера файла
Для обновления статической библиотеки придется перекомпилировать каждый исполняемый файл, который её использует
Слайд 27Динамическая библиотека
Динамическая библиотека состоит из подпрограмм, которые подгружаются в разрабатываемую программу во
![Динамическая библиотека Динамическая библиотека состоит из подпрограмм, которые подгружаются в разрабатываемую программу](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/893620/slide-26.jpg)
время её выполнения.
При компиляции программы, которая использует динамическую библиотеку, эта библиотека не становится частью исполняемого файла.
В Windows динамические библиотеки имеют расширение .dll (dynamic link library), в Linux .so (shared object).
Слайд 28Динамическая библиотека
Преимущества:
Разные программы могут совместно использовать одну копию динамической библиотеки, что значительно
![Динамическая библиотека Преимущества: Разные программы могут совместно использовать одну копию динамической библиотеки,](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/893620/slide-27.jpg)
экономит используемое пространство
Можно обновить до более новой версии без необходимости перекомпиляции всех исполняемых файлов, которые её используют.
Недостаток:
Механизм взаимодействия может быть непонятен для новичков
Слайд 30Библиотеки импорта
Библиотека импорта (import library) – это библиотека, которая автоматизирует процесс подключения
![Библиотеки импорта Библиотека импорта (import library) – это библиотека, которая автоматизирует процесс](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/893620/slide-29.jpg)
и использования динамической библиотеки.
В Windows это обычно делается через небольшую статическую библиотеку (.lib) с тем же именем, что и динамическая библиотека (.dll).
В Linux общий объектный файл (с расширением .so) дублируется сразу как динамическая библиотека и библиотека импорта.
Слайд 31Пример
// math.h
#if !defined(MATH_H)
#define MATH_H
int round(double r);
#endif
// math.cpp
#include "math.h"
int round(double r) {
return
![Пример // math.h #if !defined(MATH_H) #define MATH_H int round(double r); #endif //](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/893620/slide-30.jpg)
(r > 0.0) ? (r + 0.5) : (r - 0.5);
}
Слайд 32Пример
#include "math.h"
#include
using namespace std;
int main() {
double number;
cout << "Enter
![Пример #include "math.h" #include using namespace std; int main() { double number;](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/893620/slide-31.jpg)
the number to round: ";
cin >> number;
cout << round(number) << endl;
}
Слайд 33Пример: запускаем как обычно
g++ -c app.cpp -o app.o
g++ -c math.cpp -o math.o
g++
![Пример: запускаем как обычно g++ -c app.cpp -o app.o g++ -c math.cpp](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/893620/slide-32.jpg)
app.o math.o -o app.out
./app.out
// Enter the number to round: 11.11
// 11
Слайд 34Пример: статическая библиотека
Получаем файл библиотеки:
ar cr libmath.a math.o
Используем полученный файл библиотеки:
g++ app.o
![Пример: статическая библиотека Получаем файл библиотеки: ar cr libmath.a math.o Используем полученный](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/893620/slide-33.jpg)
libmath.a -o app.out
g++ app.o -L. -lmath -o app.out
Проверяем:
./app.out
Слайд 35Пример: динамическая библиотека
Создаем файл динамической библиотеки:
g++ -shared -o libmath.so math.o
Используем полученный файл
![Пример: динамическая библиотека Создаем файл динамической библиотеки: g++ -shared -o libmath.so math.o](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/893620/slide-34.jpg)
библиотеки:
g++ app.o libmath.so -o app.out
g++ app.o -L. -lmath -o app.out
Проверяем:
./app.out
./app.out: error while loading shared libraries: libmath.so: cannot open shared object file: No such file or directory
Слайд 36В чем проблема?
Пользователь должен подсказать операционной системе, где искать необходимые библиотеки (libmath.so).
В
![В чем проблема? Пользователь должен подсказать операционной системе, где искать необходимые библиотеки](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/893620/slide-35.jpg)
случае с Linux:
Добавить путь к библиотеке к переменной окружения LD_LIBRARY_PATH
Использовать флаг -rpath, чтобы указать путь к динамической библиотеке при сборке исполняемого файла
Слайд 37Исправленный пример
export LD_LIBRARY_PATH = $LD_LIBRARY_PATH:/c/dev/OAIP/static_example/
./app.out
Или
g++ app.o -L. -lmath -o app.out -Wl,-rpath,/c/dev/OAIP/static_example/
./app.out
![Исправленный пример export LD_LIBRARY_PATH = $LD_LIBRARY_PATH:/c/dev/OAIP/static_example/ ./app.out Или g++ app.o -L. -lmath -o app.out -Wl,-rpath,/c/dev/OAIP/static_example/ ./app.out](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/893620/slide-36.jpg)
Слайд 38Пример вопроса на экзамене
Глобальная переменная определена в файле A. Чтобы получить доступ
![Пример вопроса на экзамене Глобальная переменная определена в файле A. Чтобы получить](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/893620/slide-37.jpg)
к ней из файла B, необходимо:
Определить ее в файле B, используя extern;
Определить ее в файле B, используя static;
Расслабиться;
Должно быть константой;
Объявить ее в файле B, используя extern.
Слайд 39Пример задачи на экзамене
Создать библиотеку для нахождения параметров треугольников (тип треугольника, площадь,
![Пример задачи на экзамене Создать библиотеку для нахождения параметров треугольников (тип треугольника,](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/893620/slide-38.jpg)
периметр и т.п.).
Использовать заголовочные файлы и пространства имен.