- •Предисловие
- •Глава 1. Основные понятия
- •1.1. Элементы языка программирования
- •1.2. Процесс создания программы
- •1.3. Первая программа
- •1.4. Состав программы
- •Глава 2. Средства разработки на C++
- •2.1. Системы Turbo C++ 3.0/Borland C++ 3.1
- •2.2. Система C++ Builder
- •Глава 3. Работа с числовыми данными
- •3.1. Целые типы
- •3.2. Числа с плавающей точкой
- •3.3. Ввод и вывод чисел
- •3.4. Логический тип и логические операции
- •3.5. Математические функции
- •Глава 4. Операторы. Ключевые слова
- •4.1. Операторы
- •4.2. Приоритеты операторов
- •4.3. Ключевые слова
- •4.4. Структура программы
- •4.5. Константы
- •Задачи - . Простейшие вычисления
- •Глава 5. Управление и циклы
- •5.1. Условный оператор
- •5.2. Операторы цикла
- •5.3. Переключатель
- •5.4. Операторы break и continue
- •Задачи -. Выбор и циклы
- •Глава 6. Массивы
- •6.1. Одномерные массивы
- •6.2. Двумерные массивы
- •Задачи -. Одно- и двумерные массивы
- •Глава 7. Функции
- •7.1. Определение функции
- •7.2. Формальные параметры и фактические аргументы
- •7.3. Автоматические и статические переменные
- •7.4. Прототипы функций
- •7.5. Массивы как аргументы функций
- •7.6. Внешние переменные
- •7.7. Рекурсия
- •7.8. Перегруженные имена функций
- •7.9. Аргументы функций по умолчанию
- •Задачи -. Функции
- •Глава 8. Символы и строки
- •8.1. Символы
- •8.2. Строки символов
- •Задачи -. Символы и строки
- •Глава 9. Препроцессор
- •9.1. Директивы препроцессора
- •9.2. Макросы
- •Задачи -. Макросы
- •Глава 10. Указатели и ссылки
- •10.1. Указатели и адреса
- •10.2. Указатели и массивы
- •10.3. Адресная арифметика
- •10.4. Символьные указатели
- •10.5. Массивы указателей
- •10.6. Указатели на функции
- •10.7. Ссылки
- •10.8. Операторы new и delete
- •Задачи -. Указатели и ссылки
- •Глава 11. О файлах и командной строке
- •11.1. Знакомство с файлами
- •11.2. Командная строка
- •11.3. Перенаправление стандартного ввода и вывода на файл
- •11.4. Аргументы командной строки
- •Задачи -. Файлы и командная строка
- •Глава 12. Работа с экраном дисплея
- •12.1. Текстовый режим
- •12.2. Графический режим
- •Задачи -. Работа с экраном
- •Глава 13. Внутреннее представление чисел
- •13.1. Двоичная система счисления
- •13.2. Беззнаковые целые
- •13.3. Двоичный дополнительный код
- •13.4. Двоичный код с избытком
- •13.5. Побитовые операторы
- •13.6. Дробные числа в двоичной системе
- •13.7. Внутреннее представление плавающих типов
- •13.8. Преобразование типов
- •Задачи -. Побитовые операторы
- •Глава 14. Структуры, перечисления, объединения
- •14.1. Объявление структур
- •14.2. Структуры и функции
- •14.3. Указатели на структуры
- •14.4. Массивы структур
- •14.5. Перечисления
- •14.6. Объединения
- •14.7. Битовые поля
- •14.8. О бинарных файлах
- •Задачи -. Структуры
- •Глава 15. Классы
- •15.1. Структуры в C++. Инкапсуляция
- •15.2. Встроенные функции
- •15.3. Классы. Скрытие данных
- •15.4. Конструкторы
- •15.5. Статические члены класса
- •15.6. Друзья класса
- •15.7. Копирование объектов класса
- •15.8. Управление доступом
- •15.9. Ссылка на себя
- •15.10. Деструкторы
- •Задачи -. Работа с классами
- •Глава 16. Программы из нескольких файлов
- •16.1. Работа с проектами
- •16.2. Область действия имен
- •16.3. Заголовочные файлы
- •16.4. Пространства имен
- •Задачи -. Работа со стеком
- •Глава 17. Перегрузка операторов
- •17.1. Правила перегрузки операторов
- •Задачи -. Перегрузка операторов
- •Глава 18. Конструктор копирования и оператор присваивания
- •18.1. Проблемы при копировании
- •Задачи -. Конструктор копирования
- •Глава 19. Ввод и вывод
- •19.1. Вывод
- •19.2. Ввод
- •19.3. Ввод и вывод определяемых пользователем типов
- •19.4. Работа с файлами
- •Глава 20. Взаимоотношения классов
- •20.1. Объекты как члены класса
- •20.2. Конструкторы встроенных типов
- •20.3. Наследование
- •20.4. Виртуальные функции
- •20.5. Абстрактные классы
- •20.6. Совместимость типов
- •20.7. Множественное наследование
- •Задачи -. Наследование классов
- •Глава 21. Шаблоны, исключения
- •21.1. Шаблоны
- •21.2. Шаблоны функций
- •21.3. Классы и шаблоны
- •21.4. Обработка исключений
- •21.5. Стандартная библиотека шаблонов
- •Литература
- •Предметный указатель
227
Глава 16. Программы из нескольких файлов
Исходная программа на C++ может располагаться в одном файле, но это становится неудобными или даже невозможным для больших программ. В этом случае текст программ размещается в нескольких файлах. Это удобно, так как небольшой код можно легко понять и отладить. Кроме того, работу можно распределить между несколькими программистами.
Средством работы с программами, состоящими из нескольких файлов, являются проекты, объединяющие файлы, из которых состоит программа. В проект могут входить cpp-файлы с исходным кодом, obj- файлы, с откомпилированным кодом. Заголовочные h-файлы в проект не включаются, так как они вставляются в состав других файлов директивой препроцессора #include.
При создании проекта необходимо обеспечить, чтобы функция или переменная, определенная в одном файле, была видима в другом. Это достигается с помощью объявлений переменных или функций перед их использованием. Переменные, определенные во внешнем файле, становятся видимыми в другом файле после их объявления с ключевым словом extern. При объявлении функций слово extern можно не использовать.
16.1. Работа с проектами
Проекты в Turbo C++
В среде TC новый проект создается командой меню Project, Open Project…, при этом появляется диалог Open Project File, рис.71. В поле Open Project File следует ввести имя создаваемого проекта, расширение
PRJ к имени файла проекта будет добавлено автоматически при сохранении проекта. После нажатия кнопки OK откроется вначале
пустое окно проекта, рис.72. Окно проекта можно закрыть, но сам проект при этом закрыт не будет. Проект закрывается командой Project,
Close project. Окно проекта выводится на экран командой Window, Project.
Когда активно окно, проекта клавишей Ins можно добавить в проект файл, клавишей Delete удалить файл из проекта. Те же действия можно выполнить соответствующими командами меню Project. Порядок
228 16
включения файлов в проект произволен. На рис.73 показано, что в проект SumNumb.PRJ включены два объектных файла ATOF.OBJ и GETLINE.OBJ, а также файл с исходным кодом SUMNUMB.CPP. Если в окне проекта выбрать файл и нажать Enter, данный файл будет открыт в
окне редактирования.
Рис.74. Открытие и создание проекта
Для открытия существующего проекта выполняется та же команда Project, Open, и выбирается имя проекта из списка Files, рис.75.
Рис.76. Окно проекта
Для создания из проекта рабочей программы нужно выполнить одну из команд меню Compile:
Make или клавиша F9 – выполняется перекомпиляция измененных
файлов и производится сборка программы;
Link – производится сборка программы без перекомпиляции
исходных файлов;
Build all – перекомпилируются все файлы, входящие в проект.
Рабочая программа будет иметь имя, совпадающее с именем проекта и расширение .exe.
Программы из нескольких файлов 229
Проекты в C++Builder
Как уже говорилось, в C++Bulder проект создается для каждого приложения. Для управления составом проекта используются команды меню Project:
Add to Project… – добавление в проект нового файла; Remove from Project… – удаление из проекта файла.
16.2. Область действия имен
Имена имеют переменные, функции, структуры, перечисления, классы, элементы классов и структур. Когда программы становятся большими, возрастает вероятность конфликта между именами.
Зоной видимости глобальной переменной является файл. К такой переменной можно обратиться в любом месте программы от точки объявления до конца файла.
Зоной видимости локальной переменной является часть блока, в котором она определена от точки объявления до конца блока.
Локальная переменная может перекрывать глобальную переменной с тем же именем. Пример такого перекрытия демонстрируется в приводимой ниже программе.
Программа 50. Глобальные и локальные имена
В программе использовано одно и то же имя i для двух переменных: глобальной и локальной.
// Файл Glob_Loc.cpp |
|
|
#include <iostream.h> |
|
|
int i = 5; |
|
// Глобальная переменная |
int main() |
|
|
{ |
|
|
cout << "i = " << i << endl; |
// Печать глобальной переменной |
|
int i = 1; |
// Локальная переменная закрывает глобальную |
|
cout << "i = " << i << endl; |
// Печать локальной переменной |
|
cout << "::i = " << ::i << endl; |
// Печать глобальной переменной |
|
cin.get(); |
|
|
return 0; |
|
|
} |
|
|
Программа выводит:
i = 5 i = 1 ::i = 5
230 16
Для доступа к глобальной переменной, которая не видима из-за того, что перекрыта локальной переменной с таким же именем, можно использовать оператор разрешения зоны видимости (::). Таким образом, ::i – это имя переменной из внешнего блока.
Водной зоне видимости нельзя объявлять переменные с одинаковыми именами.
Единицей компиляции в языке C++ является файл. Файл может содержать различные объявления и определения, в том числе объявления и определения переменных и функций. В одном файле можно поместить определения нескольких функций. Запрещено помещать части одной функции в различных файлах.
ВC++ запрещено определять функции внутри других функций, поэтому имя функции всегда глобально и может быть доступно в любой другой функции при соответствующем объявлении.
Областью действия имени является часть программы, в которой это имя можно использовать. Для автоматических переменных, описанных в начале функции, областью действия является эта функция. То же относится к параметрам функций, которые фактически являются локальными переменными. Имена функций и глобальных переменных видны от точки определения до конца файла без дополнительного объявления. При соответствующем объявлении функции и глобальные переменные могут быть видны в любом файле программы. Зону действия имен можно ограничить одним файлом, объявив имена
статическими.
Статические имена
Рассмотрим схематический пример программы из двух файлов.
// Файл File_1.cpp |
|
int N; |
// Определение внешней переменной |
void f1() |
// Определение функции f1 |
{ |
|
N = 1; |
// Использование внешней переменной |
} |
|
// Файл File_2.cpp |
|
void f1(); |
// Объявление (прототип) функции f1 |
extern int N; |
// Объявление внешней переменной |
int f2() |
// Определение функции f2 |
{ |
|
f1(); |
// Обращение к функции f1 |
int k = N; |
// Использование внешней переменной, k = 1 |
return k; |
|
} |
|
Программы из нескольких файлов 231
Объявление функции f1 в файле File_2.cpp делает ее известной компилятору, который может сгенерировать ее правильный вызов. Объявление внешней переменной N позволяет использовать ее в любом месте файла File_2.cpp после точки объявления. Если в проект включены оба файла, редактор связей найдет код f1, включит его в рабочую программу и сделает ссылку на него из f2. Аналогично, редактору связей будет известен адрес N, по которому к ней можно обращаться. Недостаток данной программы состоит в том, что не так-то просто понять, почему значением k будет 1. При попытке определить еще одну внешнюю переменную с именем N в файле File_2.cpp возникает ошибка на этапе редактирования связей.
Можно ограничить зону действия имен, сделав их статическими, для чего объявления нужно начинать словом static. Проиллюстрируем это примером.
// Файл File_1.cpp |
|
static int N; |
// Определение внешней переменной |
static void f1() |
// Определение функции f1 |
{ |
|
N = 1; |
// Использование внешней переменной |
} |
|
// Файл File_2.cpp |
|
void f1(); |
// Объявление (прототип) функции f1 |
extern int N; |
// Объявление внешней переменной |
int f2() |
// Определение функции f2 |
{ |
|
f1(); |
// Обращение к функции f1 |
int k = N; |
// Использование внешней переменной, k = 1 |
return k; |
|
} |
|
При компиляции файла File_2.cpp ошибок не будет, так как есть все необходимые объявления, но на этапе компоновки возникнут ошибки, так как компоновщик не найдет f1 и N, из-за ограниченности их зоны действия файлом File_1.cpp. Компоновщик выдаст сообщение об ошибке вида: Linker error…
Программа 51. Сумматор чисел
Напишем программу, которая вводит с клавиатуры числа с плавающей точкой и суммирует их. Числа поступают с клавиатуры в виде строк, которые следует преобразовывать в числовые значения.
Строки символов можно вводить стандартным образом с помощью cin >>, разделяя вводимые числа пробелами, но в данной программе
232 16
будем читать с клавиатуры строки символов, а затем преобразовывать строки в числа.
Для чтения строк напишем функцию int readline(),
которая читает не более MAXLINE символов в массив line, извлекает из входного потока символ новой строки \n, но не помещает его в формируемую строку, и возвращает длину прочитанной строки. Массив line и предельный размер строки MAXLINE зададим как внешние переменные. Функцию readline разместим в файле Readline.cpp.
Для преобразования строк в числа с плавающей точкой напишем функцию strtof и поместим ее в отдельном файле StrTof.cpp.
Главную функцию main, которая будет вводить и суммировать числа, поместим в файле SumNumb.cpp.
Функция strtof преобразует строку цифр, в которой может быть знак и десятичная точка, отделяющая целую часть от дробной, в число двойной точности. Сначала устанавливается знак числа, затем вычисляется целая часть val. Если присутствует десятичная точка, продолжается вычисление val как целого и параллельно накапливается степень 10, на которую надо поделить val, чтобы сформировать правильное значение.
//Файл Strtof.cpp #include <ctype.h>
//strtof: преобразование строки s в double double strtof(char s[])
{
double val, pow10; |
|
int i, sign; |
|
for(i = 0; isspace(s[i]); i++) |
// Пропуск начальных пробелов |
; |
|
sign = (s[i] == '-') ? -1: 1; |
// Получение знака |
if('+' == s[i] || '-' == s[i]) |
// Если есть знак, |
i++; |
// переходим к следующему символу |
for(val = 0.0; isdigit(s[i]); i++) |
// Получаем целую часть |
val = val * 10 + s[i] - '0'; |
|
if('.' == s[i]) |
// Если есть десятичная точка |
i++; |
// Переход к дробной части |
for(pow10 = 1.0; isdigit(s[i]); i++){// Получение дробной части |
|
val = val * 10 + s[i] - '0'; |
|
pow10*=10.0; |
// Степень 10 |
} |
|
return sign * val / pow10; |
|
}
Программы из нескольких файлов 233
Для проверки того, что символ является пробельным, применяется функция isspace, а для проверки того, что символ есть цифра – isdigit.
//Файл ReadLine.cpp #include <iostream.h>
//Объявление внешних переменных extern int MAXLINE;
extern char line[];
/* readline: читает не более MAXLINE символов в массив line, возвращает длину строки */
int readline()
{
int c, i;
for(i = 0; i < MAXLINE - 1 && (c = cin.get()) != EOF && c != '\n'; ++i)
line[i] = c; |
|
line[i] = '\0'; |
|
return i; |
// Возвращаем длину строки |
}
Для чтения отдельных символов в readline применена библиотечная функция int cin.get().
В функции main читаются строки, пока не встретится строка нулевой длины (пустая), строки преобразуются в числа, которые добавляются к сумме. Очередное значение суммы выводится.
// Файл SumNumb.cpp #include <iostream.h> #include <conio.h>
int readline(); // Прототип функции чтения строки
double strtof(char[]);// Прототип функции преобразования строки в число
// Сумматор вводимых чисел int main()
{ |
|
double sum = 0.0; |
// Сумма |
extern char line[]; |
// Объявление массива line |
while(readline() > 0) |
// Пока есть строки, преобразуем |
cout << (sum+=strtof(line)) << endl;// их в числа и суммируем |
|
getch(); |
|
return 0; |
|
} |
|
// Определение внешних переменных |
|
int MAXLINE = 100; |
|
char line[100]; |
// Массив под строку |