- •Предисловие
- •Глава 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. Стандартная библиотека шаблонов
- •Литература
- •Предметный указатель
176
Глава 14. Структуры, перечисления, объединения
14.1. Объявление структур
Структура – это одна или несколько переменных, возможно, различных типов, которые сгруппированы под одним именем. Структуры полезны, когда для описания одного объекта требуется несколько данных различных типов, например, при создании электронной записной книжки каждый человек может характеризоваться строкой символов с фамилией и числовым номером телефона.
Для моделирования точек на плоскости, рис.59, можно использовать следующую структуру:
struct point{ |
// Структура для моделирования точек на плоскости |
|||||
int x; |
|
|
|
|
|
|
int y; |
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
y |
|
|
|
|
|
|
|
|
|
|
||
|
3 |
|
|
|
(4, 3) |
|
|
|
|
|
|
|
|
|
(0, 0) |
4 |
x |
|||
|
|
|
|
Рис.60. Точки на плоскости
Здесь struct – это ключевое слово, с которого начинается описание структуры. Идентификатор point – это имя структуры. В фигурных скобках помещается список объявлений членов или полей структуры x и y. Имена членов структуры должны различаться, но могут совпадать с именами других переменных программы.
Объявление структуры является объявлением типа. Имя структуры является именем нового пользовательского типа данных, который можно использовать так же, как имена встроенных типов. Например, чтобы создать переменные структурного типа, нужно записать:
point pt1, pt2, pt3; // Определение трех точек на плоскости
Эта запись аналогична объявлению переменных встроенных типов:
Структуры, перечисления, объединения 177
int a, b, c;
Переменные структурного типа могут копироваться, над ними можно выполнять операции присваивания, их можно передавать в функции в качестве аргумента и возвращать из функции в качестве результата.
Структурные переменные можно инициализировать при определении, например,
point nachkoord = {0, 0}, p1 = {1, 1};
Список инициализаторов заключается в фигурные скобки, в качестве инициализаторов можно использовать константы и константные выражения. Локальные переменные структурного типа, определенные внутри функции, можно инициализировать вызовами функций, которые возвращают результат структурного типа.
Доступ к члену структуры осуществляется конструкцией:
ИМЯ_СТРУКТУРЫ.ЧЛЕН
Например, чтобы напечатать координаты точки p1, можно использовать инструкцию:
cout << p1.x <<”, ” << p1.y;
y
pt2
pt1
(0 |
, 0) |
|
x |
|
Рис.61. Прямоугольник как совокупность двух точек
Структуры могут быть вложенными друг в друга, например, прямоугольник, рис.62, можно рассматривать как совокупность двух точек, объединенных в одну структуру:
struct rect{ |
// Прямоугольник |
point pt1; |
// Первая вершина |
point pt2; |
// Вторая вершина |
}; |
|
Структура rect имеет своими членами две структуры point. Пусть объявлена структурная переменная:
178 14
rect screen;
Выражение screen.pt1.x ссылается на координату x точки pt1 из структуры screen.
14.2. Структуры и функции
Рассмотрим несколько функций, манипулирующих точками и прямоугольниками.
// make_point: создание точки point make_point(int x, int y)
{
point tmp;
tmp.x = x; tmp.y = y; return tmp;
}
Здесь внутри функции создается локальная структура tmp, ее членам присваиваются значения. Затем с помощью return значение структуры возвращается из функции, после чего работа функции завершается, и локальная структура tmp уничтожается. Значение структуры, возвращенное из функции, может быть присвоено какой-то структурной переменной в вызывающей программе.
Следующая функция создает прямоугольник по двум точкам p и q:
// make_rect: создание прямоугольника rect make_rect(point p, point q)
{
rect tmp;
tmp.pt1 = p; tmp.pt2 = q; return tmp;
}
Здесь внутри функции создается локальная структура tmp, полям которой присваиваются значения структур p и q. При присваивании структур производится почленное копирование.
Возможно, что точка pt1 не лежит ниже и левее, чем pt2. Следующая функция преобразует прямоугольник к каноническому виду.
#define max(a, b) (a)>(b)?(a):(b) |
// Макрос для выбора максимума |
#define min(a, b) (a)<(b)?(a):(b) |
// Макрос для выбора минимума |
// canon_rect: канонизация координат прямоугольника rect canon_rect(rect r)
{
rect tmp;
Структуры, перечисления, объединения 179
tmp.pt1.x = min(r.pt1.x, r.pt2.x); tmp.pt1.y = min(r.pt1.y, r.pt2.y); tmp.pt2.x = max(r.pt1.x, r.pt2.x); tmp.pt2.y = max(r.pt1.y, r.pt2.y); return tmp;
}
14.3. Указатели на структуры
При передаче структуры в функцию создается локальная копия этой структуры, в которую копируются все члены структуры-аргумента. Если структура большая, то эффективнее может быть передача указателя на структуру, так как указатель – это адрес, имеющий небольшой размер.
Объявление point* pp;
сообщает, что pp есть указатель на структуру point. Если pp ссылается на структуру, то выражение
*pp
есть сама структура, а выражения
(*pp).x, (*pp).y
являются членами структуры. Скобки в выражении (*pp).x необходимы, так как приоритет оператора точка (.) выше, чем приоритет оператора звездочка (*) и выражение *pp.x будет проинтерпретировано как *(pp.x), что неверно, так как pp не структура, а pp.x не является указателем.
Пусть имеем фрагмент программы:
point origin, *pp; |
// Структура и указатель на структуру |
pp = &origin; |
// Указателю pp присвоен адрес структуры origin |
Напечатать координаты точки origin можно следующим образом: cout << ”origin: (” << (*pp).x << ”, ” << (*pp).y << ”)”;
Для доступа к членам структуры через указатель существует специальный оператор стрелка, образованный символами минус и больше:
->
Если p – указатель на структуру, то выражение p->ЧЛЕН_СТРУКТУРЫ
180 14
есть ее отдельный член, поэтому напечатать координаты точки origin можно инструкцией:
cout <<”origin: (” << pp->x << ”, ” << pp->y << ”)”;
Операторы точка (.) и стрелка (->) имеют одинаковый приоритет и выполняются слева направо. Пусть, например, сделаны объявления:
rect r, *pr = &r;
Следующие выражения эквивалентны:
r.pt1.x, pr->pt1.x, (r.pt1).x
С помощью функции make_point можно динамически инициализировать структуры. Например, следующая функция получает в качестве аргумента указатель на структуру rect, внутри функции создается точка, динамически инициализируемая вызовом функции.
// cetner_rect: возвращает точку - центр прямоугольника point center_rect(rect* pr)
{
point tmp =
make_point((pr->pt1.x + pr->pt2.x) / 2, (pr->pt1.y + pr->pt2.y) / 2); return tmp;
}
Программа 36. Точки и прямоугольники на экране
Программа иллюстрирует применение разработанных выше структур и функций, моделирующих точки и прямоугольники на математической плоскости. Требуется отображать точки и прямоугольники на физической плоскости экрана, где система координат отличается от принимаемой, обычно, в математике, рис.63.
На экране при его работе в текстовом режиме начало системы координат находится в левом верхнем углу, ось xs направлена вправо, ось ys вниз, то есть координата ys отсчитывается от верхнего края экрана. Левый верхний угол экрана имеет координаты (1, 1). Высота экрана составляет обычно 25 строк, ширина – 80 столбцов. Кроме того, если на экране создано окно, то в нем действует своя локальная система координат, с началом в левом верхнем углу окна.
Будем считать, что первый квадрант математической плоскости совпадает с физической плоскостью экрана, то есть ось x совпадает с нижним краем экрана, ось y – с левым, единица длины на математической плоскости численно равна единице длины на экране. Отсюда следует связь математических координат x, y и экранных координат xs, ys:
Структуры, перечисления, объединения 181
xs = x, ys = 25 − y.
Данные соображения учитываются в функции void show_rect(rect* pr, int color);
которая изображает на экране прямоугольник и переводит курсор в его центр. В программе использованы такие же обозначения, как на рис. 64.
Рис.65. Отображение математической плоскости на плоскость экрана
В текст программы следует вставить сделанные выше объявления структур point и rect и определения функций.
// Файл PointRct.cpp |
|
struct point{ |
// Cтруктура точка |
int x, y; |
|
}; |
|
// make_point: создание точки |
|
point make_point(int x, int y) |
|
{ |
|
point tmp; |
|
tmp.x = x; tmp.y =y; |
|
return tmp; |
|
} |
|
struct rect{ |
// Структура прямоугольник |
point pt1, pt2; |
|
}; |
|
// make_rect: создание прямоугольника rect make_rect(point p, point q)
{
182 14
rect tmp;
tmp.pt1 = p; tmp.pt2 = q; return tmp;
}
#include <conio.h>
// cetner_rect: возвращает точку - центр прямоугольника point center_rect(rect* pr)
{
point tmp =
make_point((pr->pt1.x + pr->pt2.x) / 2, (pr->pt1.y + pr->pt2.y) / 2); return tmp;
}
#define max(a, b) (a)>(b)?(a):(b) #define min(a, b) (a)<(b)?(a):(b)
//canon_rect: канонизация координат прямоугольника rect canon_rect(rect r)
{
rect tmp;
tmp.pt1.x = min(r.pt1.x, r.pt2.x); tmp.pt1.y = min(r.pt1.y, r.pt2.y); tmp.pt2.x = max(r.pt1.x, r.pt2.x); tmp.pt2.y = max(r.pt1.y, r.pt2.y); return tmp;
}
//show_rect: изображает прямоугольник на экране и
//помещает курсор в его центр
const int HIGHT = 25; |
// Высота экрана в строках |
void show_rect(rect* pr, int color)
{
//LU – Левый верхний угол прямоугольника на экране point RD = make_point(pr->pt2.x, HIGHT - pr->pt1.y);
//RD – Правый нижний угол прямоугольника на экране
window(LU.x, LU.y, RD.x, RD.y); |
// Создание окна, |
|
|
|
// соответствующего прямоугольнику |
||
textbackground(color); |
// Выделение прямоугольника |
|
|
clrscr(); |
// цветом |
|
|
point M = center_rect(pr); |
// Центр прямоугольника в |
|
|
|
// |
математической |
системе |
координат |
|
|
|
int xM = M.x, yM = M.y; |
// Координаты центра в |
|
Структуры, перечисления, объединения |
183 |
|||
|
|
// |
математической |
системе |
|
координат |
|
|
|
int xsM = xM, ysM = HIGHT - yM; |
// Координаты центра |
|
||
|
|
// прямоугольника на экране |
|
|
int xwM = xsM - LU.x, ywM = ysM - LU.y; |
// xwM, ywM – координаты |
|||
|
|
// центра прямоугольника в окне |
||
M = make_point(xwM, ywM); |
// Преобразование координат центра |
|||
|
|
// прямоугольника в оконные |
|
|
gotoxy(M.x, M.y); |
// Перевод курсора в центр прямоугольника |
|||
} |
|
|
|
|
# include <iostream.h> |
|
|
|
|
void main() |
|
|
|
|
{ |
|
|
|
|
point a, b; |
// Две точки |
|
||
rect ab; |
// Прямоугольник |
|
||
int x, y; |
|
|
|
|
textbackground(BLACK); |
|
|
|
|
clrscr(); |
// Очистка экрана |
|
||
cout << "Введите координаты первой точки\n"; |
|
|||
cin >> x >> y; |
|
|
|
|
a = make_point(x, y); |
// Первая вершина прямоугольника |
|||
cout << "Введите координаты второй точки \n"; |
|
|||
cin >> x >> y; |
|
|
|
|
b = make_point(x, y); |
// Вторая вершина прямоугольника |
|||
ab = make_rect(a, b); |
// Создание прямоугольника |
|
||
ab = canon_rect(ab); |
// Приведение к каноническому виду |
|
||
show_rect(&ab, RED); |
// Изображение на экране |
|
||
getch(); |
|
|
|
|
} |
|
|
|
|
На рис. 66 приведено изображение экрана при работе с программой.