Открыть Электронные книги
Категории
Открыть Аудиокниги
Категории
Открыть Журналы
Категории
Открыть Документы
Категории
КОВШОВ
КОНСТРУИРОВАНИЕ ПРОГРАММНОГО
ОБЕСПЕЧЕНИЯ
Лабораторный практикум
Самара
Самарский государственный технический университет
2022
МИНИСТЕРСТВО ОБРАЗОВАНИЯ И НАУКИ РОССИЙСКОЙ ФЕДЕРАЦИИ
К а ф е д р а «Вычислительная техника»
В.И. КОВШОВ
КОНСТРУИРОВАНИЕ ПРОГРАММНОГО
ОБЕСПЕЧЕНИЯ
Лабораторный практикум
Самара
Самарский государственный технический университет
2022
1
Печатается по решению редакционно-издательского совета СамГТУ
УДК 004.438
ББК 32.973.26-018.2
К 56
Ковшов В.И.
К 56 Конструирование программного обеспечения: лабораторный прак-
тикум / В.И. Ковшов. – Самара: Самар. гос. техн. ун-т, 2022. – 58 с.
УДК 681.324
К 56
2
Лабораторная работа № 1
ПРОСТЫЕ ПРОГРАММЫ С ЦИКЛАМИ
И ОПЕРАТОРАМИ КОНСОЛЬНОГО ВВОДА/ВЫВОДА
ЗАДАНИЕ
3
ТЕОРЕТИЧЕСКИЙ МАТЕРИАЛ
4
− Debug – версия проекта, в которой выключается оптимизация
кода и включается в него отладочная информация;
− Release – версия, в которой делается все наоборот
(выключается отладочная информация и включается оптимизация
кода).
Обычно при создании нового проекта он автоматически помеща-
ется во вновь созданное решение в конфигурации Debug. Демонстра-
ция файлов проекта в отдельной папке проекта не означает, что фай-
лы физически расположены в одной папке. Оболочка может исполь-
зовать ссылки на файлы из других директорий, но графически отоб-
ражать файлы так, как будто они находятся в папке проекта. В про-
цессе работы с проектом вы можете безболезненно удалять папки
Debug или Release. Они автоматически восстановятся при последую-
щей компиляции исходных файлов.
Visual Studio предлагает выбор из различных типов проектов
приложений. Их все можно увидеть, выбрав пункт меню File > New >
Projects. Для создания консольного приложения выполните действия
в следующей последовательности.
1. Выберите в меню команду File > New > Projects.
2. В появившемся окне диалога выберите тип проекта Win32 Con-
sole Project.
3. В поле Name задайте имя проекта: First.
4. Выберите месторасположение папки с проектом (в поле Location:).
5. Нажмите кнопку More, введите имя решения Solution (Lab1) и
сделайте отметку в окне Create directory for Solution.
6. Подтвердите выбор, нажав ОК.
7. Нажмите кнопку Finish.
Фокус переходит в окно редактора текста, где можно ввести код
программы. Набранную программу можно сразу компилировать и за-
пускать на выполнение.
Компиляция, компоновка и запуск приложения в Microsoft Visual
Studio совершаются с помощью команд, выбираемых из меню Build
или Debug или с помощью комбинаций клавиш (shortcuts). Самый
5
быстрый способ запуска программы – с помощью команды Debug >
Start или F5. Отдав команду, вы должны увидеть сообщение (message
box) о том, что не существует файла First.exe или First.obj во вновь
созданной папке Debug (эта конфигурация проекта выбрана по умол-
чанию). Согласитесь с предложением создать эти файлы.
Выполнение Debug-версии проекта в пошаговом режиме осу-
ществляется с помощью следующих клавиш:
− F10 – без захода в вызываемые функции (Step Over);
− F11 – с заходом в вызываемые функции (Step Into).
Поставьте фокус в окно редактора и нажмите клавишу F10. При-
ложение запускается в режиме пошаговой отладки и появляется но-
вое окно Locals для просмотра текущего содержимого переменных
программы.
Массивы, объекты классов и структуры можно «раскрывать» (ex-
pand). Переход в окно выполняемого приложения выполняется обыч-
ным способом – нажатием комбинации клавиш Alt+Tab. Каждое
нажатие клавиши F10 приводит к выполнению одной строки про-
граммы. Указатель в окне редактора опережает события и устанавли-
вается на ту строку, которую еще предстоит выполнить. Нажмите
клавишу F10 еще раз – указатель перемещается на первую строку с
выполнимыми операторами. Посмотрите в окно Locals. Здесь высве-
чены текущие значения переменных
Останавливать отладку следует командой Stop Debugging (Shift+F5).
Клавиша F11 служит для пошагового выполнения с заходом в
вызываемые функции. Она позволяет пройтись по многим системным
функциям, и ее можно рассматривать как некоего гида по коду, на-
писанному разработчиками системы. Без сомнения, таким образом
можно многое увидеть, многое понять и многому научиться. Гид про-
сто необходим, когда вы хотите попасть внутрь своей функции, вызов
которой находится в текущей строке отладчика.
Ошибки, обнаруженные на этапах компиляции и компоновки,
выводятся в окно Output. Мгновенный переход в файл с текстом про-
граммы (к строке с ошибкой) происходит при двойном щелчке на
6
строке с сообщением об ошибке. Это справедливо для ошибок, обна-
руженных на этапе компиляции. Многие ошибки на этапе компонов-
ки (linking) могут быть исправлены путем изменения настроек про-
екта (Project > Properties...).
Пример
Ввод точек экспериментально полученной зависимости у = f(x),
то есть дискретных значений аргумента x[i] и соответствующих им
значений функции y[i].
7
printf ("\nx[%d]= ",i+1);
scanf ("%f",&x[i]);
printf ("y[%d]= ",i+1);
scanf ("%f",&y[i]);
}
puts ("\n You've entered:");
for (i=0; i<n; i++)
printf("\nx[%d]=%5.2f\ty[%d]=%6.3f",i+1,x[i],i+1,y[i]);
puts( " \n\n");
}
МЕТОДИКА ВЫПОЛНЕНИЯ
СОДЕРЖАНИЕ ОТЧЕТА
КОНТРОЛЬНЫЕ ВОПРОСЫ
8
1. Как выполняется отладка приложений в среде MS Visual Studio?
2. Как определить место в программе, где обнаружена ошибка компиляции?
3. Как работает функция printf()?
4. Какую роль в программе играет функция int in(int min, int max)?
5. Какие операторы циклов существуют в С++, каково их назначение, принцип
работы?
6. Как называется главная функция в программах на С++ и какова ее роль?
7. Как работают функции ввода, использованные в примере?
Лабораторная работа № 2
РАБОТА С ТЕКСТОВЫМИ ФАЙЛАМИ,
СТРУКТУРАМИ ДАННЫХ И МЕНЮ
ЗАДАНИЕ
9
Таблица 2
Варианты задания
Бригада Объекты и их атрибуты
№
1 Комплектующие для ПК: тип, модель, цена.
2 Географические объекты: тип, название, размер
(длина/высота/площадь), ед. измерения (м, кв.м).
3 Сотрудники: Ф.И.О., возраст, должность.
4 Канцелярские товары: тип, фирма-производитель, цена.
5 Графические фигуры: тип, длина контура, площадь.
6 Микросхемы: тип, технология, серия.
7 Бытовые приборы: тип, марка, потребляемая мощность.
8 Компьютерные программы: категория, название, объем дистрибутива.
9 Радиоэлектронные элементы: тип, марка, количество в наличии.
10 Автомобили: марка, изготовитель, мощность двигателя.
11 Книги: автор, название, объем.
12 Небесные тела: тип, название, расстояние от Земли.
ТЕОРЕТИЧЕСКИЙ МАТЕРИАЛ
СТРУКТУРНОЕ ПРОГРАММИРОВАНИЕ
И ФУНКЦИОНАЛЬНАЯ ДЕКОМПОЗИЦИЯ СИСТЕМЫ
10
4. Текст программы физически разбит на части, чтобы облегчить
чтение. Выполняемые предложения каждого модуля должны уме-
щаться на одной странице печатающего устройства.
5. Программа представляет собой простое и ясное решение за-
дачи.
6. Текст программы сопровождается комментариями, поясняю-
щими назначение переменных и шаги алгоритма.
При структурном подходе главным является принцип разработки
ПО сверху вниз. Все начинается со структурного анализа будущего
комплекса ПО и декомпозиции алгоритма на осмысленные части
(блоки), которые должны быть максимально автономными, обозри-
мыми (то есть достаточно короткими) и обычно не реализованными в
виде программ. Структурированная программа состоит из блок-
программы и блоков. Первая не должна содержать вычислений, она
содержит обращения к блокам, которые выполняют роль отдельных
строительных кирпичиков сложного комплекса. Начинают писать
структурированную программу с блок-программы, которую пытают-
ся отладить, даже не имея всех составляющих ее блоков. Блоки заме-
няют временными программными заглушками. Если какой-то блок
оказывается плохо обозримым или появляются трудности в его реа-
лизации, то с ним пытаются поступить так же, как и со всей програм-
мой, то есть разбить на отдельные более мелкие части. Каждый блок
оформляется в виде отдельной функции языка.
В языке С++ все функции глобальные. Объявление функции име-
ет вид:
return_type func_name(arg_typel argl, arg_type2 arg2, ...);
Для объявления функции необходимо указать тип возвращаемого
значения, который может быть любым: как базовым (int, char* и т. д.),
так и определенным программистом (struct fruit и т. п.). Если функция
не возвращает никакого значения, то следует указать тип void. Затем
следует имя функции, которое может быть произвольным, но лучше,
если оно несет информацию о ее назначении. После имени в круглых
скобках перечисляются все ее аргументы с указанием типа каждого.
11
Аргументы могут и отсутствовать. Определение функции содержит код
ее реализации (тело функции), заключенный в фигурные скобки. Объ-
явление и определение функции могут быть отделены друг от друга.
В C++ передача параметров осуществляется по значению. При
этом внутри функции заводится копия переданного параметра. Копии
присваивается значение, равное значению фактического параметра.
Если функция в процессе своей работы изменит значение параметра
(его копии), то вызывающая процедура никак не сможет это обнару-
жить. Если необходимо, чтобы функция возвращала измененные зна-
чения параметров, то в функцию передается адрес переменной (ука-
затель). Переменная типа указатель объявляется при помощи символа
* перед именем переменной:
long factorial(int nNumber) {…}
int swap(float *a, float *b) {…}
12
case 0: break;
default: с = 0;
}
}
}
Выражение getch()-'0' использовано для анализа символа, введен-
ного пользователем. При вычитании кода символа '0', равного 48, код
введенного символа преобразуется в целое число, соответствующее
количеству символов в кодовой таблице между нулем и введенным
символом. Таким образом, если была введена цифра, то выражение
дает число, равное этой цифре. Если введена не цифра, то переменная
unsigned c содержит некоторое недопустимое число, которое игнори-
руется, и цикл запроса ввода повторяется.
СТРУКТУРЫ ДАННЫХ
13
Следующий пример показывает различные варианты обращения к
полю Age структуры Man:
Man m, *p=&m, d[10], *pm[10];
m.Age=20;
р->Аge=20;
d[2].Age=31;
pm[0]->Age=23;
ОПЕРАЦИИ С ФАЙЛАМИ
14
Режим обработки чисел (binary mode) отмечается символом b,
например: а+b, wb и т. д.
В случае успеха функция fopen возвращает указатель на вновь откры-
тый поток. Если попытка оказалась неудачной, она возвращает NULL.
Библиотека ввода-вывода stdio.h имеет много других функций
для работы с файлами, например:
− void rewind (FILE* stream); – переустанавливает указатель
файла на начало потока;
− int fseek (FILE *stream,long offset,int origin); – перемещает
указатель в заданную позицию;
− int fclose (FILE *stream); – закрывает файл;
− char *fgets (char *string, int n, FILE *stream ); – чтение строки
текста из потока, где
String – место размещения данных; N – максимальное количество
символов, которые должны быть считаны; stream – указатель на
структуру FILE;
− int fgetc (FILE *stream ); – чтение символа из потока;
− int fprintf (FILE *stream, const char *format [, argument ]...); –
форматированный вывод в текстовый файл. Аналогично printf, но
первый параметр – указатель на файловую структуру;
− int fputc (int c, FILE *stream ); – Вывод символа с в тексто-
вый файл
FILE *stream;
char line[100];
15
МЕТОДИКА ВЫПОЛНЕНИЯ
СОДЕРЖАНИЕ ОТЧЕТА
КОНТРОЛЬНЫЕ ВОПРОСЫ
16
5. Расскажите о типе данных struct (структура) языка C++.
6. Расскажите о функциях ввода/вывода в текстовый файл.
7. Что представляют собой строки символов в языке C++ и каковы основные
операции со строками?
8. Расскажите об алгоритме выбора функции в меню консольного приложения.
Лабораторная работа № 3
РАЗРАБОТКА И СПЕЦИФИКАЦИЯ ФУНКЦИЙ
И МОДУЛЕЙ ПРОГРАММЫ
ЗАДАНИЕ
ТЕОРЕТИЧЕСКИЙ МАТЕРИАЛ
17
раторы. Традиционно в программах на языке С++ используются два
типа файлов: файлы реализации, имеющие расширение .сpp, и заго-
ловочные файлы (файлы интерфейса), имеющие расширение .h. В за-
головочных файлах обычно располагаются именованные константы,
макроопределения и объявления, а в файлах реализации – определе-
ния переменных и функций. Заголовочные файлы подключаются по-
средством директивы препроцессора #include.
Обычный способ доступа к внешним определениям в файле состо-
ит в создании отдельного файла заголовка, содержащего внешние объ-
явления и поддерживающего необходимые для корректного использо-
вания определения типов. Объявления заголовочного файла включают-
ся в любой файл, использующий внешние функции и объекты.
Разделение большой программы на модули (файлы) может облег-
чить процесс создания, понимания и сопровождения программ. При
этом связанные функции и структуры могут группироваться для об-
легчения их чтения и понимания, а локальные модификации могут
иметь ограниченный эффект. Кроме того, код, разделенный на фай-
лы, легче перерабатывать для повторного использования в другой
программе. Это обычный способ повторного использования кода,
например в библиотеках.
После того как проведены функциональная и модульная компо-
зиции, т. е. определена структура программы, можно переходить к
следующему этапу – написанию кода.
Любые переменные, описанные в файле (модуле) вне какой-
либо функции и не имеющие спецификатора класса памяти (auto,
register, extern или static), по умолчанию относятся к глобальному
классу памяти и называются глобальными или внешними. Для гло-
бальных переменных память отводится только один раз и сохраня-
ется за ними до окончания выполнения программы. Если не указано
никакое инициализирующее значение, то таким переменным по
умолчанию присваивается нулевое значение. Это положение отно-
сится и к структурным типам переменных.
Область видимости таких переменных простирается от точки опи-
сания до конца файла. Если внутри блока определена автоматическая
18
переменная, имя которой совпадает с именем глобальной переменной,
то внутри блока глобальная переменная становится невидимой.
Доступ к глобальным переменным возможен и из других модулей
(файлов); для этого следует задать спецификатор памяти extern. Если
описание extern применяется к переменной, расположенной внутри
функции, то его действие распространяется только на данную функ-
цию; если же оно расположено вне какой-либо функции, то его дей-
ствие распространяется до конца модуля.
При использовании спецификатора класса памяти extern пере-
менная только объявляется и память под нее не выделяется. Следует
иметь в виду, что переменная должна быть определена в каком-
нибудь одном модуле – в нескольких модулях переменную с одним и
тем же именем определять нельзя.
Все функции по умолчанию считаются внешними или глобальны-
ми. К любой функции из любого модуля возможно обращение, если
для нее не указан спецификатор static. Другими словами, функция
определяется один раз, но может быть объявлена много раз с помо-
щью спецификатора extern.
Каждый модуль должен предваряться заголовком, который как
минимум содержит:
− название модуля;
− краткое описание его назначения;
− краткое описание входных и выходных параметров с
указанием единиц измерения;
− список используемых (вызываемых) модулей;
− краткое описание алгоритма (метода) и/или ограничений;
− Ф.И.О. автора программы;
− идентифицирующую информацию (номер версии и/или дату
последней корректировки).
Стиль оформления текстов модулей определяет использование
отступов, пропусков строк и комментариев, облегчающих понимание
программы. Как правило, пропуски строк и комментарии используют
для визуального разделения частей модуля, что позволяет прояснить
структуру программы: обычно дополнительный отступ обозначает
вложение операторов языка.
19
При использовании комментариев переводить с английского язы-
ка каждый оператор программы не нужно: любой программист, зна-
ющий язык программирования, на котором написана программа, без
труда прочитает тот или иной оператор. Комментировать следует це-
ли выполнения тех или иных действий, а также группы операторов,
связанные общим действием, т. е. комментарии должны содержать
некоторую дополнительную (неочевидную) информацию.
20
лов. В главную функцию программы main система способна передать
два параметра int argc и char* argv[].
Первый представляет собой целое число, которое соответствует
количеству параметров в командной строке программы. Второй явля-
ется массивом указателей на строки текста, которые пользователь за-
дал в командной строке.
Если запуск программы осуществлен с помощью кнопки Start на
панели задач Windows (Task bar) и при этом выбрана команда Run, то
в окне Open можно, кроме имени программы, указать дополнитель-
ные строки, адреса которых и попадут в массив argv. Предположим,
что строка запуска программы выглядит так:
"С:\Му Projects\Console\Debug\Console.exe" "..\Svet.c"
Обе строки должны быть разделены пробелами. При этом:
− argc будет равен 2, то есть учтена строка с именем запускаемо-
го файла;
− argv[0] содержит адрес первой строки (то есть строки с полным
именем запускаемого модуля);
− argv[l] содержит адрес второй строки (то есть строки с именем
файла – параметра).
Пример программы:
МЕТОДИКА ВЫПОЛНЕНИЯ
21
3. Перенесите из основного модуля в дополнительный заголовочный
объявление структуры данных и всех функций, кроме функции
main. Подключите заголовочный файл к файлу "stdafx.h". В допол-
нительный файл реализации перенесите из главного модуля опре-
деления функций и подключите файл "stdafx.h". Скомпилируйте
проект. Сделайте выводы.
4. Добавьте объявления и определения новых функций для реализа-
ции операций, указанных в п. 2 задания. Определения новых
функций должны представлять собой программные заглушки. В
главное меню программы добавьте вызовы функций. Запустите
программу и проверьте правильность ее работы.
5. Используя метод пошаговой детализации, разработайте функцию
сохранения данных в бинарном файле, затем функцию загрузки
данных из бинарного файла. Если нужно, оптимизируйте структу-
ру программы, оформив вывод таблицы на экран в виде отдельной
функции. Отладьте работу функций ввода/вывода данных в двоич-
ный файл совместно.
6. Добавьте в основной модуль функцию обработки параметров ко-
мандной строки.
СОДЕРЖАНИЕ ОТЧЕТА
КОНТРОЛЬНЫЕ ВОПРОСЫ
22
6. Расскажите о функциях ввода/вывода в бинарный файл.
7. Как в программах на С++ используются параметры командной строки?
8. Как параметры командной строки передаются в программу на C++?
Лабораторная работа № 4
РАЗРАБОТКА И СПЕЦИФИКАЦИЯ СТРУКТУР ДАННЫХ,
ИСПОЛЬЗОВАНИЕ УКАЗАТЕЛЕЙ И ДИНАМИЧЕСКИХ
МАССИВОВ СТРУКТУР
ЗАДАНИЕ
ТЕОРЕТИЧЕСКИЙ МАТЕРИАЛ
УКАЗАТЕЛИ
23
В выражениях операция * используется для разадресации, то есть
выборки содержимого по адресу. Существует обратная операция & взя-
тия адреса. Присвоение указателю адреса какой-либо другой перемен-
ной позволяет получить ее значение путем разадресации указателя (*р).
double v,*p;
*p=10.0;
v = *p + 2;
p=&v;
После выполнения оператора указатель р содержит адрес пере-
менной v, который компилятор определил для хранения значений
этой локальной переменной.
Переменная может быть создана в любой точке программы с по-
мощью операции new и затем при необходимости уничтожена с по-
мощью операции delete. Например, оператор
р = new int;
присваивает переменной р адрес начала области памяти длиной в
один элемент типа int. Память выделяется динамически из специаль-
ной области центрального пула памяти, которая называется heap.
Элемент занимает sizeof(int) байт. Операция sizeof(arg) возвращает
размер в байтах своего аргумента arg, который может быть либо ти-
пом, либо выражением.
Операция delete освобождает ранее занятую память, возвращая ее в
heap. Сам указатель при этом продолжает указывать на тот же участок
памяти, но он больше ею не управляет. При освобождении памяти нет
необходимости явно указывать ее размер, так как эту информацию со-
храняет система при реализации операции new. Если программист за-
бывает освободить память, то это остается незамеченным в небольших
программах, однако часто приводит к отказам в достаточно серьезных
разработках и является плохим стилем программирования.
В языке C++ имеется возможность инициализировать указатель пу-
тем запроса памяти прямо в момент объявления переменной. Например,
24
Эту же операцию можно было бы выполнить в два этапа.
25
a[i]=float(i*i); //Заполнение массива
p = &а[6]; //p указывает на а[6]
*р = 3.14f; // Равносильно а[6] = 3.14
p++; // Теперь р указывает на а[7]. Произошел сдвиг на 4 байта.
а[1] = *(р+3); // Равносильно а[1] = а[10]. В а[1] попадает 100.
а[2] = ++*р; //Равносильно а[2] = ++а[7]. В а[2] попадает 50.
а[3] = *++р; //Равносильно а[3] = а[8]. В а[3] попадает 64.
26
ществляется в единицах базового типа данных. Теперь такой едини-
цей является строка двухмерного массива или массив целых из трех
элементов. Имеют место следующие равенства:
а= =&а[0] а[0]= =&а[0][0] **а= = а[0][0].
Так как а является адресом адреса, понадобилась двойная ра-
задресация (**а) для того, чтобы добраться до первого элемента мас-
сива.
27
последней операцией new в применении к указателю р. Явно указы-
вать это число не нужно.
МЕТОДИКА ВЫПОЛНЕНИЯ
СОДЕРЖАНИЕ ОТЧЕТА
КОНТРОЛЬНЫЕ ВОПРОСЫ
28
5. Какой тип данных имеет идентификатор трехмерного статического массива
целых чисел?
6. Что представляет собой двумерный динамический массив?
7. Как создаются и уничтожаются динамические массивы?
8. Как создать динамический массив с переменным количеством элементов в
каждой строке?
Лабораторная работа № 5
ИСПОЛЬЗОВАНИЕ ОБЪЕКТНО ОРИЕНТИРОВАННОГО
ПРОГРАММИРОВАНИЯ В РАЗРАБОТКЕ ПРИЛОЖЕНИЙ
ЗАДАНИЕ
29
5. Переопределить для разработанного класса операторы << и >>
для консольного ввода/вывода.
ТЕОРЕТИЧЕСКИЙ МАТЕРИАЛ
30
работке реальных приложений модули описаний классов (definition
module) размещают в отдельных файлах с расширением h. Они ком-
пилируются отдельно и именно в них задаются все правила игры с
объектами классов. Тела методов размещают вне блока описания
класса в этом же файле или в другом файле (с расширением срр).
Принадлежность метода к классу обозначается в заголовке функции c
помощью операции :: .
сlass MyClass{
…. // Объявления переменных и методов
float func();
};
float MyClass::func() {
…. // операторы метода
return x;
}
КОНСТРУКТОРЫ И ДЕСТРУКТОРЫ
31
именем должен стоять символ ~. Например, описание А::~А(){}; задает
деструктор класса А, а А::А(){}; определяет его конструктор.
Один и тот же класс может иметь несколько конструкторов, если
каждый из них имеет свой собственный список аргументов. При
определении объекта будет запущен тот конструктор, с которым сов-
падает заданный список аргументов. В качестве аргумента конструк-
тора нельзя использовать объект того же класса. Вместо этого можно
использовать ссылку на объект.
Конструктор по умолчанию не имеет аргументов и используется
при создании неинициализированного объекта:
class MyClass{
public:
MyClass() { } // Конструктор по умолчанию
MyClass(int Arg) { … } // Конструктор с параметрами
….. // Остальные данные и методы
};
Без такого конструктора объекты не могли бы быть определены
без задания инициализирующих значений. Если конструктор по
умолчанию не объявлен явно, то компилятор автоматически назнача-
ет его. Он вызывается при таких определениях, как
MyClass clObj;
Аргументом конструктора может быть и сам объект класса. Та-
кой конструктор будет иметь следующий прототип:
MyClass::MyClass(MyClass &);
Такие конструкторы запускаются при копировании данных "ста-
рого" объекта во вновь создаваемый:
MyClass clObjl(7);
MyClass clObj2 = clObj1;
Если для класса конструктор копирования не определен, то ком-
пилятор сделает это сам.
В отличие от конструкторов, деструктор класса не имеет аргу-
ментов и не может быть перегружен. Деструкторы вызываются стро-
32
го в обратной последовательности вызова соответствующих кон-
структоров. Они вызываются автоматически при выходе объекта из
блока, в котором были определены. Единственным исключением из
этого общего правила является случай, когда объект создается дина-
мически из "кучи" путем вызова оператора new. В этом случае для
корректного удаления объекта необходимо явно выполнить оператор
delete, который и вызовет необходимый деструктор.
ПЕРЕОПРЕДЕЛЕНИЕ ОПЕРАЦИЙ
33
+,-,*,/ в классе комплексных чисел, мы как бы наделяем язык C++ спо-
собностью оперировать комплексными числами по обычным правилам.
Оператор cout<<i; интерпретируется как cout.operator<<(i);. Так
как тип возвращаемого значения операции – ostream&, возможна це-
почка последовательного вывода. Оператор cout<<i<<j; интерпрети-
руется как (cout.operator<<(i)).operator<<(j);.
Для ввода и вывода переменных нестандартных типов, например
объектов класса, операции << и >> следует переопределить в этом
классе с помощью friend-функций.
class Vector {
double x1, x2; // Координаты вектора
public:
// Три конструктора
Vector (double c1, double c2) // С параметрами
{x1=c1; x2=c2;}
Vector() // По умолчанию
{x1=x2= 0.; }
Vector(const Vector& v) // Копирования
{x1=v.x1; x2=v.x2;}
//= = = = = = Переопределение операций =====//
friend ostream& operator<<(ostream&, Vector& v);
friend istream& operator>>(istream&, Vector& v);
};
Pеализуем тела friend-функций вне блока описания класса.
34
Второй параметр является ссылкой на объект класса Vector. Функция
возвращает адрес выходного потока. Аналогично для переопределен-
ной операции ввода. Теперь можно вводить и выводить объекты
класса Vector:
Vector х, у;
//Переопределенные операции ввода-вывода
cout << "\n\n Enter vector:"; cin >> x;
cout << "\n Enter one more:"; cin >> y;
cout << "\n\n You have entered: " << x <<y;
МЕТОДИКА ВЫПОЛНЕНИЯ
СОДЕРЖАНИЕ ОТЧЕТА
35
КОНТРОЛЬНЫЕ ВОПРОСЫ
Лабораторная работа № 6
ИСПОЛЬЗОВАНИЕ НАСЛЕДОВАНИЯ,
ПОЛИМОРФИЗМА И АБСТРАКТНЫХ КЛАССОВ
ЗАДАНИЕ
36
6. В классах запретить непосредственный доступ к полям данных.
Доступ к атрибутам объектов осуществлять только с помощью
методов классов.
Таблица 3
Варианты задания
Бри- Предметная Список типов объектов Общие атрибуты
гада область
№
1 Комплектую- Процессор, память, НЖМД, Модель, цена
щие для ПК монитор
2 Географические Страна, река, озеро, гора Название, континент
объекты
3 Сотрудники Руководитель верхнего уров- Ф.И.О., возраст,
ня, менеджер, штатный должность
исполнитель, совместитель
4 Канцелярские Карандаш, скоросшиватель, Фирма-
товары тетрадь, органайзер производитель, цена
5 Графические Линия, треугольник, Название,
фигуры прямоугольник, окружность длина контура
6 Микросхемы Регистр, счетчик, дешифратор, Технология, серия
мультиплексор
7 Бытовые Телевизор, холодильник, сти- Марка, цена
приборы ральная машина, СВЧ-печь
8 Компьютерные Игра, ОС, СУБД, среда про- Название, объем
программы граммирования дистрибутива
9 Радио- Конденсатор, резистор, Марка, количество
электронные транзистор, диод в наличии
элементы
10 Автомобили Легковой, грузовой, тягач, Марка, изготовитель,
автобус мощность двигателя
11 Книги Учебник, справочник, Автор, название,
худ. литература, альбом объем
12 Небесные тела Планета, комета, звезда, Название
галактика
ТЕОРЕТИЧЕСКИЙ МАТЕРИАЛ
37
класса, а также средством подстройки класса к нуждам пользователя.
Подкласс (или производный класс) наследует все данные и методы ба-
зового класса. В дополнение к ним он может приобрести новые данные
и методы, не содержащиеся в базовом классе, но необходимые для кон-
кретных целей, преследуемых при создании подкласса. Каждый объект
производного класса содержит свои собственные копии данных, уна-
следованных от базового класса. Любой класс может стать базовым, ес-
ли создать новый класс, объявив его производным от первого.
class BaseClass
{ // Компоненты базового класса
};
class SubClass: public BaseClass
{ // Компоненты производного класса
};
Имя базового класса указывается непосредственно после имени
производного, до открывающей фигурной скобки. В данном случае
производный класс SubClass наследует все компоненты базового
BaseClass, а также содержит любые, определенные непосредственно в
нем самом, компоненты. В языке существует возможность управлять
атрибутами доступа унаследованных данных и методов. Ключевое
слово перед именем базового класса определяет тип наследования.
По умолчанию установлен тип наследования доступа private.
В производном классе можно изменять доступность отдельных
компонентов базового класса.
class BaseClass
{
public: // Общедоступные компоненты базового класса
int nPublBase;
void funcBase ();
protected: // Защищенные компоненты базового класса
int nProtBase;
private: // Частные компоненты базового класса
int nPrivBase;
};
38
class Subclass: BaseClass // private-наследование по умолчанию
{
public: // Общедоступные компоненты производного класса
BaseClass::nPublBase; // Конкретно объявляем как public
int nPublSub;
void funcSub();
} clSub;.
Из любого места программы становится возможным доступ к
этому компоненту базового класса:
clSub.nPublBase = 7;.
ПОЛИМОРФИЗМ И ВИРТУАЛЬНЫЕ ФУНКЦИИ
39
может связать послание объекту с конкретными кодами заранее, так
как он знает класс объекта, которому послано данное сообщение.
Раннее связывание дает преимущество в скорости, поскольку компи-
лятор имеет возможность оптимизировать код до его выполнения.
class Parent
{
public:
void print(){…}
} *pp,pobj;
class Derived: Parent
{
public:
void print(){…}
} *pd,dobj;
40
рр объявлен указателем на класс Parent, оператор pp->print(); вызовет
Parent::print(). Тот факт, что рр в данный момент времени содержит
адрес объекта производного класса, не влияет на решение, принятое
на этапе компиляции.
Позднее связывание реализуется с помощью виртуальных функ-
ций. Оно дает преимущество в гибкости и высоте абстракции задачи.
Виртуальная функция определяется в базовом классе с помощью спе-
цификатора virtual перед ее объявлением. Изменим объявление мето-
да print в предыдущем примере.
class Parent
{
public:
virtual void print(){…}
} *pp,pobj;
class Derived: Parent
{
public:
void print(){…}
} *pd,dobj;
pobj.print (); // Вызов метода Parent::print()
dobj.print(); // Вызов метода Derived::print()
рp=&pobj;
pp->print(); // Вызов метода Parent::print()
рd=&dobj;
pp=pd;
pp->print(); // Вызов метода Derived::print()
pd->print(); // Вызов метода Derived::print()
В этих условиях изменится функционирование только одного опе-
ратора pp->print. В игру вступает полиморфизм позднего связывания, и
выбор метода print производится на этапе исполнения программы в за-
висимости от того, на объект какого класса ссылается в данный момент
времени указатель Parent *pp. Если он ссылается на объект производно-
го класса, то будет вызван Derived::print(), если же указатель ссылается
на объект базового класса, то будет вызван Parent::print(). Такая гиб-
кость функционирования виртуальных функций является мощным
41
средством, позволяющим выбрать нужный метод при получении указа-
телем (на текущий объект одного из производных классов иерархии)
сообщения общего характера вида print(), input() и т. д.
Все методы классов могут быть виртуальными, за исключением
конструктора. Деструктор класса, однако, может быть объявлен вир-
туальным. Это позволяет вызвать требуемый деструктор с помощью
указателя на базовый класс. Если указатель в данный момент ссыла-
ется на объект одного из производных классов, то будет вызван де-
структор соответствующего класса. Деструктор класса, производного
от класса с virtual-деструктором, сам является virtual-деструктором
(так же, как и любая другая виртуальная функция).
При определении в производных классах виртуальных функций
количество и типы параметров у всех функций в разных классах
иерархии должны быть одинаковы. Только в этом случае они счита-
ются виртуальными.
Необходимо различать три варианта переопределения функций,
для которых в английском языке используются разные специальные
термины. Говорят, что переопределенная в производном классе вир-
туальная функция (overrides) преобладает (над) или заменяет одно-
именную функцию базового класса. Если в производном классе пере-
определена обычная функция, то говорят, что она скрывает (hides)
функцию из базового класса с таким же именем. Если в классе опре-
делены две функции с одинаковым именем, но разным набором па-
раметров, то говорят, что они совмещены или что вторая является пе-
регруженной (overloaded) версией первой функции.
В случае скрытия (hiding) количество и типы аргументов не вли-
яют на сам факт скрытия. Совмещение (overloading) функций с одним
именем, но различием в аргументах возможно только в рамках одного
класса и при одинаковом типе возвращаемого значения. Если объяв-
ленная виртуальной в базовом классе функция имеет в производном
классе другой тип или набор параметров, то она считается спрятан-
42
ной (hiden) и виртуальный механизм игнорируется. Если в произ-
водном классе она имеет другой тип возвращаемого значения, то это
рассматривается как ошибка.
МЕТОДИКА ВЫПОЛНЕНИЯ
СОДЕРЖАНИЕ ОТЧЕТА
КОНТРОЛЬНЫЕ ВОПРОСЫ
43
Лабораторная работа № 7
СЛОЖНЫЕ СТРУКТУРЫ ИЗ ОБЪЕКТОВ КЛАССОВ
ЗАДАНИЕ
ТЕОРЕТИЧЕСКИЙ МАТЕРИАЛ
44
ВЛОЖЕННОСТЬ КЛАССОВ
Поле данных класса может иметь любой тип, в том числе быть
объектом какого-либо класса или указателем на объект класса. Это
обстоятельство используется при разработке сложных структур дан-
ных, состоящих из различных классов. В целях экономии памяти бо-
лее предпочтительным является вариант работы с динамически со-
здаваемыми объектами, что предполагает использование указателей.
Существует специально зарезервированное ключевое слово this,
определяемое как указатель на объект, которому было послано обра-
батываемое сообщение. В каком-то конкретном методе указатель this
содержит адрес объекта, который инициировал этот метод. Это спра-
ведливо только для методов класса, не имеющих описатель static. При
любом вызове метода класса указатель this передается как скрытый
(hidden) параметр, то есть передается неявно. Он является локальной
переменной внутри метода и неявно используется при обращении к
данным и методам класса. Иногда его используют явно.
Рассмотрим эти возможности на примере инкапсуляции в классе
Node такой распространенной структуры данных, как узел линейного
односвязного списка. Класс Node имеет в качестве элемента данных
указатель next на объект своего собственного класса.
class Node {
char *data; // Информационная часть узла
Node *next; // Указатель на следующий узел
publiс:
Node (char *s) // Конструктор
{
data = strcpy(new char[strlen(s)+l], s);
next = NULL;
}
void GetData()
{
puts (this->data);
}
void SetNextTo (Node& n)
45
{
n.next = this;
}
Node* GetNext()
{
return next;
}
~Node ()
{
puts("\nDeleting data");
delete data;
}
};
void main ()
{ // Использование класса Node
Node n1(“First"), n2("Second");
n1.GetData();
n2.GetData();
n2.SetNextTo(n1);
n1.GetNext()->GetData();
}
Конструктор класса Node дважды вызывается в функции main при
объявлении объектов n1 и n2. Каждый раз он запрашивает память из
области heap и размещает там строку символов (содержимое узла спис-
ка), которая передастся конструктору в качестве параметра. Метод
класса GetData выводит в поток stdout (стандартный выходной поток)
поле data того объекта, которому передается сообщение. Здесь мы спе-
циально вставили выбор с помощью указателя (this->), чтобы проиллю-
стрировать то, что обычно делает компилятор. Его можно оставить, а
можно и убрать. Любое обращение к data в любом методе класса Node
компилятор расширяет до this->data. Оператор программы n1.GetData();
выведет строку "First", а оператор n2.GetData(); – строку "Second".
Внутри конструктора мы обращаемся к переменной data, не указывая
явно, какому объекту принадлежит это поле данных. Компилятор C++
сам расширяет это обращение до this->data. Метод SetNextTo получает
в качестве параметра ссылку на объект класса Node. Поскольку этот
46
метод принадлежит к тому же классу, что и параметр, внутренний ком-
понент next объекта n прямо доступен в данном методе. Ему присваи-
вается адрес объекта, который инициировал метод (n.next=this;). Адрес
содержится в переменной this. Так как в нашем случае объекту n2 по-
слано сообщение SetNextTo(n1), указатель this содержит адрес объекта
n2, и он присваивается полю next объекта nl. Получается, что объект n1
имеет в качестве следующего узла списка объект n2, или можно ска-
зать, что n2 зацеплен за n1.
Метод GetNext позволяет получить адрес следующего элемента
списка, то есть поле next объекта, которому послано сообщение. В
последней строке функции main он используется для того, чтобы до-
быть объект, стоящий в списке за объектом n1. Выражение
n1.GetNext() имеет результатом адрес объекта n2, которому посыла-
ется сообщение GetData. Следовательно, результатом всего выраже-
ния будет вывод поля data объекта n2, то есть строка "Second".
СЛОЖНЫЕ СТРУКТУРЫ ДАННЫХ
47
своит его значение переменной sItem. На применение операции вытал-
кивания из стека существует единственное ограничение: она не может
применяться к пустому стеку, т. е. к такому, который не содержит ни
одного элемента. Помимо этих двух основных операций, часто бывает
необходимо прочитать элемент в вершине стека, не извлекая его отту-
да. Для этих целей используют операцию peek(s).
Очередью называется упорядоченный набор элементов, которые
могут удаляться с одного ее конца (называемого началом очереди) и
помещаться в другой конец этого набора (называемого концом очере-
ди). Ее также называют структурой данных, организованной по прин-
ципу FIFO (First In First Out, первый вошел – первым вышел). Как и для
стека, максимальное число элементов в очереди не должно лимитиро-
ваться используемым программным обеспечением: память должна за-
прашиваться и освобождаться динамически по мере того, как в очередь
добавляются новые и из нее удаляются находящиеся там элементы.
Рассмотренные структуры – стек и очередь – являются специаль-
ными разновидностями более общей структуры данных – обобщен-
ного связанного списка. Приведенные ниже функции позволяют ра-
ботать со списком:
− insert – добавить новый элемент в список, сохраняя
установленный порядок следования.
− destroy – разрушить список.
− display – вывести все элементы списка.
− remove – удалить элемент списка.
Существует множество способов конкретной реализации списков.
В линейном однонаправленном списке поле next содержит адрес сле-
дующего элемента списка. Последний элемент в поле next хранит зна-
чение NULL. В линейном двунаправленном списке, кроме поля next,
имеется также поле prev, которое содержит адрес предыдущего элемен-
та списка. Поле prev первого элемента списка содержит NULL. В цик-
лическом однонаправленном списке поле next последнего элемента
содержит указатель назад на первый элемент. Такой список не имеет
первого и последнего элементов. Однако в некоторых случаях удобно
48
использовать внешний указатель на последний элемент, что автомати-
чески делает первым следующий за ним элемент. Альтернативный ва-
риант предполагает использование указателя на первый элемент. В
циклическом двунаправленном списке поле prev первого элемента
содержит указатель на его последний элемент, а поле next последнего
элемента – указатель на первый элемент.
Коллекция – это упорядоченный набор объектов, построенный на
базе динамического массива и записи, что позволяет, с одной стороны,
перенумеровать все элементы семейства, а с другой – иметь прямой до-
ступ к объектам – элементам семейства – по значению определенного
поля, называемого ключом. Ключ – это строковое выражение, которое
может быть использовано вместо индекса для доступа к элементу семей-
ства. Класс Collection имеет одно свойство Count и три метода – Add,
Item и Remove. Свойство Count возвращает количество элементов семей-
ства.
Метод Add (элемент [, ключ][, до] [, после]) добавляет объект в се-
мейство. Его обязательным аргументом является элемент, он указывает
добавляемый в семейство элемент. Параметр ключ задает ключ, по кото-
рому возможно будет произвести поиск этого элемента. Параметры до и
после указывают на то, перед каким или после какого элемента добавля-
ется новый. По умолчанию элемент добавляется в конец семейства.
Метод Remove (ключ) удаляет элемент из семейства. Параметр ключ
– это ключ или индекс, указывающие на удаляемый элемент. Заметьте,
что при удалении элемента из семейства не остается "дыр": индексы пе-
ренумеровываются, значение свойства Count уменьшается на единицу.
Метод Item (ключ) возвращает значение элемента семейства с
ключом ключ. Как в случае с методом Remove, параметр ключ может
быть как ключом, так и индексом.
Бинарное дерево – это конечное множество элементов, которое
либо пусто, либо содержит один элемент, называемый корнем дерева, а
остальные элементы множества делятся на два непересекающихся под-
множества, каждое из которых само является бинарным деревом. Эти
подмножества называются левым и правым поддеревьями исходного
49
дерева. Каждый элемент бинарного дерева называется узлом дерева.
Функции для работы с бинарными деревьями те же, что и для списка.
МЕТОДИКА ВЫПОЛНЕНИЯ
СОДЕРЖАНИЕ ОТЧЕТА
КОНТРОЛЬНЫЕ ВОПРОСЫ
50
5. Что такое бинарное дерево?
6. В чем состоит отличие линейного списка от циклического?
7. В чем разница между однонаправленными и двунаправленными списками?
8. С помощью каких классов и методов библиотеки классов потокового вво-
да/вывода организуется работа с текстовыми файлами?
51
Лабораторная работа № 8
РАЗРАБОТКА WINDOWS-ИНТЕРФЕЙСА ПРИЛОЖЕНИЯ
ЗАДАНИЕ
ТЕОРЕТИЧЕСКИЙ МАТЕРИАЛ
52
(пиктограммы), М – Mouse (мышь), Р – Pop-up (всплывающие или
выпадающие меню). Основными элементами графических интерфей-
сов, таким образом, являются: окна, пиктограммы, компоненты вво-
да-вывода и мышь, которую используют в качестве указующего
устройства и устройства прямого манипулирования объектами на
экране.
Окна. Окно – обычно прямоугольная, ограниченная рамкой об-
ласть физического экрана. Окно может менять размеры и местополо-
жение в пределах экрана. Все окна можно разделить на 5 категорий:
− основные окна (окна приложений);
− дочерние или подчиненные окна;
− окна диалога;
− информационные окна;
− окна меню.
Окно приложения Windows обычно содержит: рамку, ограни-
чивающую рабочую область окна, строку заголовка с кнопкой си-
стемного меню и кнопками выбора представления окна и выхода,
строку меню, пиктографическое меню (панель инструментов), гори-
зонтальные и вертикальные полосы прокрутки и строку состояния.
Дочернее окно Windows используют в многодокументных про-
граммных интерфейсах (MDI), предполагающих, что программное обес-
печение должно работать с несколькими документами одновременно. В
отличие от окна приложения дочернее окно не содержит меню. В строке
заголовка – специальное имя, идентифицирующее связанный с ним до-
кумент или файл. Пиктограммы всех дочерних окон одинаковы.
Диалоговое окно используют для просмотра и задания различных
режимов работы, необходимых параметров или другой информации.
Оно может содержать:
− строку заголовка с кнопкой системного меню;
− компоненты, обеспечивающие пользователю возможность
ввода или выбора ответа;
− вспомогательные компоненты, обеспечивающие подсказку,
например поле предварительного просмотра или кнопка вызова справки.
53
Как правило, размер диалогового окна не изменяется, но его
можно перемещать по экрану.
Информационные окна бывают двух типов: окна сообщений и
окна помощи. Окна сообщений, кроме заголовка с кнопкой системно-
го меню, обычно содержат текст сообщения и одну или несколько
кнопок реакции пользователя, например кнопки Yes и No или кнопки
Yes, No и Cancel.
Окно помощи имеет более сложную структуру: оно может содер-
жать меню, полосы прокрутки и информационную область, т. е. по
структуре оно аналогично окну приложения, но отличается от него
тем, что имеет узко специальное назначение, обеспечивая навигацию
по справочной информации.
Окна меню Windows можно использовать как открывающиеся
панели иерархического меню или как отдельные контекстные меню.
Каждой строке окна меню может соответствовать:
− команда;
− меню следующего уровня, что обозначается стрелкой;
− окно диалога, что обозначается тремя точками.
Кроме того, в некоторых строках добавляется указание клавиш
быстрого вызова.
Пиктограммы. Пиктограмма представляет собой небольшое ок-
но с графическим изображением, отражающим содержимое буфера, с
которым она связана. Различают:
− программные пиктограммы;
− пиктограммы дочерних окон;
− пиктограммы панели инструментов;
− пиктограммы объектов.
Программными пиктограммами, которые связаны с соответ-
ствующей программой, управляет операционная система. Так, можно
«свернуть» окно приложения в пиктограмму на панели задач Win-
dows или «развернуть» его обратно «на рабочий стол».
Аналогично многодокументная программная система управляет
пиктограммами дочерних окон, обеспечивающими доступ к различным
документам, одновременно обрабатываемым программной системой.
54
Пиктограммы панели инструментов обычно дублируют доступ к
соответствующим функциям через меню, обеспечивая их быстрый вызов.
Пиктограммы объектов используют для прямого манипулирова-
ния этими объектами.
Как правило, все пиктограммы можно перемещать мышью. Кро-
ме того, для облегчения работы с пиктограммами обычно используют
«всплывающие» подсказки, которые появляются, если пользователь в
течение некоторого времени удерживает мышь над пиктограммой
панели инструментов.
Прямое манипулирование изображением. Прямое манипулиро-
вание изображением – это возможность замены команды воздействия
на некоторый объект физическим действием в интерфейсе, осуществ-
ляемым с помощью мыши. При этом любая область экрана рассмат-
ривается как адресат, который может быть активизирован при подве-
дении курсора и нажатии клавиши мыши.
По реакции на воздействие различают следующие типы адресатов:
− указание и выбор (развертывание пиктограмм, определение
активного окна и т. п.);
− буксировка и «резиновая нить» (перенос объекта или его границ);
− экранные кнопки и «скользящие» барьеры (выполнение
дискретных или циклически повторяемых действий, например
выполнение некоторой операции или рисование, что подразумевается
при активизации определенной области экрана – кнопки).
Не последняя роль в графических интерфейсах отводится динами-
ческим визуальным сигналам, которые представляют собой изменение
изображения на экране. Основная цель этих сигналов заключается в
предоставлении пользователям дополнительной информации. Про-
стейшим примером такого сигнала является изменение изображения
курсора мыши при выполнении конкретных операций, например изоб-
ражение его в форме песочных часов во время обработки. Другой при-
мер – изменение изображения кнопки при нажатии на нее. Хотя в отли-
чие от анимационных интерфейсов прямого манипулирования эти ви-
зуальные сигналы играют в графических интерфейсах вспомогатель-
ную роль, обеспечивая более реалистическую картинку.
55
Компоненты ввода-вывода. Как уже упоминалось, в окнах при-
ложения могут размещаться специальные компоненты, используемые
для ввода-вывода информации. Интерфейс практически любого совре-
менного программного обеспечения включает несколько меню: основ-
ное или «ниспадающее» иерархическое меню, пиктографические меню
(панели инструментов) и контекстные меню для разных ситуаций. Лю-
бое из указанных меню представляет собой компонент ввода-вывода,
реализующий диалог с пользователем, используя табличную форму.
Иерархические меню используют, чтобы организовать выполня-
емые программным обеспечением операции, если их число превыша-
ет 5-8 (6 в соответствии с рекомендациями фирмы IBM), и обеспечить
пользователю их обзор. Панели инструментов и контекстные меню
применяют для обеспечения быстрого доступа к часто используемым
командам, тем самым пользователю предоставляется возможность
свободной навигации.
Кроме меню в интерфейсе используют и другие компоненты вво-
да-вывода, которые можно разделить на три группы в соответствии с
тем, какую форму диалога они реализуют: фразовую, табличную или
смешанную. Директивная форма диалога обычно предполагает ввод
комбинаций клавиш или перемещение пиктограмм, а потому не тре-
бует использования компонентов ввода-вывода.
МЕТОДИКА ВЫПОЛНЕНИЯ
56
5. Переопределите методы классов, выполняющие операции кон-
сольного ввода/вывода, с учетом использования элементов графи-
ческого интерфейса пользователя.
СОДЕРЖАНИЕ ОТЧЕТА
КОНТРОЛЬНЫЕ ВОПРОСЫ
БИБЛИОГРАФИЧЕСКИЙ СПИСОК
57
СОДЕРЖАНИЕ
Лабораторная работа № 1.
Простые программы с циклами и операторами консольного ввода/вывода ........ 3
Лабораторная работа № 2.
Работа с текстовыми файлами, структурами данных и меню ................................ 9
Лабораторная работа № 3.
Разработка и спецификация функций и модулей программы .............................. 17
Лабораторная работа № 4.
Разработка и спецификация структур данных, использование указателей
и динамических массивов структур ........................................................................ 23
Лабораторная работа № 5.
Использование объектно ориентированного программирования
в разработке приложений ......................................................................................... 29
Лабораторная работа № 6.
Использование наследования, полиморфизма и абстрактных классов ............... 36
Лабораторная работа № 7.
Сложные структуры из объектов классов............................................................... 44
Лабораторная работа № 8.
Разработка windows-интерфейса приложения ....................................................... 52
Библиографический список ...................................................................................... 57
58
Учебное издание
Отпечатано в типографии
Самарского государственного технического университета
443100, г. Самара, ул. Молодогвардейская, 244. Корпус № 8
59