Интегрированная среда MVS-2010
Поможем в ✍️ написании учебной работы
Поможем с курсовой, контрольной, дипломной, рефератом, отчетом по практике, научно-исследовательской и любой другой работой

Интегрированная среда MVS-2010

Неопределимые ошибки бесконечны, а определимые ограничены возможностями компилятора

Закон Мерфи

Цель работы – освоить основные возможности интегрированной среды Microsoft Visual Studio 2010 (далее ИС MVS-2010) по разработке и отладке типового консольного приложения на языке С++ (4 час.)

Задание. Проделайте следующее:

1. Прочитайте это задание и методические указания до конца, прежде чем терзать клавиатуру, соседа, преподавателя и пр. сущности

2. Запустите на выполнение ИС MVS-2010, ознакомьтесь с командами меню и инструментальными панелями.

3. Создайте консольное приложение и дайте ему благопристойное имя («Как яхту назовешь – так она и поплывет»).

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

5. Освойте использование команд компиляции, запуска и отладки приложения (F7, Ctrl+F7, F5, Ctrl+F5, Shift+F5, F10, F11 и пр.).

6. Научитесь вызывать контекстное меню Debug, выполнять трассировку программы, просматривать значения переменных во время отладки, устанавливать и снимать контрольные точки (breakpoint).

7. Научитесь использовать окна «Autos», «Locals» и «Watch» для просмотра значений переменных во время выполнения (трассировки) программы. Воспользуйтесь помощью (Help) и трассировкой для изучения назначения перечисленных окон.

8. Попробуйте сдать работу, предварительно тщательно протестировав ее на предмет отсутствия хомутов

Методические указания

Шаг 1. Создание заготовки приложения.

Запустите на выполнение ИС, с помощью команды FileèNewèProject вызовите мастера ИС, выберите шаблон Win32 Console Application (рис. 1), в свойствах проекта Application Settings выберите, для простоты, поддержку  MFC (рис. 2). В этом сценарии я присвоил проекту очень оригинальное имя Lab1. При создании проекта не устанавливайте (или снимите, если он установлен по умолчанию), переключатель Create directory for solutions (см. рис. 1).

Если при выборе каркаса приложения вы ошиблись, то надо выйти из ИС, удалить папку с проектом и начать жизнь с начала.

Совет. В условиях работы в сети рекомендую выбрать локальный диск компьютера, а не сетевой, для ускорения работы, отсутствия проблем согласования времени локального компьютера и сетевого, уменьшения вероятности потери проекта из-за возможных сбоев сети. На локальном компьютере рекомендую выбирать каталог, имя которого и путь к нему не содержат символов кириллицы, например, C:\Temp. Самое плохое место для работы над проектом – флешка. Сохраняйте проект на флешке только тогда, когда вы закончили работу с ним, например, в конце лабораторной работы.

 

Рис. 1. Выбор каркаса консольного приложения – начало

 

 

 

Рис. 2. Выбор каркаса консольного приложения – продолжение

Перечень файлов проекта

Файл Содержимое
Lab1.vcproj файл проекта формата XML, содержащий сведения о версии ИС, программной платформе приложения, настройках проекта и пр.
Lab1.ncb база данных интеллектуального средства Class View
ReadMe.txt содержит текстовое описание проекта и входящих в него файлов
stdafx.h, stdafx.cpp эти файлы используются для построения предкомпилированных заголовочных файлов (.pch - precompiled header files)
Resource.h стандартный заголовочный файл, содержащий определения идентификаторов ресурсов приложения
Lab1.rc содержит листинг всех ресурсов, включая заголовок окна приложения, иконки и курсоры, которые сохраняются в подкаталоге RES. Может напрямую редактироваться в ИС
Lab1.h заголовочный файл приложения
Lab1.sln описывает так называемое решение (solution), которое в общем случае может включать несколько проектов, предназначенных для решения определенной задачи
Lab1.suo скрытый двоичный файл, содержащий пользовательские настройки решения (Solution User Options)
Lab1.vcproj.NEW.Виктор.user файл формата XML, содержащий описания конфигураций (debug, release) решения. NEW – имя компьютера, Виктор – имя пользователя
Lab1.cpp основной файл проекта, содержащий функцию main() и программный код, добавленный программистом

 

Из всех перечисленных в табл.1 типов файлов непосредственно редактируются файлы с исходными текстами программы .cpp и заголовочные файлы .h. Остальные файлы, за исключением файла .rc, не редактируются в ИС напрямую и их не стоит модифицировать с помощью внешних редакторов.

При компиляции и сборке приложения создается каталог Debug или Release, в зависимости от выбранной конфигурации (Debug или Release), в которых размещается исполняемый файл приложения (.ехе), объектные файлы (.obj), предкомпилированные заголовочные файлы (.pch) и некоторые другие вспомогательные файлы. Для работы приложения необходим только ехе-файл, а остальные можно удалять (из каталогов Debug и Release только!) при необходимости сокращения объема памяти, занимаемого проектом. Также для сокращения объема памяти, занимаемой проектом, можно удалить файл .sdf. Простым и удобным способом удаления необязательных файлов, в том числе ехе-файла, является использование команды меню Build ÞClean Solution. Эта команда бывает также полезна при необходимости повторной компиляции и сборки приложения в случае какой-либо непонятной ошибки.

Рекомендую просмотреть не двоичные файлы проекта с помощью какого-либо внешнего редактора, например, с помощью файлового менеджера Far, Total Commander или блокнота.

 

Шаг 6. Прежде чем двигаться дальше, давайте посмотрим на наиболее часто используемые команды меню Build.

Таблица 2

Основные команды меню Build

Команда Назначение
Build Solution F7 Компилирует и собирает все проекты решения, обрабатывая все файлы, которые были изменены со времени последней сборки. После сборки программа может быть запущена на выполнение, если во время сборки не было фатальных ошибок
Rebuild Solution Ctrl+Alt+F7 Делает то же, что и команда Build, но при этом обрабатываются все файлы всех проектов, даже те, которые не были изменены со времени последней сборки. Команда полезна для того случая, когда имеются какие-либо проблемы со временем модификации файлов или есть другие причины для того, чтобы выполнить повторную полную сборку проекта
Clean Solution Удаляет все временные и промежуточные файлы, создаваемые компилятором и компоновщиком. Полезно использовать в тех случаях, когда есть какие-либо проблемы с повторной компиляцией и сборкой решения или проекта. После выполнения этой команды надо повторно откомпилировать и собрать проект. Эту команду удобно также использовать перед тем, как архивировать проект или сохранять на мобильном носителе вроде флешки, так как она сильно уменьшает размер проекта в байтах.
Compile Ctrl+F7 Компилирует выбранный (выбранные) файлы проекта
Configuration manager … Вызов окна для установки текущей активной конфигурации (Debug или Release) и программной платформы приложения

 

 

Основные команды меню Debug приведены в табл. 3. Перечень команд этого меню сильно зависит от текущего режима работы ИС: если приложение запущено и находится в режиме отладки, то набор доступных команд этого меню наиболее полный.

Таблица 3

Основные команды меню Debug

Команда Назначение
Windows Вызывает вспомогательное меню, с помощью которого, в свою очередь, можно вызывать окна вывода, просмотра значений наблюдаемых переменных (watch) и многое другое. Смотрите и изучайте. Как сказал один неглупый человек «Если Вы бог, то Вам отладчик не нужен. А нам, простым смертным, он необходим»
Break All Останавливает выполнение всех программ, выполняющихся под управлением отладчика, без их завершения. Полезно использовать для приостановки «вечных» или просто длительных по времени циклов
Continue F5 Продолжение выполнения программы в отладочном режиме, возможно, до завершения или до контрольной точки. Эта же команда, как вы уже знаете, используется для запуска приложения в отладочном режиме
Restart Ctrl+ Shift+ F5 Завершение текущей отладки и повторный старт программы в режиме отладки
Stop Debugging Shift+F5 Прекращение выполнения программы и выход из режима отладки. Именно ее лучше всего использовать для того, чтобы завершить работу программы в режиме отладки и заняться любимым делом – исправлением найденных «старых» ошибок и внесением новых
Step into F11 Трассировка «с заходом» в функции. Полезно использовать для анализа хода выполнения операторов вашей (библиотечной, ворованной, тыренной, украденной, похищенной, заимствованной, выполненной на заказ…) функции
Step over F10 Трассировка с выполнением функций за один шаг, т.е. функции выполняются, но отладчик в них не останавливается. Можно использовать для «обхода» библиотечных функций, которые в отличие от ваших собственных ошибок не содержат
Step out Shift+F11 Выполнение программы до выхода из текущей функции
Quick Watch Вызов окна для просмотра значений переменных и добавления их в окно Watch (понаблюдайте внимательно за работой этой команды)
Toggle breakpoint F9 Установить или удалить контрольную точку

 

Из других команд отладки часто используют Run to Cursor Ctrl+F10 – выполнить программу до оператора, на который указывает курсор. При запуске программы в режиме отладки на панели инструментов ИС появляется панель кнопок, дублирующих указанные в табл. 3 команды. Эту панель можно вызвать командой View è Toolbars è Debug.

Когда программа запущена на выполнение в режиме отладки (командами F10, F11 или F5 с установленной точкой прерывания breakpoint), то в окне Output появятся вкладки Autos, Locals, Watch и другие.

Во вкладке Autos отображаются значения переменных, видимых в текущей строке программы и в предыдущей.

Во вкладке Locals отображаются значения локальных переменных текущей функции.

Во вкладке Watch можно добавить для просмотра значения переменных и/или выражений.

 

 

Void Р rintBinary(int х )

{

int Bit=128;

for (int i=0;i<8;i++,Bit>>=1)

if (( х & В it)!=0) c о ut<<1; else cout<<0;

cout<<endl;

}

Void m а in()

{

setloc а le(LC_ALL,"rus");

int a,b,res;

cout<<"Введи два целых числа из диапазона 0..255>";

cin>> а >>b;

Print В inar у (a);

cout<<" +"<<endl;

PrintBinary(b);

res=a+b;

с out<<" v"<< е ndl;

PrintBin а ry(r е s);

_gеtсh(); // ожидает нажатия любой клавиши

}

 

Настоятельно рекомендую не копипастить этот текст, а набрать его пальчиками из соображений усвояемости и экономии времени. Разберите алгоритм этой программы «по косточкам».

 

Шаг 9. Наконец-то самостоятельная работа!

Доработайте программу таким образом, чтобы она выполняла над данными те операции, которые выпали вам по жребию. Ваш вариант задания приведен в таблице 4: номер варианта – это номер бригады.

Таблица 4

00000100

+

00001100

v

00010000

Введи два целых числа из диапазона 0..255 для умножения>3 27

00000011

*

00011011

v

00011110

Шаг 10. Использование отладчика.

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

 

 

Рис. 5. Меню Tools èOptions, с помощью которого, в частности, можно включить

                          нумерацию строк исходных текстов программы

Шаг 11 – последний, точнее, крайний? Примеры контрольных коварных вопросов преподавателя:

1. Выполните программу до указанного перстом преподавателя оператора.

2. Продемонстрируйте применение трассировки с «заходом» в функции и без оного и объясните разницу между ними

3. Поставьте в программе контрольную точку (breakpoint) и выполните программу до нее.

4. Прервите процесс отладки программы с помощью команды меню или с помощью «горячей» клавиши.

5. Покажите в справочной системе место, где описано назначение окон Watch, Autos и Locals.

6. Покажите, как вызываются окна Watch, Autos и Locals.

7. Покажите, как просматривать значения переменных и выражений с помощью окон Watch, Autos и Locals.

8. В чем отличия между окнами Watch, Autos и Locals?

9. Объясните правила выполнения той или иной операции, в частности, битовых операций:  << >> & ^ | и др.



Методические указания

Int GetNum()

{

int N;

cout<<"Введи фактическое число элементов массива>";

cin>>N;

return N;

}

int GetNum(char * Prompt)

{

int N;

cout<<Prompt;

cin>>N;

return N;

}

 

Выполните анализ качества программного кода, предназначенного для ввода целого числа. Ясное дело, что ни одна из приведенных функций не является идеальной. Недостатки реализации:

ü нет проверки вводимого числа на предмет его вхождения в требуемый диапазон и повторения запроса на ввод в случае ввода некорректного значения;

ü нет проверки корректности соблюдения формата ввода. Например, не контролируется ввод недопустимых символов. Проверьте, что будет, если вместо числа ввести букву(ы). Для этой цели лучше всего было бы использовать механизм обработки ИС (мы этого еще не изучали!);

ü две первые реализации функции «заточены» только на запрос ввода числа элементов массива и их нельзя использовать для запроса, например, числа ног или зубов;

ü ни одна из функций не предлагает некоторого «значения по умолчанию», благодаря чему пользователь мог бы просто нажать Enter вместо ввода очевидного значения.

 

Следующая функция генерирует целое псевдослучайное число из заданного диапазона:

Постановка задачи

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

Таблица 1

Клиенты брачного агентства

Имя Пол Рост Возраст Характер Цвет кожи Доход Число разводов
Джон м 150 20 Пакостный Белый 198 0
Барбара ж 178 23 Зловредный Черный 567 5
Майкл м 165 45 Нежный Желтый 987 2
Инесса ж 189 43 Отвратительный Белый 3544 5
Стивен м 201 21 Хороший Желтый 1234 4
Деннис м 172 18 Ласковый Черный 987 3
Смит м 168 19 Твердый Черный 7463 1
Джоан ж 153 33 Пакостный Белый 873 2
Джейла ж 178 44 Зловредный Желтый 368 2
Рейчел ж 178 23 Зловредный Черный 567 7
Лайла ж 153 33 Пакостный Коричневый 873 3
Тильда ж 166 43 Отвратительный Белый 3454 7
Льюис м 168 23 Твердый Белый 463 5
Керол ж 165 32 Нежный Желтый 876 4
Гликерия ж 198 44 Пакостный Белый 2340 5
Пафнутий м 178 25 Отвратительный Белый 567 2
Зазноба ж 189 43 Пакостный Желтый 999 0
Отморозок м 187 25 Отвратительный Черный 657 2

 

Характеры клиентов разбиты на категории в соответствии с табл. 2 для того, чтобы можно было не только указывать в запросах конкретный характер, но и делать более общие запросы путем указания категории характера, в том числе и в числовой форме. Подобным образом введены категории клиентов по величине доходов и цвету кожи (см. табл.3 и табл.4).

Таблица 2

Таблица 3

Таблица 4

Задание

1. Внимательно изучите листинги файлов проекта MAgency, которые приведены ниже. Каркас приложения – консольное приложение с поддержкой MFC.

2. Наберите текст приведенной программы или разработайте свой вариант. Файл с исходными данными вы можете создать элементарно путем копирования содержимого табл.1 в блокнот или в другой текстовый редактор, в том числе и в редактор MVS. Приветствуется увеличение объема табл.1 в любых направлениях: как увеличение числа строк, так и увеличение числа столбцов. Категорически возбраняется уменьшать размеры таблицы. Таблицы 2-4, как вы понимаете, предназначены для другой цели, а именно для формулировки запросов к программе и реализации алгоритмов удовлетворения запросов придирчивых клиентов.

3. Разработайте свое приложение в соответствии с вариантом, ниспосланным вам судьбой. Приложение должно выводить результат в понятной даже клиенту-дебилу форме, т.е. со всеми необходимыми сопроводительными и поясняющими текстами.

4. Выполните отладку приложения и сдайте его преподавателю, предварительно тестировав его на ввод корректных и не очень данных.

 

Таблица 5

Варианты заданий

№ комп. Задание
1 Найти все имеющиеся пары клиентов противоположного пола, имена которых начинаются с одинаковых символов и чей совокупный доход не меньше заданного пользователем значения
2 Найти пару клиентов противоположного пола, совокупный доход которых максимален и у них одинаковая категория характера
3 Найти все имеющиеся пары клиентов противоположного пола, которые имеют характер одной и той же категории
4 Найти пару клиентов одного пола, совокупный доход которых максимален и которые относятся к одной и той же категории цвета кожи. Поиск выполнять отдельно для клиентов обоих полов; сие значит, что вы обязаны найти двух особей мужеского рода и двух особей – женского.
5 Найти все имеющиеся пары клиентов одного пола, которые имеют характер одной и той же категории. Поиск выполнять отдельно для клиентов обоих полов.
6 Найти пару разнополых клиентов с диаметрально противоположными категориями характера, но с одинаковой категорией цвета кожи.
7 Сформировать пару из разнополых клиентов с заданными для каждого из них доходами (в числовой форме) при условии, что клиенты имеют одинаковую (заданную) категорию характера
8 Заданному (по имени) клиенту подобрать всех подходящих клиентов противоположного пола, вес которых и рост находится в заданных в процентном отношении пределах относительно его собственных. Разжевываю: ежели, например, рост клиента равен 150см и задан процент 20, то рост подходящих клиентов должен находиться в диапазоне 120..180см.
9 Найти две пары клиентов противоположного пола, которые имеют диаметрально противоположный рост, т.е. «самый высокий мужчина + самая невысокая женщина» и «самый короткий мужчина + самая высокая женщина»
10 Сформировать все возможные пары противоположного пола с одинаковой категорией цвета кожи и одинаковым числом разводов
11 Найти пару противоположного пола, у которых минимальное число разводов и одинаковая категория характера
12 Сформировать все возможные пары из разнополых клиентов с заданными для каждого из них доходами (в числовой форме в виде интервала) при условии, что клиенты имеют одинаковое число разводов

Листинг файла MAgency . cpp (с главной функцией)

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

 

 

 

 




Листинг файла Lib . h

 

 


Листинг файла Lib . cpp

 

 

 

 

 

 

 









Задача «куча камней»

Любая найденная в программе ошибка – не последняя

 Закон Мерфи

 

Цель работы – попробовать реализовать свой алгоритм решения известной «задачи о камнях» как пример оптимизационной задачи (4 час.).

 

Постановка задачи.

Из Википедии: Полный перебор (или метод «грубой силы», англ. brute force ) относится к классу методов поиска решения исчерпыванием всевозможных вариантов. Сложность полного перебора зависит от количества всех возможных решений задачи. Если пространство решений очень велико, то полный перебор может не дать результатов в течение нескольких лет или даже столетий. (Другими словами, если вы хотите получать зарплату еще при жизни, то, возможно, вам следует поискать более «быстрое» решение?)

Возьмем в качестве иллюстрации известную «олимпиадную» задачу о куче камней, которая заключается в следующем. Имеется произвольное число камней N>1, вес каждого из которых известен и равен Wi, i=1..N, причем  0<Wi <100000, N и W – целые числа. Требуется распределить камни на две кучи таким образом, чтобы разность весов этих двух куч была минимальной. Например, пусть есть N=5 камней с весами: 5, 8, 13, 27, 14. Очевидно, что в одну кучу надо поместить камни 5 и 27 (вес 32), а в другую – 8, 13 и 14 (вес 35). Тогда разность весов будет минимальна и равна 3 (по абсолютной величине).

Надо написать (точнее, разработать) алгоритм и программу, которая бы решала поставленную задачу. Учтите, что программа должна запросить у пользователя N и Wi , или, еще лучше, сгенерировать их как псевдослучайные числа из заданного диапазона.

 

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

Оживите интерфейс своего приложения с помощью класса CConsole (файлы Console.h, Console.cpp в каталоге Labprakt\OP\), информацию о котором можно найти в сценарии л.р. «Рамка» (файл Labprakt\OP\OP_Lab_16_17.doc).

 

Методические указания.

Шаг 1. Генерация каркаса приложения.

С помощью мастера ИС MVS создайте консольное приложение и включите в него поддержку библиотеки MFC (как и в предыдущих работах). В приведенных ниже листингах предполагается, что проекту присвоено имя StonesHeap, но вы вправе присвоить ему другое имя, например, Lab4, и тогда в вашем проекте у вас будет имя Lab4 там, где в приведенных листингах присутствует идентификатор StonesHeap.

Шаг 2. Добавление заголовочных файлов.

В начало файла StonesHeap.cpp (а у вас будет, возможно, имя файла Lab4.cpp), содержащего функцию _tmain(), добавьте директивы include для подключения необходимых заголовочных файлов (добавления выделены курсивом):

 

Заголовочный файл Limits.h содержит, в частности, предельные значения для интегральных типов данных и их рекомендуется использовать вместо непосредственно заданных «своих» констант.

Шаг 3. Примитивнейшая версия программы.

Автор этой работы не смог придумать более совершенную программу, чем в приведенном ниже листинге. Помимо отсутствия достоинств, главными ее недостатками являются:

ü возможность нахождения решения задачи только для такого случая, когда исходную кучу достаточно разбить на две такие, одна из которых содержит всего один камень, а в другой, соответственно, находятся все остальные;

ü в программе не предусмотрен ввод числа камней в куче и их весов, так как автору было лень в процессе отладки программы всякий раз их вводить;

ü в программе использовано так называемое «магическое» число 5, что в процессе дальнейшего развития программы сулит неприятности. Очевидно, что максимально возможное число камней в куче (20) лучше бы сделать константой. Если вы по натуре человек бесстрашный, то можете вместо 20 использовать 200, 2000, 20000 и т.д;

ü программу надо повторно запускать для того, чтобы решать задачу с другими исходными данными, что, конечно, неудобно, т.е. «по-дебильному».

 

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

 

 

Русифицировать (консольное) приложение можно и путем вызова функции setlocale(LC_ALL,"rus");, которая, упрощенно говоря, устанавливает русский язык в качестве языка ввода/вывода. Эту функцию достаточно вызвать один раз при запуске программы на выполнение – проще всего в начале функции main().

Шаг 4. Вперед на мины! Для проверки корректности алгоритма и собственно программы рекомендуется заранее придумать несколько тестов с известными решениями. В частности, некоторые тестовые задания приведены в этой табл..

Таблица

Некоторые примеры разделения камней на две кучи, которые должна решать ваша программа

Камни Решение
7 10, 20, 30, 15, 25, 35, 15 10+30+35  =75  20+15+25+15=75
7 1, 5, 11, 16, 18, 21, 21 5+21+21   =47 1+11+16+18=46
6 1, 4, 5, 6, 7, 9 1+4+5+6 = 16 7+9     = 16
5 4, 4, 5, 6, 7 4+4+5 =13 6+7 =13
5 6, 1, 1, 1, 1 6         =6 1+1+1+1 =4

 

 



Разработка простого класса

Чтобы получить реальное время разработки программы, надо прогнозируемое время увеличить вдвое и перейти к следующей единице измерения времени. Например, если вы помышляете написать программу за 2 часа, то вы ее будете писать 4 дня

Закон Мерфи

 

Цель работы – освоить программирование и применение простого класса, включающего конструктор, деструктор, член-данные и член-функции (4 час.).

 

Задание

1. Создайте консольное приложение с поддержкой MFC.

2. Добавьте в проект новый класс.

3. Спроектируйте собственный класс в соответствии с вашим вариантом задания, добавьте в заголовочный файл описание тела класса, а в файл реализации – реализацию его конструктора, деструктора и член-функций.

4. Во всех заданиях дату определить как структуру, включающую день, месяц и год в формате целых чисел.

5. Все член-данные классов должны быть объявлены в секции с ключом доступа protected и для чтения и записи их значений надо написать соответствующие функции, называемые иногда аксессорами (от англ. accessor – средство доступа). Функции записи значений член-данных должны проверять их корректность и, как правило, возвращать значение булевского типа, указывающее на наличие ошибки. Ясное дело, что эти функции должны быть объявлены в секции public.

6. Значения член-данных строкового типа должны сохраняться в указателях char *. Выделение памяти для указателей должно выполняться в конструкторе или в методах класса, предназначенных для записи значений член-данных. Освобождение памяти надо выполнять в деструкторе класса.

7. Во всех вариантах заданий предполагается создание и обработка массива объектов. Значения член-данных объектов необходимо загружать из предварительного созданного текстового файла, иначе отладку программы при жизни завершить не удастся.

8. «По умолчанию» предполагается, что пользователь должен иметь возможность просмотреть (вывести на экран) значения всех объектов в форме таблицы как до их модификации, так и после.

5.2. Описание вариантов заданий

Таблица 2.1.

Варианты заданий

№ вар. Задание
1 Класс Студент с член-данными: фамилия, номер зачетки, массив из 5 отметок, средний балл. Разработать метод вычисления среднего балла по массиву объектов. Сортировка студентов в порядке убывания среднего балла.
2 Класс Клиент банка с член-данными: фамилия, имя, № счета, сумма вклада, дата внесения депозита. Реализовать метод пересчета суммы вклада по заданной ставке годовых (например, 15%) в зависимости от срока хранения вклада (текущей даты).
3 Класс Автовладельцы с член-данными: марка авто, номер, цвет авто, фамилия и адрес владельца. Реализовать поиск владельцев авто с заданной маркой, цветом и номером, который заканчивается на две заданные цифры.
4 Класс Мотовладельцы с член-данными: марка мотоцикла, номер, цвет, фамилия и адрес владельца, отметка о техосмотре и дата его прохождения. Вывести информацию о владельцах тех мотоциклов, которые проходили техосмотр до заданной даты.
5 Класс Книголюб с член-данными: автор книги, название, издательство, год издания, число страниц. Найти книги заданного автора, изданные после заданного года и имеющие число страниц не более заданного.
6 Класс Рабочий с член-данными: фамилия, величина почасовой оплаты, дата последней выплаты зарплаты. Разработать функцию вычисления суммы заработка, причитающегося работнику. Заработок начислять за целое число недель, прошедшее с момента последней выплаты зарплаты до заданной даты. Считать, что число отработанных часов в неделе равно 40.
7 Класс Погода с член-данными: дата, средние температура (градусы) и скорость ветра (м/сек), величина осадков (мм), балл жесткости. Разработать метод вычисления балла жесткости по такому правилу: если температура ниже нуля, то балл жесткости равен температуре плюс удвоенная скорость ветра; в противном случае балл жесткости принимать равным нулю. Отсортировать объекты в порядке убывания баллов жесткости.
8 Класс Товары с член-данными: название товара, код товара, цена одной единицы товара, количество единиц товара. Разработать метод вычисления суммарной стоимости товаров (одного объекта). Найти объекты с максимальной и минимальной стоимостью товаров.
9 Класс Файл с член-данными: имя файла, тип файла, размер в байтах, дата создания, число кластеров, необходимое для хранения файла на диске. Разработать метод вычисления числа кластеров, приняв размер кластера равным 4096 байт. Если размер файла равен, например, 4097 байт, то для его хранения потребуется 2 кластера и в этом случае 4095 байт на диске не используются. Отсортировать файлы в порядке убывания такой «неиспользуемой» памяти.
10 Класс Преступник с член-данными: фамилия, рост, ширина и высота головы, длина руки, расстояние между глазами. Разработать метод вычисления близости заданных параметров подозреваемого к преступнику как сумма процентов отклонения физических параметров. По заданным физическим параметрам подозреваемого найти в базе наиболее близкого по параметрам преступника.
11 Класс Заготовки с член-данными: материал, номер, длина, высота. Заготовка прямоугольной формы, причем длина всегда не меньше высоты. Разработать метод, который получает в качестве параметров материал, длину и высоту детали и возвращает процент остатка площади материала, если деталь можно выкроить из данной заготовки. Метод должен вернуть отрицательное значение, если деталь выкроить не удается или если материал детали не совпадает с материалом заготовки.
12 Класс Абонент библиотеки с член-данными: фамилия, номер читательского билета, дата получения книги, число дней, на которое выдана книга. Разработать метод, который по заданной дате вычисляет «задолженность» (число дней) по несвоевременному возврату книги. Найти всех должников и их степень задолженности.
13 Класс Событие с член-данными: описание события, дата, время напоминания. Описание события – строка символов, например, «день рождения мамы». Время напоминания задается в часах в виде двух чисел: начало и конец (от 0 до 24). Написать метод, который получает в качестве параметров заданную дату и время суток (в часах) и возвращает значение true, если надо напоминать о событии. По заданной дате и времени суток проанализировать все объекты и вывести соответствующие напоминания
14 А здеся могет быть ваш варьянт

 

Во всех заданиях дату определить как структуру, включающую день, месяц и год в целочисленном формате.


 


Класс вектор

Приходит студент-программист на занятия с утра злой. Однокурсники его спрашивают:

 - Ты чего такой злой?

 - Да программу вчера всю ночь набивал.

 - И что, не заработала?

 - Да нет, заработала.

 - Может, неправильно заработала?

 - Да нет, правильно.

 - А что тогда?

 - Да на Backspace уснул…           

 

Автор не известен, но можно ему посочувствовать

Цель работы – разработать собственный (конечно же, гениальный!) класс, предназначенный для обработки массивов чисел (4 час.)

Задание. Требуется разработать свой собственный класс, облегчающий работу с числовыми массивами. Класс должен иметь, помимо конструктора (ов) и деструктора, перечисленные в табл. 1 методы.

Таблица 1

Методы класса

Метод Назначение
Size Возвращает фактическое число элементов массива
Capacity Возвращает число элементов массива, для которых зарезервирована память
SetCapacity Позволяет задать число элементов массива, для которых должна быть зарезервирована память
SetElem Задать значение элемента массива с заданным индексом
GetElem Получить значение элемента массива с заданным индексом
InsertElem Вставить в заданную позицию новый элемент массива
DeleteElem Удалить элемент массива с заданным индексом
AddElem Добавить новый элемент в конец массива

Методы для самостоятельной разработки

InsertVec Вставить в заданную позицию данного массива другой массив
DeleteVec Удалить заданное число элементов массива, начиная с элемента с заданным индексом
AddVec Добавить новый массив в конец данного массива
SortVec Отсортировать массив в заданном порядке (по возрастанию или убыванию)

 

Класс должен быть реализован таким образом, чтобы тип его элементов можно было изменить или задать наиболее безболезненным способом. Методы класса должны быть оптимизированы по времени. Это, в частности, значит, что вставка или удаление нескольких элементов массива (методы InsertVec() и DeleteVec()) не должна быть сведена к многократному вызову методов вставки и удаления одного элемента массива.

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

Методические указания. При реализации класса можно воспользоваться примером класса TVector, приведенном в конспекте лекций и ниже.

Для отслеживания вызовов конструкторов и деструкторов класса рекомендуется поместить в них макросы TRACE, которые будут выводить в окно Debug соответствующие сообщения. Можно, естественно, поместить эти макросы и в другие функции класса.

Пример класса TVector

 

Этот пример реализован в проекте Vector (консольное приложение с поддержкой MFC). Содержимое заголовочного файла TVector.h (директивы препроцессора и компилятора опущены):

Содержимое файла реализации TVector.cpp (директивы препроцессора и компилятора опущены):

 

Тестирование класса:

 

Наследование классов

Если мысль не приходит в голову, она не приходит никуда

Виктор Шендерович

 

Цель работы – освоить разработку и использование классов-наследников для создания объектно-ориентированных программ (4 час.).

Задание

Разработайте базовый класс в соответствии с вашим вариантом задания, снабдите его конструктором с параметрами. Член-данные базового класса должны быть объявлены со спецификатором доступа protected. Для доступа к данным этого класса разработайте соответствующие функции чтения и записи их значений. Производный класс объявите со спецификатором доступа public:

class CBase {/**/};

class CChild : public CBase {/**/};

 

Разработайте производный класс в соответствии с вариантом задания. Снабдите его конструктором с параметрами, предназначенным для инициализации как член-данных базового класса, так и член-данных производного класса. В конструкторе производного класса вызовите конструктор базового класса.

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

Базовый и производный классы должны быть размещены в отдельных файлах (.h и .cpp).

В каждом варианте необходимо предусмотреть сохранение член-данных объектов в файле и чтение сохраненных данных из файла и присваивание их значений соответствующим член-данным объектам производного класса.

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

Методическая помощь

Очевидно, что в программе вам понадобится описать массив объектов класса и работать с ним. Допустим, вы сделали такие описания:

Варианты заданий

№ вар. Задание
1 Базовый класс КОМНАТА с член-данными ширина, длина и высота. Производный класс ОДНОКОМНАТНАЯ КВАРТИРА с комнатой, кухней ФИО владельца и номером квартиры. Для кухни задать площадь. 
2 Базовый класс ЛЕТАТЕЛЬНЫЙ АППАРАТ с член-данными вес, максимальные высота и скорости (горизонтальная и вертикальная) полета. Производный класс ПАССАЖИРСКИЙ САМОЛЕТ с член-данными марка, число пассажиров, дальность полета, количество салонов.
3 Базовый класс ДВИГАТЕЛЬ с член-данными тип двигателя (дизельный, бензиновый, электрический, комбинированный), фирма-производитель, объем и мощность двигателя. Производный класс ЛЕГКОВОЙ АВТОМОБИЛЬ с член-данными марка, число мест, максимальная скорость.
4 Базовый класс МАССИВ с член-данными вещественный массив и число его элементов. Массив описать как имеющий конкретное число элементов, заданное с помощью перечисления enum. Производный класс СТЕК с член-данным число элементов в стеке. Методы производного класса должны позволять помещать данные в стек, извлекать их, проверять наличие в стеке свободной памяти.
5 Базовый класс ЖИДКОСТЬ с член-данными название, удельный вес и условная вязкость. Производный класс БЕЗАЛКОГОЛЬНЫЙ НАПИТОК с член-данными цвет, вкус (горький, сладкий, кислый и т.д.), объем расфасовки и цена. Примечание: Условная вязкость — величина, косвенно характеризующая гидравлическое сопротивление течению, измеряемая временем истечения заданного объёма жидкости через вертикальную трубку определённого диаметра. Измеряют в градусах Энглера (по имени немецкого химика К. О. Энглера), обозначают — °ВУ. Определяется отношением времени истечения 200 см3 испытываемой жидкости при данной температуре из специального вискозиметра ко времени истечения 200 см3 дистиллированной воды из того же прибора при 20 °С.
6 Базовый класс ЧЕЛОВЕК с член-данными вес, рост, раса. Производный класс ЖЕНЩИНА с член-данными имя, объем груди, талии и бедер.
7 Базовый класс ПРОЦЕССОР с член-данными марка, тактовая частота, объем кэш-памяти. Производный класс КОМПЬЮТЕР с член-данными марка, число процессоров, объем оперативной памяти.
8 Базовый класс РАМКА с член-данными координаты левого верхнего и правого нижнего угла, заголовок. Производный класс ОКНО с член-данными меню (строка символов) и число тем меню, наличие инструментальной панели и строки статуса.
9 Базовый класс ХОМО САПИЕНС с член-данными возраст и цвет волос. Производный класс СТУДЕНТ с член-данными ФИО, пол, специальность, курс обучения.
10 Базовый класс ВЕКТОР с член-данными указатель на целочисленный тип данных, его размер и фактическое число элементов. Предоставить метод заполнения элементов массива. Производный класс МАССИВ с член-данными максимальное, минимальное и среднее значения элементов вектора. Разработать метод производного класса, который должен выполнять сортировку элементов массива в заданном порядке.
11 Базовый класс АВТОМОБИЛЬ с член-данными марка, цвет, объем и мощность двигателя. Производный класс ГРУЗОВИК с член-данными длина и ширина кузова, грузоподъемность.
12 Базовый класс РАБОТНИК с член-данными ФИО, идентификационный код, возраст. Производный класс ИНЖЕНЕР с член-данными специальность, месячный оклад, место работы
13 Базовый класс ПЕЧАТНОЕ ИЗДАНИЕ с член-данными число страниц, язык издания, наличие иллюстраций. Производный класс УЧЕБНИК с член-данными название, область знаний, тираж, цена экземпляра.

 

Void BadFunc()

{

for(i=0; i<Max; i++) Mas[i]=0;

//...

}

//...

BadFunc ();

следует считать дебильным и он должен быть переписан примерно так

const int Max=100;

int i;

int Mas[Max];

bool GoodFunc( int Mas[], int NMax)

{

if(NMax<1) return false;

for(int i=0; i<NMax; i++) Mas[i]=0;

//...

}

//...

if(GoodFunc(SomeVec,N)) //...

//...

 

 



Приложение с окном вида

Плохо спроектированная программа требует в три раза больше времени, чем предполагалось; тщательно спроектированная - только в два раза

            Закон Мерфи

Цель работы – освоить разработку приложения с графическим интерфейсом, основанного на классе «вид» библиотеки MFC (4 час.).

Задание.

1. Внимательно изучите материал разделов «Каркас приложений MFC» и «Класс вид библиотеки MFC (версия MVS 2005)» в файле VC_Lect.doc. В данной части используемые нами свойства и возможности MVS 2010 практически ничем не отличаются от MVS 2005.

2. Разработайте приложение в соответствии с рекомендациями, приведенными в разделе «Класс вид библиотеки MFC (версия MVS 2005)». Тестируйте приложение, добейтесь его работоспособности.

3. Добавьте в разработанное приложение программный код, который будет читать из файла данные о положении и размерах нескольких геометрических фигур и изображать эти фигуры в окне вида. Для получения представления о том, как можно выводить графические изображения в Windows, проработайте раздел конспекта «Интерфейс графического устройства, цвет и шрифт».

4. Выполните отладку приложения, проанализируйте его работу при изменении размеров окна приложения.

 

Методические указания.

Шаг 5. Открытие и чтение файла.

Добавьте в функцию OnFileOpen() открытие файла и чтение из него данных. Вы можете использовать простой текстовый файл (как в работе «Обработка текстового файла») или программно (с помощью этой же или другой программы) создать двоичный файл и читать данные из него или, в конце концов, использовать ini-файл (см. подраздел конспекта «Использование ini-файла»), что полезно с точки зрения не такой уж и далекой перспективы выполнения ДЗ.

Шаг 7. Рисование фигур.

Код рисования проще всего разместить в функции CDRWView::OnDraw(), которая вызывается автоматически (это так называемая функция обратного вызова – callback function) всякий раз, когда изображение в окне должно быть обновлено, а именно при свертывании и развертывании окна, при изменении его размеров, при перекрытии окна другим окном и т.д. Если мы поместим код рисования фигур, данные для которых читаются из файла, в функцию OnDraw(), то возникнет такая проблема: функция OnDraw() вызывается каркасом приложения уже при первом отображении содержимого окна, т.е. еще до того, как мы прочтем файл и собственно получим данные. Как быть? Можно поступить так: ввести специальную переменную (член-данное) булевского типа, например, bool FirstRun, в конструкторе присвоить ей значение true и проверять это значение в функции OnDraw(). После того как будут прочитаны данные из файла, этой переменной нужно присвоить значение false и «заставить выполниться» функцию OnDraw(). Функцию OnDraw() вызывают на выполнение не явно, а косвенным образом, с помощью функции Invalidate (). С учетом сказанного функция CDRWView::OnFileOpen() может быть реализована так:

CDRWView::OnFileOpen()

{

  // ввод имени файла

  // чтение данных из файла

  Invalidate();

}

 

Каждая уважающая себя бригада должна выбрать оригинальный набор таких фигур, которых нет в приведенной реализации функции OnDraw(), и этот джентльменский набор должен включать не менее двух фигур (см. функции класса CDC в MSDN).

Варианты заданий

№ п/п Реализуемые функции
1,12 Draw3dRect, Arc
2,13 DrawEdge, ArcTo
3,13 DrawFrameControl, PolyBezierTo
4,14 DrawIcon (используйте функцию LoadIcon для загрузки одной из стандартных иконок), PolyDraw
5,15 FrameRect, Polyline
6,16 InvertRect (интересно наложить частично прямоугольник, указанный в качестве параметра функции InvertRect, на другую фигуру), ExtTextOut
7,17 Chord, PolylineTo
8,18 Pie, PolyPolyline
9,19 PolyPolygon, DrawText
10,20 RoundRect, PolyBezier
11,21 AngleArc, DrawTextEx

С помощью Draw3dRect, приложив совсем немного сообразительности, можно изобразить фигуру, представленную на рис.3.

 

Рисунок 3. Творческий подход к Draw3dRect




Задание

1. По конспекту лекций освежите в памяти абстрактные и виртуальные функции, а также абстрактные классы.

2. Ознакомьтесь с приведенными ниже методическими указаниями.

3. Создайте заготовку консольного приложения.

4. В соответствии с вашим вариантом задания разработайте иерархию классов, добавьте их в приложение. Базовый класс вашей иерархии должен содержать конструктор с параметрами и минимум одну абстрактную функцию; производные классы должны содержать реализацию абстрактной функции (функций) и конструкторы с параметрами.

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

 

Методические указания

В качестве иллюстрации разработаем иерархию классов (рис. 1) и поместим ее реализацию в файлы Base.h и Base.cpp (проект ACVF).

 

 

// Файл Base.h

#pragma once


Class CBase

{     

Public :

       virtual char * getName()=0;

};

Class CFirst: public CBase

{

       double *dFoo;

public:

virtual char * getName();

       CFirst();

       ~CFirst();

};

CFirst::CFirst()

{

dFoo=new double [100];

cout<<"CFirst::CFirst"<<endl;

}

CFirst::~CFirst()

{

cout<<"CFirst::~CFirst"<<endl;

delete [] dFoo;

}

CSecond::CSecond()

{

cout<<"CSecond::CSecond"<<endl;

iFoo=new int [100];

}

CSecond::~CSecond()

{

cout<<"CSecond::~CSecond"<<endl;

delete [] iFoo;

}

char * CFirst::getName()

{return "CFirst";}

char * CSecond::getName()

{return "CSecond";}

 

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

void PrintClassNam е1( CBas е * pb ) // параметр-указатель

{

с out << pb -> g е tNam е()<<е ndl ;

}

void PrintClassNam е2( CBas е & b ) // параметр-ссылка

{

с out << b . g е tNam е()<<е ndl ;

}

Варианты заданий

В каждом варианте предусмотреть ввод данных с клавиатуры (с подсказками) или чтение из файла. Вывод результатов также нужно оформить с подсказками.

Таблица 1.

Индивидуальные задания

Задание
1 Разработать абстрактный БАЗОВЫЙ класс с виртуальной функцией, вычисляющей площадь плоской фигуры. Разработать производные классы: ПРЯМОУГОЛЬНИК, КРУГ, ПРЯМОУГОЛЬНЫЙ ТРЕУГОЛЬНИК и ТРАПЕЦИЯ со своими функциями вычисления площади. Для справки: площадь трапеции равна S=(a+b)*h*0.5, а формулы площадей других фигур надо помнить наизусть
2 Разработать абстрактный БАЗОВЫЙ класс с виртуальной функцией, вычисляющей норму. Разработать производные классы: КОМПЛЕКСНОЕ ЧИСЛО (норма есть корень квадратный из суммы квадратов действительной и мнимой частей), ВЕКТОР (корень квадратный из суммы элементов) и МАТРИЦА (максимальное значение по модулю)
3 Разработать абстрактный класс КРИВАЯ с виртуальной функцией вычисления зависимости y(x). Разработать производные классы: ПРЯМАЯ (y=a*x+b), ЭЛЛИПС (x2/a2+y2/b2=1) и ГИПЕРБОЛА (x2/a2-y2/b2=1). В каждом производном классе реализовать виртуальную функцию y(x)
4 Разработать абстрактный БАЗОВЫЙ класс с виртуальной функцией вычисления суммы прогрессии. Разработать производные классы АРИФМЕТИЧЕСКАЯ ПРОГРЕССИЯ и ГЕОМЕТРИЧЕСКАЯ ПРОГРЕССИЯ. Каждый класс должен иметь два поля вещественного типа: первое – значение начального элемента прогрессии, второе – шаг для арифметической прогрессии и множитель – для геометрической. Определить функцию вычисления суммы с параметром n: число элементов прогрессии. Арифметическая прогрессия: ai=a0+i*h, sn=(n+1)*(a0+an)/2. Геометрическая прогрессия: ai=a0*hi, sn= (a0-an*h)/(1-h)
5 Разработать абстрактный базовый класс ФИГУРА с виртуальной функцией вычисления площади и периметра фигуры. Разработать производные классы ПАРАЛЛЕПИПЕД, СЕКТОР КРУГА и УСЕЧЕННЫЙ СЕКТОР КРУГА. Определить в производных классах функции вычисления площади и периметра перечисленных фигур
6 Разработать абстрактный базовый класс РАБОТНИК и производные классы РАБОТНИК С ПОЧАСОВОЙ ОПЛАТОЙ и СЛУЖАЩИЙ С ОКЛАДОМ. Определить в классах соответствующие компонентные данные. Определить виртуальные функции начисления зарплаты за указанный период времени
7 Разработать абстрактный базовый класс ТЕЛО с виртуальной функцией вычисления площади поверхности. Разработать производные классы ПРЯМОУГОЛЬНЫЙ ПАРАЛЛЕЛИПИПЕД, ТЕТРАЭДР и ШАР с функциями вычисления площади поверхности S. Площадь поверхности параллелепипеда S=2*(a*b+b*c+c*a), где a,b,c – ребра. Площадь поверхности шара S=4*π*r2. Площадь поверхности тетраэдра S=a2*√3, где а – длина ребра
8 Разработать абстрактный базовый класс ТЕЛО с виртуальной функцией вычисления объема тела. Разработать производные классы ПАРАЛЛЕЛИПИПЕД, ПИРАМИДА, ТЕТРАЭДР и ШАР с функциями вычисления объема V. Объем прямоугольного параллелепипеда V=a*b*c, правильной пирамиды V=a*b*h/3 (a,b – стороны прямоугольной основы, h – высота), тетраэдра V=12*a3*√2 (а – длина ребра), шара V=4*π*r3/3
9 Разработать абстрактный базовый класс МЛЕКОПИТАЮЩИЕ с виртуальной функцией описания конкретного объекта класса. Разработать производные классы ЖИВОТНОЕ и ЧЕЛОВЕК. Для класса ЖИВОТНОЕ определить производные классы ЛОШАДЬ и КОРОВА. Определить виртуальные функции, возвращающие описания человека, лошади и коровы
10 Разработать абстрактный базовый класс БАНКОВСКИЙ СЧЕТ с виртуальной функцией, возвращающей величину счета. В базовом классе определить величину счета и дату его открытия. Разработать производные классы ДЕПОЗИТ и КРЕДИТ, в которых необходимо определить величину процентной ставки и дату для начисления величины вклада или суммы долга. Для производных классов разработать виртуальные функции, которые должны вычислять сумму депозита или сумму платежа в зависимости от типа класса: ДЕПОЗИТ или КРЕДИТ. Если вы еще не пользовались кредитами или депозитами, то знайте, что проценты обычно задают в годовом исчислении. Это значит, например, что если процент по кредиту равен 35 и вы погашаете его через месяц, то банк вам начислит пеню, равную (сумма кредита)*0.35*30/365
11 Разработать абстрактный базовый класс МАССИВ с виртуальными абстрактными функциями, возвращающими сумму значений элементов массива, максимального и минимального значений. Разработать производные классы ВЕКТОР и МАТРИЦА. В этих классах определить функции формирования значений массивов по определенному закону, которые надо задать самостоятельно, а также определить реализацию функций, возвращающих сумму значений элементов массива, максимального и минимального значений
12 Разработать абстрактный базовый класс СТУДЕНТ с виртуальной функцией, возвращающей сумму дохода студента за указанное число месяцев. В базовом классе определить член-данное фамилия студента. Разработать производные классы СТИПЕНДИАТ и КОНКРАТНИК. Для класса СТИПЕНДИАТ виртуальная функция должна вычислять сумму стипендии за указанный промежуток времени, а для класса КОНКРАТНИК – сумму платежа.   


Задание

Разработайте собственный контейнерный класс в соответствии с вашим счастливым вариантом задания (см. табл. 4.1). В качестве член-данного класс должен содержать класс TVector, разработанный Вами в предыдущей работе, и использовать его для хранения данных.

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

Обязательно следует реализовать два варианта вашего класса: использование класса TVector с конструктором без параметров и с конструктором с параметрами.

Если в вашем задании не оговорен конкретно тип обрабатываемых данных, то он может быть любым числовым. Другими словами, объявляйте тип данных как ElemType, который описан в файле TVector.h.

Разработанный вами класс должен размещаться в отдельных файлах (.h и .cpp).

В качестве примера реализации класса Стек смотрите программу Stck . exe.

10.2. Описание вариантов заданий

Таблица 4.1.

Варианты заданий

№ вар. Задание
1,8 Класс Стек (CStack) со следующими методами:
  • запись данного в стек (Push);
  • извлечение данного из стека (Pop);
  • вывод содержимого стека на монитор (Print);
  • получение числа данных в стеке (Size);
  • проверка стека на наличие в нем данных (Empty).
Класс Стек представляет собой такую структуру данных, в которой реализуется правило «первым пришел – последним вышел»
2,9 Класс Очередь (CQueue) с такими же методами, как и класс Стек. Этот класс представляет собой такую структуру данных, в которой реализуется правило «первым пришел - первым вышел»
3,10 Класс Очередь с приоритетом (CPriorityQueue) с такими же методами, как и класс Очередь. Отличительной чертой этого класса является то, что самый большой элемент всегда находится в начале очереди, т.е. данные в очереди упорядочены.
4,11 Класс Ассоциативный массив (CMap), каждый элемент которого имеет не целочисленный индекс, а «имя», представляющее собой строку символов. Когда числовое значение заносится в массив, для него указывается также имя. Аналогичным образом извлечение данного из массива также выполняется по его имени. Для облегчения решаемой задачи можно принять некоторые допущения:
  • длина имени ограничена, например, 5 символами;
  • каждое имя предполагается оригинальным;
  • число элементов массива ограничено, например, 100.
Из этого следует, что имена элементов массива можно хранить в двумерном массиве, например, char Names[100][6] или char *Names[100]. Массив указателей предпочтительнее, так как позволит не накладывать ограничение на число символов в имени.
5,12 Класс Массив (CArrChar), предоставляющий возможность задания индексов массива символьного типа. Конструктор класса должен получать в качестве параметров начальный и конечный индексы массива как данные символьного типа. Методы добавления, получения, вставки, удаления элементов массива должны получать в качестве параметра индекс массива символьного типа.
6,13 Класс Массив (CArrInt), предоставляющий возможность задания начального и конечного индексов массива как целых чисел. Конструктор класса должен получать в качестве параметров начальный и конечный индексы массива. Методы добавления, получения, вставки, удаления элементов массива должны получать в качестве параметра индекс массива целочисленного типа.
7,14 Класс Кольцо (CRing), предназначенный для хранения и обработки данных числового типа как массива. Отличительной особенностью класса является тот факт, что класс всегда «помнит» текущий индекс массива и при добавлении нового элемента массива вставляет его вслед за текущим и делает новым текущим, а при получении значения текущего элемента массива автоматически перемещается к следующему. Когда текущим становится последний элемент массива, то после получения его значения текущим должен стать первый элемент массива.

 

Методические указания

В качестве иллюстрации контейнерного класса рассмотрим следующий пример. Пусть имеется класс CDate, который поддерживает обработку дат (день, месяц и год):

// Файл Date.h

#pragma once

class CDate

{

public:

CDate(void);

~CDate(void);

void setDay(int newDay);

void setMonth(int newMonth);

void setYear(int newYear);

int getDay();

int getMonth();

int getYear();

private:

int m_nDay;

int m_nMonth;

int m_nYear;

};

 

Реализацию этого класса разместим, как принято, в cpp-файле:

// Файл Date.cpp

#include "StdAfx.h"

#include "Date.h"

CDate::CDate(void): m_nDay(0), m_nMonth(0), m_nYear(0)

{

TRACE("Constructor CDate was called\n");

}

CDate::~CDate(void)

{

TRACE("Destructor ~CDate was called\n");

}

void CDate::setDay(int newDay){m_nDay=newDay;}

void CDate::setMonth(int newMonth){m_nMonth=newMonth;}

void CDate::setYear(int newYear){m_nYear=newYear;}

int CDate::getDay(){return m_nDay;}

int CDate::getMonth(){return m_nMonth;}

int CDate::getYear(){return m_nYear;}

 

Обратите внимание на реализации конструктора и деструктора класса CDate, в которые добавлен макрос TRACE для отслеживания момента их (автоматического) вызова.

Пусть также имеется класс CPerson, назначение которого состоит в обработке данных о служащих. Очевидно, что для каждого служащего надо сохранять несколько дат, например, день рождения, дата поступления на работу, даты отпусков и т.п. Для простоты ограничимся одной датой и опишем класс таким образом:

// Файл Person.h

#pragma once

#include "date.h"

Class CPerson

{

public :

CPerson(void);

~CPerson(void);

char * getFName(void);

char * getSName(void);

void setFName(char * newFName);

void setSName(char * newSName);

void setBirthDate(int Day, int Month, int Year);

int getBirthDay();

int getBirthMonth();

int getBirthYear();

private :

char *m_sFName;

char *m_sSName;

CDate m_dBirthDate;

};

=======================================================================

// Файл Person.cpp

#include "StdAfx.h"

#include "Person.h"

CPerson::CPerson(void): m_sFName(NULL), m_sSName(NULL)

{

TRACE("Constructor CPerson was called\n");

}

CPerson::~CPerson(void)

{

if(m_sFName) delete [] m_sFName;

if(m_sSName) delete [] m_sSName;

TRACE("Destructor ~CPerson was called\n");

}

char * CPerson::getFName(void)

{ return m_sFName; }

char * CPerson::getSName(void)

{ return m_sSName; }

void CPerson::setFName(char * newFName)

{

m_sFName=new char [strlen(newFName)+sizeof(char)];

strcpy(m_sFName,newFName);

}

void CPerson::setSName(char * newSName)

{

m_sSName=new char [strlen(newSName)+sizeof(char)];

strcpy(m_sSName,newSName);

}

Int CPerson::getBirthDay()

{ return m_dBirthDate.getDay(); }

Int CPerson::getBirthYear()

{ return m_dBirthDate.getYear(); }

 

В приведенном листинге класса CPerson обратите особое внимание на реализацию конструктора и деструктора класса, в которые добавлены макросы TRACE для отслеживания последовательности их вызовов.

Проведем эксперимент: создадим консольное приложение, подключим к нему заголовочный файл Person . h и добавим в главную функцию следующий код:

int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])

{

// ...

CPerson *pPers;

pPers=new CPerson;

delete pPers;

// ...

}

После запуска приложения на выполнение в окне Debug мы увидим следующие строки:

Class CDate

{

public :

CDate(void);

CDate(int iDay, int iMonth,int iYear);

// ...

};

==========================================================================

// Файл Date.cpp

Задание

Разработайте консольное приложение, а если хотите – приложение с графическим интерфейсом пользователяJ, в котором реализуются операции над векторами и матрицами, оформленные как перегруженные «классовые» операции в соответствии с вашим индивидуальным заданием. Само собой разумеется, что вы должны разработать классы матриц и векторов и в них реализовать перегруженные операции. Для хранения значений элементов матриц и векторов необходимо использовать указатели.

Любое приложение должно предоставлять очеееень привередливому пользователю, например, тому же добрейшему преподуL, следующие бесплатные, т.е. даровые, услуги:

Ø возможность многократно вводить исходные данные и получать результат без выхода из приложения, т.е. без его перезапуска на выполнение;

Ø возможность ввода размеров векторов, матриц и других параметров;

Ø реализовать перегруженную операцию [] доступа к элементам векторов и матриц;

Ø в каждом варианте задания необходимо реализовать перегруженные операции как компонентные функции, дружественные и глобальные;

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

 

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


Обратите внимание, что здесь проиллюстрирована операция умножения матриц и результирующая матрица «настоящая».

Class CMatrix

{

//

};

 

Допустим, требуется выполнять операции над прямоугольной матрицей размером NxM, где N – число строк, а М – число столбцов. Тогда выделить память для этой матрицы можно так:

double ** Mtr ;

Mtr=new double * [N];

for (int i=0;i<N;i++) Mtr[i]= new double [M];

 

Соответственно, освободить память можно так:

for (int i=0;i<N;i++) delete [] Mtr[i];

delete []Mtr;

 

Можно, элементарно, выделить память и для треугольной матрицы (в первой строке N столбцов, а в последней – 1):

double **Mtr;

Mtr=new double * [N];

for (int i=0;i<N;i++) Mtr[i]= new double [N-i];

 

Реализация перегруженной операции доступа по индексу [] для вектора вам известна, а как ее реализовать для матрицы как двумерного массива? Операции [][] в языке С++ не существует! Как же быть, если требуется передать два индекса (строка и столбец) посредством одного параметра? Да например так:

int Index=i/*строка*/*1000+j/*столбец*/; // "Упаковка индексов"

int i=Index/1000,j=Index%1000; // " Распаковка индексов "

 

Еще можно номер строки хранить в двух старших байтах переменной типа int, а номер столбца – в двух младших. Достоинством такого подхода является возможность контроля номера строки и номера столбца, т.е. индексов двумерного массива.

Заметим, однако, что можно перегрузить операцию [] и таким образом:

double * CMatrix::operator [](int Index)

{     

return Mtr[Index];

}

 

В этом случае выражение Obj[i] возвращает указатель на i-тую строку матрицы, а Obj[i][j] – значение двумерного массива в i-той строке и j-том столбце. Другими словами, имеет место тождество Obj[i][j] == *(Obj[i]+j).

Сказанное относится не только к двумерным массивам, а и к многомерным. Однако при таком подходе сложнее контролировать корректность индексов.

Class Complex

{

double Re,Im;

char * ObjName ; // для хранения имени объекта

public :

Complex(double iRe=0, double iIm=0, char * ObjName="")

{

Re=iRe; Im=iIm; this->ObjName=ObjName;

TRACE("Complex ObjName=%s this=%d\n",ObjName,(int)this);

}

~Complex()

{

if ((!ObjName) || ((int)ObjName==0xcccccccc)) ObjName="Bad_Ptr";

TRACE("~Complex ObjName=%s this=%d\n",ObjName,(int)this);

}

Complex(const Complex & Org)

{

 TRACE("CopyCTR Org.ObjName=%s this=%d\n",Org.ObjName,(int)this);

 Re=Org.Re; Im=Org.Im; ObjName=Org.ObjName;

}

Complex & operator=(const Complex & Org)

{

TRACE("operator= Org.ObjName=%s this=%d\n",Org.ObjName,(int)this);

Re=Org.Re; Im=Org.Im;

return *this;

}

Complex operator +(Complex &X)

{

  return Complex(Re+X.Re,Im+X.Im,"Return operator+");

}

Complex operator -(Complex X);

Complex operator -=(Complex X)

{ Re-=X.Re; Im-=X.Im; return *this;}

friend Complex operator *(Complex X,Complex Y);

friend ostream & operator <<(ostream &Out, Complex X)

{ return Out<< '('<<X.Re<<"+i"<<X.Im<<')';}

};

Void main()

{

{

       Complex a (1.23,4," a " ), b (2.34,5," b " ), c (0,0," C " );

                   //Complex ObjName=a this=1244980

                   //Complex ObjName=b this=1244948

                   //Complex ObjName=C this=1244916

       c=a+b;

                   //CopyCTR Org.ObjName=b this=1244604

                   //Complex ObjName=Return operator+ this=1244628

                   //~Complex ObjName=b this=1244604

                   //operator= Org.ObjName=Return operator+ this=1244824

                   //~Complex ObjName=Return operator+ this=1244628

                   //CopyCTR Org.ObjName=C this=1244624

                   //~Complex ObjName=C this=1244624

// Если параметр операции-функции сложения объявить ссылкой

// Complex operator +(Complex &X),

// то получим такую последовательность вызовов методов:

                   //Complex ObjName=Return operator+ this=1244648

                   //operator= Org.ObjName=Return operator+ this=1244916

                   //~Complex ObjName=Return operator+ this=1244648

                   //CopyCTR Org.ObjName=C this=1244644

                   //~Complex ObjName=C this=1244644

// Если операцию-функцию присвоить объявить как

// Complex & operator=(const Complex & Org)

// (и при этом операцию-функцию сложения объявить как

// Complex operator +(Complex &X),

// то получим такую последовательность вызовов методов:

                   //Complex ObjName=Return operator+ this=1244680

                   //operator= Org.ObjName=Return operator+ this=1244916

                   //~Complex ObjName=Return operator+ this=1244680

       cout<<c<<endl;

                   //CopyCTR Org.ObjName=C this=1244624

                   //~Complex ObjName=C this=1244624

}

                   //~Complex ObjName=C this=1244916

                   //~Complex ObjName=b this=1244948

                   //~Complex ObjName=a this=1244980

}

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

Какие можно сделать основные выводы из результатов выполнения этой программы, точнее, реализации операций-функций?

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

В качестве еще одного примера рассмотрим класс CArr, предназначенный для обработки одномерных массивов.

 

 

Реализация операции вычитания массивов, как и других полезных операций, отдана на ваше усмотрение. После выполнения этой работы использование объектов класса может быть реализовано следующим образом:

Void main()

{

setlocale(LC_ALL,"rus");

srand( (unsigned)time( NULL ) );

int N=7;

CArr A(N,"A");

CArr B(N,"B"),*C;

for(int i=0;i<N;i++)

{

       double Val=(double)rand()/RAND_MAX*10;

       A.setElem(i,Val);

       Val=(double)rand()/RAND_MAX*10;

       B.setElem(i,Val); // можно так

       B[i]=Val;      // а можно и так

}

cout<<" Массив А " <<endl<<A<<endl<<endl;

cout<<" Массив B" <<endl<<B<<endl<<endl;

C=A+B;

cout<<" Массив C=A+B" <<endl<<*C<<endl<<endl;

delete C;

CArr D(N,"D");

D=A-B;

cout<<" Массив D=A-B" <<endl<<D <<endl<<endl;

cout<<" Массив A-B" <<endl<<(A-B)<<endl<<endl;

}

Варианты заданий

В приведенных ниже вариантах заданий под векторами подразумеваются одномерные массивы, а под матрицами – двумерные.

Значения элементов векторов и матриц должны иметь вещественный тип; их необходимо генерировать с помощью датчика псевдослучайных чисел из заданного пользователем диапазона.

Выбор варианта задания согласуйте с преподавателем.

Таблица 1

Варианты заданий

Вариант Задание
1 Реализовать операции сложения и вычитания двух прямоугольных матриц одинакового размера
2 Реализовать операцию транспонирования прямоугольной матрицы. Например, если для этой операции выбрать знак ~, то программа должна позволять вычислять выражения вроде A=~B. Понятно, что если матрица А имеет размер 3х4, то матрица В должна иметь размер 4х3
3 Реализовать операцию умножения двух прямоугольных матриц. Две матрицы можно перемножить, если число столбцов первой матрицы равно числу строк второй. Например, если первая матрица имеет размер 3х4, а вторая 4х2, то получим результирующую матрицу 3х2
4 Реализовать операцию умножения матрицы на заданную величину, а также сложения матрицы с заданной величиной
5 Реализовать операцию умножения матрицы на вектор. Например, если имеется матрица размером 3х4 и вектор размером 4, то в результате должен получиться вектор размером 3. Матрица и вектор должны быть реализованы как разные классы
6 Реализовать операции сложения и умножения векторов, для чего необходимо разработать два разных класса: один с данными вещественного типа, а другой – целого
7 Реализовать операцию прямого (внешнего) произведения двух прямоугольных матриц одинакового размера С=А*В. Элементы матрицы С являются произведением соответствующих элементов матриц А и В: С[i][j]=A [i][j]*B[i][j]
8 Реализовать операцию нормирования вектора путем приведения его значений к диапазону от -1 до +1
9 Реализовать операцию умножения матрицы на вектор. Например, если имеется матрица размером 3х4 и вектор размером 4, то в результате должен получиться вектор размером 3
10 Реализовать операции вычитания и деления векторов и проиллюстрировать возможность вычисления выражений вроде a=(b-c)/d, где a, b, c и d – векторы
11 Реализовать операции сложения и вычитания двух треугольных матриц одинакового размера

 



Задание

По работе [4] изучите подраздел 13.4 «Реализация связного списка как класса», в котором изложен сценарий создания односвязного списка и приведены листинги программы.

Создайте консольное приложение, добавьте в него класс узел связного списка и класс список на основе данных листингов. Разместите эти классы в разных файлах.

Выполните отладку приложения, тестируйте его и добейтесь корректной работы. Убедитесь, что по завершению работы вашей программы утечек памяти нет. Смотрите пример проекта LinkV2.exe.

Разработайте собственный класс узел (элемент списка) в соответствии с вашим вариантом задания, приведенным ниже в табл. 9.1. Далее необходимо разработать класс список, который будет оперировать объектами-узлами: добавлять, удалять и т.д. Один из вариантов реализации класса список имеется в работе [4].

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

Ваше приложение должно быть русифицировано, а еще лучше – украинизировано.

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

Предусмотрите в программе два варианта ввода данных, которые должны сохраняться в узлах списка: 

§ ввод данных с клавиатуры;

§ чтение данных из текстового файла.

 

Эти варианты ввода должны выбираться с помощью меню.

 

12.2. Описание вариантов заданий

В каждом варианте задания оговаривается содержимое класса узла, т.е. те данные, которые должны там сохраняться, и их типы (если не указан – то int). Кроме того, оговаривается член-функция класса списка, которая должна быть реализована в дополнение к тем, текст которых приведен в приведенном выше источнике.

Таблица 9.1.

Варианты заданий

№ вар. Задание
1 Узел списка Трактор с член-данными марка (char *), цвет (char *), объем (float) и мощность двигателя. Реализовать член-функцию «добавление в начало списка нового узла»
2 Узел списка Служащий с член-данными ФИО (char *), идентификационный код, возраст. Реализовать член-функцию «удаление первого элемента списка»
3 Узел списка Книга с член-данными число страниц, язык издания (char *), наличие иллюстраций (bool). Реализовать член-функцию «удаление последнего элемента списка»
4 Узел списка Комната с член-данными ширина (float), длина (double) и цвет стен (char *). Реализовать член-функцию «получение элемента с заданным порядковым номером»
5 Узел списка Птица с член-данными вес (float), максимальные высота и скорости, порода (char *). Реализовать член-функцию «удаление элемента с заданным порядковым номером»
6 Узел списка Двигатель с член-данными тип двигателя ((char *)бензиновый, дизельный, электрический, комбинированный), фирма-производитель (char *) и мощность двигателя (float). Реализовать член-функцию «замена элемента с заданным порядковым номером на новый»
7 Узел списка Вектор с член-данными указатель на целочисленный тип данных, его размер и фактическое число элементов, т.е. массив. Реализовать член-функцию «поиск в списке массива с заданным содержимым». Требуется найти в списке все узлы, которые содержат массив с заданным содержимым. Разные узлы списка должны содержать различное число элементов массива
8 Узел списка Муха с член-данными вид (char *), число крыльев и их размах (float). Реализовать член-функцию «вставка элемента перед указанным порядковым номером»
9 Узел списка Сок с член-данными марка (char *), производитель (char *) и объем упаковки. Реализовать член-функцию «удаление всех элементов, удовлетворяющих некоторому условию»
10 Узел списка Ребенок с член-данными вес, рост и раса (char *). Реализовать член-функцию «вставка элемента после указанного порядкового номера»
11 Узел списка Компьютер с член-данными марка (char *), число процессоров, объем оперативной памяти. Реализовать член-функцию «добавление в конец списка нового узла»
12 Узел списка Окно с член-данными меню (char *) и число тем меню, наличие инструментальной панели (bool) и строки статуса (bool). Реализовать член-функцию «замена элемента с заданным порядковым номером на новый»
13 Узел списка с член-данными ФИО (char *), пол (char), специальность (char *), курс обучения. Реализовать член-функцию «замена элемента с заданным порядковым номером на новый»

 



Приложение, основанное на модальном диалоговом окне

Если программа не работает – это нормально, если работает – значит, Вы не замечаете ошибок

                              ОВН

Цель работы – освоить разработку приложения, главным и единственным окном которого является модальное диалоговое окно со стандартными элементами управления Windows (4 час.)

Идея этой работы заимствована из материала главы 6 «Модальные диалоговые окна и стандартные элементы управления Windows» работы [1].

Задание.

1. Ознакомиться с теоретической частью работы по методическим указаниям.

2. Создать приложение в соответствии с приведенными в названной работе указаниями.

3. Отладить и добиться работоспособности приложения.

4. Осмыслить полученный результат, примененный инструментарий и приемы программирования.

5. Ответить на коварные вопросы преподавателя и получить наивысшую оценку, если повезет

 

 

Разбор приложения

 

После вызова функции Cdialog::DoModal() управление возвратится вашей программе, только когда пользователь закроет диалоговое окно. Если Вам это ясно, то Вы гений, который постиг тайну модального диалогового окна. Перейдя к работе с немодальными диалоговыми окнами, Вы еще оцените, как просто было программировать модальные диалоговые окна, потому что при вызове DoModal() очень многое остается за кадром. Но вернемся к нашей теме и рассмотрим, «кто кого вызывает»:

CDialog::DoModal()
CDiaWinDlg::OnInitDialog()
…дополнительная инициализация…

CDialog::OnInitDialog()
CWnd::UpdateData(FALSE)
CDiaWinDlg::DoDataExchange()
пользователь вводит данные…

пользователь нажимает кнопку OK

 CDiaWinDlg::OnOK()
… дополнительная проверка …

CDialog::OnOK
CWnd::UpdateData(TRUE)
CDiaWinDlg::DoDataExchange()
CDialog::EndDialog(IDOK)

 

OnInitDialog() и DoDataExchange() — виртуальные функции, переопределенные в классе CDiaWinDlg. Windows вызывает OnlnitDialog() при инициализации диалогового окна, что приводит к вызову виртуальной функции DoDataExchange(), которую сгенерировал для Вас мастер. Взгляните на листинг этой функции, размещенной в Вашем файле DiaWinDlg.cpp. Функция DoDataExchange() и функции DDX_(обмен) и DDV_(проверка достоверности) — «двусторонние». Если функция UpdateData() вызывается с параметром FALSE, то она переносит данные из связанных переменных в элементы управления диалогового окна. Если же она вызывается с параметром TRUE, то передает данные в противоположном направлении: из элементов управления в связанные переменные. DDX_Text переопределяется для подстройки под множество типов данных.

Функция EndDialog() играет главную роль в процедуре завершения диалогового окна. DoModal() возвращает параметр, передаваемый ей функцией EndDialog(). Значение параметра IDOK означает, что пользователь завершил диалог нажатием кнопки ОК или клавиши Enter, a IDCANCEL – что пользователь завершил диалог нажатием кнопки Cancel. Вы можете самостоятельно вызвать EndDialog() при наступлении какого-либо события – пример см. в MSDN.

Совет. Вы можете написать собственные DDX-функции и подключить их к Visual C++. Это бывает весьма полезно, если во всей своей программе Вы пользуетесь уникальным типом данных. Подробнее см. MFC Technical Note #26 в интерактивной справочной системе MSDN (для версии MVS 6.0).

 

Усовершенствование приложения

 

Один из законов Мэрфи гласит: «Совершенство достигается к моменту краха». Будем оптимистами и все же попытаемся усовершенствовать нашу программу. Избавим наше приложение от скверной привычки завершать свою работу при, даже случайном, нажатии клавиши Enter (ну, например, вследствие падения головы или какой-либо более важной части тела на клавиатуру).

Шаг 11. Обработка нажатия кнопки ОК.

В нашем приложении виртуальная функция CDialog:: OnOK() обрабатывает щелчок кнопки ОК, что запускает процесс обмена данными и процедуру выхода из диалогового окна. Тот же результат дает и клавиша Enter — может быть, это как раз то, чего Вы хотели, а может быть – и нет. Если пользователь нажмет клавишу Enter, скажем, в поле ввода «Фамилия», его немедленно «выбросит» из диалогового окна. Вряд ли это пользователю понравится, если он не мазохист …

Что же происходит? В момент нажатия этой клавиши Windows ищет кнопку, на которой установлен фокус ввода (input focus) — на экране он выглядит как дополнительная пунктирная рамка внутри рамки кнопки при ее нажатии.

 

Замечание. Советую запустить программу, вызвать окно диалога и внимательно к нему присмотреться: нетрудно заметить, что кнопка ОК имеет более толстые границы, чем другие. Теперь добавьте в окно «ничего не делающую» дополнительную кнопку Button1, попробуйте нажимать клавишу табуляции, выделите кнопку Button1 и нажимайте клавишу Enter – ничего не произойдет. Обратите внимание также на то, что в классе CDiaWinDlg сейчас нет обработчика нажатия кнопки OK, как, впрочем, и кнопки Cancel. Вместе с тем в классе CDialog имеется виртуальная функция OnOK(), как и функция OnCancel().

 

Если фокус не установлен ни на одну кнопку, Windows ищет указанную программой или в ресурсе кнопку по умолчанию (default pushbutton): у такой кнопки более толстые границы. Если такой кнопки нет, вызывается виртуальная функция ОnОК — даже если кнопка ОК отсутствует.

Клавишу Enter можно «отключить», просто написав ничего не делающую функцию CDiaWinDlg:: OnOK() и добавив код завершения в новую функцию, реагирующую на щелчок кнопки ОК. Последовательность действий такова.

1. На вкладке Resource View отыщем идентификатор IDD_ DIAWIN_ DIALOG нашего окна и щелкнем по нему ЛКМ, вызвав тем самым появление нашего окна в окне графического редактора. Выберем кнопку ОК, щелкнем по ней ПКМ и в появившемся контекстном меню выберем команду Add Event Handler (добавить обработчик события). Появится окно (рис. 9), в поле которого Function Handler Name необходимо предлагаемое по умолчанию имя OnBnClickedOk заменить на OnOK (обратите внимание на регистр символов!) и нажать кнопку Add and Delete. Мастер сгенерирует функцию

void CDiaWinDlg::OnOK()

{

// TODO: Add your control notification handler code here

OnOK();

}

 

Как видите, мастер не такой уж и мастер: функция вызывает саму себя, что при запуске приложения на выполнение и нажатии клавиши Enter приведет к переполнению стека. Надо в нашем обработчике вызывать (виртуальную) функцию CDialog::OnOK() родительского класса – тогда все будет ОК, т.е. по-прежнему. Однако мы должны на этом этапе сделать нашу функцию просто пустышкой с одним только макросом TRACE:

void CDiaWinDlg::OnOK()

{

TRACE(“Вход в CDiaWinDlg::OnOK()\n”);

}

 

Если теперь мы запустим приложение на выполнение, то нажатие кнопки ОК или клавиши Enter не будет приводить к закрытию окна, т.е. завершению программы, так как мы устранили вызов функции CDialog::OnOK(). В окне Debug мы должны видеть сообщение о вызове функции CDiaWinDlg::OnOK(). Однако нашей задачей является все же обеспечение такой логики работы приложения, при которой нажатие кнопки ОК будет приводить к завершению работы программы.

 

2. Вызовите окно свойств для кнопки ОК и замените идентификатор кнопки IDOK на IDC_ OK и отмените у нее свойство Default Button, присвоив ему значение False (рис. 10). Теперь нажмите кнопку Control Events в окне Properties и сгенерируйте для нее обработчик события BN_ CLICKED. Мастер сгенерирует функцию CDiaWinDlg::OnBnClickedOk(), в которую достаточно добавить одну-единственную строку и вызов макроса TRACE для наглядности:

void CDiaWinDlg::OnBnClickedOk()

{

TRACE("Вход в CDiaWinDlg::OnBnClickedOk()\n");

CDialog::OnOK();    

}

 

Обратите внимание на вызов функции CDialog::OnOK(): эта функция делает полезную работу.

 

 

Рис. 9. Добавление обработчика события нажатия кнопки ОК

 

3. Соберите и протестируйте приложение. Попробуйте теперь нажать клавишу Enter. Ничего произойти не должно, но в окне Debug появится вывод макроса TRACE «Вход в CDiaWinDlg::OnOK()». Вместе с тем по щелчку кнопки ОК диалоговое окно должно закрыться.

 

 

Рис. 10. Изменение свойств кнопки ОК

Шаг 12. Обработка нажатия кнопки Cancel.

Так же как нажатие клавиши Enter приводило к вызову О nОК(), так и нажатие клавиши Esc инициирует вызов OnCancel(), в результате чего диалоговое окно завершается с кодом возврата IDCANCEL от функции DoModal(). Наша программа не предусматривает особой обработки IDCANCEL, поэтому нажатие клавиши Esc (или щелчок кнопки Close) закрывает диалоговое окно. Вы можете обойти этот процесс, применив функцию-заглушку OnCancel() по аналогии с тем, как это уже делалось для кнопки ОК.

Замечание. Попробуйте изменить какие-нибудь значения в управляющих элементах окна и закрыть его – диалоговое окно – с помощью кнопки ОК и с помощью кнопки Cancel. Понаблюдайте при этом за значениями элементов управления (точнее, связанных с ними переменных-членов) в окне Debug. Есть разница?

 

Шаг 13. Выбор фона диалогового окна и цвета элементов управления.

Чтобы изменить фон отдельных диалоговых окон или конкретных элементов управления в каком-либо диалоговом окне, придется (в отличие от работы в Delphi) потрудиться. Каждый элемент управления, прежде чем появиться на экране, посылает родительскому диалоговому окну сообщение WM_CTLCOLOR. Такое же сообщение отправляется и самому диалоговому окну. Если написать в производном классе диалогового окна обработчик этого сообщения, можно установить цвет текста и его фон, а также выбрать кисть для заполнения нетекстовой области элемента управления или диалогового окна.

Ниже приведен пример функции OnCtlColor(), задающей желтый фон для всех полей ввода и синий фон с красной штриховкой для диалогового окна. Для цвета фона текста полей ввода, исключительно в качестве иллюстрации, задан зеленый цвет. В результате цветовая гамма диалогового окна получается ужасной, но зато наглядной.

В функции CDia WinDlg::OnCtlColor() параметр nCtlColor определяет тип элемента управления, а pWnd — конкретный элемент управления. Чтобы установить цвет отдельного элемента управления, нужно преобразовать pWnd в идентификатор дочернего окна и проверить его значение, как это сделано в приведенной ниже функции.

 

Заготовку функции C DiaWinDlg:: OnCtlColor() можно создать с помощью все того же окна свойств Properties для нашего диалогового окна, выбрав на вкладке Messages сообщение WM_CTLCOLOR и сгенерировав обработчик этого сообщения. Текст обработчика приведите в соответствие с приведенным выше.

Переменные m_hYellowBrush и m_hRedBrush – это переменные-члены типа HBRUSH (brush – кисть), которые предлагается описать в классе CDiaWinDlg, в секции protected. Эти переменные можно инициализировать в CDiaWinDlg::OnInitDialog(), например, так:

 

 

 

Попробуйте собрать приложение и тестировать его. Если Вам не понравится цветовая гамма – измените!

 

Замечание. Диалоговое окно не помещает сообщение WM_CTLCOLOR в очередь сообщений (message queue); вместо этого окно, чтобы немедленно отправить сообщение, вызывает Win32-функцию SendMessage(). Благодаря этому обработчик сообщения может вернуть параметр, в данном случае описатель кисти. Это не MFC-объект типа CBrush, a Win32 HBRUSH. Создать кисть можно, вызвав Win32-функции CreateSolidBrush(), CreateHatchBrush(), CreatePatternBrush() и др.

В функции CDiaWinDlg::OnCtlColor() можно получить информацию о конкретном элементе управления несколькими способами, например, путем анализа значения указателя на элемент управления:  

if(*pWnd==objBio)

{

pDC->SetBkColor(RGB(255, 0, 0)); // цвет фона текста биографии

pDC->SetTextColor(RGB(255,192,128)); // цвет фона текста биографии

TRACE("IDC_BIO\n");

return m_hYellowBrush; // кисть элемента управления

// или return CreateSolidBrush(RGB(150,150,255));

}

 

Шаг 14. Сохранение результатов диалога в текстовом файле. Доработайте программу таким образом, чтобы введенные пользователем данные сохранялись в текстовом файле по нажатию кнопки «Сохранить», которую Вы добавите в диалоговое окно. Для этой благородной цели вы можете воспользоваться подсказками, приведенными в подразделе «Запись текстовых файлов с использованием класса CFile» файла VC_Lect.doc. В этом же файле вы найдете подсказки, как добавить в свою программу диалог по выбору имени файла (класс CFileDialog).

 

 

Коварно-контрольные вопросы:

1. Как вызвать системное меню диалогового окна, какие команды в нем есть?

2. Вызовите окно «О программе» диалогового окна, а также покажите в программе код, который вызывает это окно.

3. Какие Вы знаете способы задания заголовка окна (в сценарии – «Кадры решают все!»)?

4. Какие комбинированные списки (ComboBox) позволяют только выбирать одно из имеющихся значений, а какие позволяют также и вводить собственные значения? Какое свойство комбинированного списка ответственно за такое поведение элемента управления?

5. Зачем нужна функция ToAnsi и что это за функция: библиотечная или собственная?

6. Чем полезен макрос TRACE, чем он отличается от просмотра значений переменных с помощью средств отладчика?

7. Вызов какой функции приводит к появлению диалогового окна на экране?

8. Для чего предназначен макрос RGB, чем его можно было бы заменить?

9. Для чего предназначена функция Format класса CString? 

 

 















Приложения

Виды сортировок

Сортировка – процесс перегруппировки заданного множества объектов в некотором определенном порядке.

Сортировка в программировании – это упорядочивание элементов в возрастающем или убывающем порядке.

Цель сортировки – облегчить последующий поиск элементов в отсортированном множестве.

Основные из наиболее важных применений сортировки:

ü решение задачи «группировки», когда нужно собрать вместе все элементы с одинаковым значением некоторого признака;

ü сортировка двух или более файлов в одном и том же порядке, позволяющая отыскать в них все общие элементы за один последовательный просмотр всех файлов без возвратов;

ü сортировка может сделать вывод результатов ЭВМ более удобными для человеческого восприятия.

Классификация сортировок

Обычно сортировки подразделяют на два класса:

ü внутренние сортировки, когда все сортируемые элементы хранятся в быстрой оперативной памяти. Отличительной особенностью является следующее: сортировка должна экономно использовать память. Это предполагает, что перестановки должны выполняться на одном и том же месте. Поэтому к внутренним методам сортировок относятся методы сортировки массивов, т.к. массивы располагаются во «внутренней» оперативной памяти, для которой характерны быстрый произвольный доступ к элементам.

ü внешние сортировки, когда все сортируемые элементы не помещаются в оперативной памяти. Поэтому к внешним сортировкам относят сортировку файлов, которые располагаются в более медленной, но более вместительной «внешней» памяти, т.е. на запоминающих устройствах.

Принципиальное различие в составлении алгоритмов внутренних и внешних сортировок обусловлено способом доступа к элементам массивов и файлов: в массиве любой элемент виден и доступен (рис. 1); в файле виден текущий элемент (рис. 2).

     
 

 


Рисунок 1 – Сортировка массива          Рисунок 2 – Сортировка файлов

 

Внутренние методы сортировки, в свою очередь, делятся на простые и улучшенные методы.

К простым методам сортировок можно отнести:

ü сортировки с помощью включения (by insertion);

ü сортировки с помощью выбора (by selection);

ü сортировки с помощью обмена (by exchange).

 

К улучшенным методам относятся:

ü сортировка Шелла;

ü пирамидальная сортировка;

ü быстрая сортировка.

 

К внешним сортировкам относятся:

ü сортировка простым слиянием;

ü сортировка естественным слиянием;

ü многопутевое слияние;

ü многофазная сортировка;

ü каскадная сортировка.


Сортировка массивов

Основным критерием оценки для внутренних сортировок является экономное использование доступной памяти. Методы, в которых элементы из массива а передаются в результирующий массив b, представляют существенно меньший интерес. Для классификации методов сортировки хорошей мерой эффективности может быть число необходимых сравнений ключей (С) и число пересылок (перестановок) элементов (М).

Хотя хорошие алгоритмы сортировки требуют порядка n* logn сравнений, сначала разберем несколько простых и очевидных методов, называемых простыми, где требуется порядка n2 сравнений элементов.

Алгоритмы прямых методов следует изучить по следующим причинам:

ü прямые методы особенно удобны для объяснения характерных черт основных принципов большинства сортировок;

ü программы этих методов легко понимать, и они коротки – а ведь сами программы также занимают память;

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

 

Пример сортировки с помощью прямого включения

 

Элементы массива:  44 55 12  42   94  18  06   67

i=2                   44 55 12 42 94 18 06  67 (55 остался на месте)

i=3                 12 44 55 42 94 18 06 67 (12 перешел на 1 ячейку)

i=4                 12 42 44 55 94  18 06 67   (42 перешел на 2 ячейку)

i=5                 12 42 44 55 94 18  06 67 (94 остался на месте)

i=6                 12 18 42 44 55 94 06  67 (18 перешел на 2 ячейку)

i=7                 06 12 18 42 44 55 94 67   (06 перешел на 1 ячейку)

i=8                06 12 18 42 44 55 67 94  (67 перешел на 7 ячейку)

     

Идея алгоритма этой сортировки такова:

{для каждого элемента, начиная со второго}

x := a[i];

включение x  на соответствующее место среди a[1] … a[i];

 

В реальном процессе поиска подходящего места удобно, чередуя сравнения и движения по последовательности, как бы просеивать x, т.е. x сравнивается с очередным предыдущим элементом aj , а затем либо x вставляется на свободное место, либо aj сдвигается (передается) вправо и процесс «уходит» влево. Следует обратить внимание, что процесс просеивания может закончиться при выполнении одного из двух условий:

ü найден элемент aj со значением, меньшим, чем x;

ü достигнут левый конец готовой последовательности.

 

Это типичный пример цикла с двумя условиями окончания, что дает возможность применить известный прием фиктивного элемента («барьера»). Его можно реализовать, установив барьер a0 = x , для чего следует расширить диапазон индексов массива a [0.. n].

 

Сортировка Шелла

В 1959 г. Д.Шеллом было предложено усовершенствование сортировки с помощью прямого включения. Суть метода в следующем: сначала отдельно группируются и сортируются элементы, отстоящие друг от друга на расстоянии 4. Такой процесс называется четверной сортировкой. После первого прохода элементы перегруппировываются. Теперь каждый элемент группы отстоит от другого элемента группы на две позиции - и элементы вновь сортируются. Это называется двойной сортировкой. И, наконец, на третьем проходе идет обычная, или одинарная сортировка.

Такой метод в результате дает упорядоченный массив, и видно, что каждый проход от предыдущего только выигрывает (так как каждая i-я сортировка объединяет две группы, уже отсортированные 2 i-сортировкой). Очевидно, что расстояния в группах можно уменьшать по-разному, лишь бы последнее было единичным, ведь в самом плохом случае последний проход и сделает всю работу.

 

Пример сортировки

 

Исходный массив:

44 55 12 42 94 18 06 67

 

Четверная сортировка дает:

44 18 06 42 94 55 12 67

 

Двойная сортировка дает:

06 18 12 42 44 55 94 67

 

Одинарная сортировка дает:

06 12 18 42 44 55 67 94

 

На самом деле значение шага сортировки можно (и нужно) варьировать. В общем случае при сортировке Шелла сначала сравниваются и сортируются между собой значения, стоящие один от другого на некотором расстоянии d. После этого процедура повторяется для некоторых меньших значений шага, а завершается сортировка Шелла упорядочиванием элементов при d=1 (то есть обычной сортировкой вставками). Эффективность сортировки Шелла в определённых случаях обеспечивается тем, что элементы «быстрее» встают на свои места.

Невзирая на то, что сортировка Шелла во многих случаях медленнее, чем быстрая сортировка, она имеет ряд преимуществ:

ü отсутствие потребности в памяти под стек;

ü отсутствие деградации при неудачных наборах данных — быстрая сортировка легко деградирует до сложности O(n²), что хуже, чем худшее гарантированное время для сортировки Шелла.

 

 


Список литературы

1. Круглински Д., Уингоу С., Шеферд Дж. Программирование на Microsoft Visual C++ для профессионалов/Пер. с англ. – СПб:Питер; М.: Издательско-торговый дом "Русская редакция", 2000. - 864с.

2. Холзнер С. Visual C++ 6: учебный курс – СПб.: Изд-во «Питер», 2000. – 576с.

3. Конспект лекций в файле VC_Lect.doc

4. Овсянник_Язык_С++_не_для_чайников.doc

5. Кравець П.О. Об’єктно-орієнтоване програмування: навч. посібник/ П.О.Кравець. – Львів: Видавництво Львівської політехніки, 2012. – 624с.

 

 


 



Интегрированная среда MVS-2010

Неопределимые ошибки бесконечны, а определимые ограничены возможностями компилятора

Закон Мерфи

Цель работы – освоить основные возможности интегрированной среды Microsoft Visual Studio 2010 (далее ИС MVS-2010) по разработке и отладке типового консольного приложения на языке С++ (4 час.)

Задание. Проделайте следующее:

1. Прочитайте это задание и методические указания до конца, прежде чем терзать клавиатуру, соседа, преподавателя и пр. сущности

2. Запустите на выполнение ИС MVS-2010, ознакомьтесь с командами меню и инструментальными панелями.

3. Создайте консольное приложение и дайте ему благопристойное имя («Как яхту назовешь – так она и поплывет»).

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

5. Освойте использование команд компиляции, запуска и отладки приложения (F7, Ctrl+F7, F5, Ctrl+F5, Shift+F5, F10, F11 и пр.).

6. Научитесь вызывать контекстное меню Debug, выполнять трассировку программы, просматривать значения переменных во время отладки, устанавливать и снимать контрольные точки (breakpoint).

7. Научитесь использовать окна «Autos», «Locals» и «Watch» для просмотра значений переменных во время выполнения (трассировки) программы. Воспользуйтесь помощью (Help) и трассировкой для изучения назначения перечисленных окон.

8. Попробуйте сдать работу, предварительно тщательно протестировав ее на предмет отсутствия хомутов

Методические указания

Дата: 2019-07-30, просмотров: 222.