
ООП_Лабораторный практикум
.pdf
Рис 3.1. Вид главного окна лабораторной программы №3
Создайте диалоговый проект со следующими параметрами:
Project Name - Draw.
Please enter title of your dialog - The Draw Program.
2. Проектирование диалоговой панели
Расставьте элементы управления как показано на рис. 3.1 и согласно таблице 3.1.
|
|
Таблица 3.1. Оконные элементы программы. |
Объект |
Свойство |
Установка |
Dialog Box |
ID |
IDD_DRAW_DIALOG |
|
Caption |
The Draw Program |
|
Font |
System, Size 10, страница Styles |
Static Text |
ID |
IDC_INSTRUCTION_STATIC |
|
Caption |
To Draw: Press the left button of the mouse and move the |
|
|
mouse |
|
|
(Рисование: нажмите левую кнопку мыши и перемещайте) |
|
Align Text |
Center, страница Styles |
|
Client edge |
отмечен, страница Extended Styles |
|
Static edge |
отмечен, страница Extended Styles |
Push Button |
ID |
IDC_EXIT_BUTTON |
|
Caption |
E&xit |
|
Client edge |
отмечен, страница Extended Styles |
|
Static edge |
отмечен, страница Extended Styles |
|
Modal frame |
отмечен, страница Extended Styles |
3. Связывание событий с элементами управления
1) Свяжите код с событием BN_CLICKED кнопки Exit
При нажатии на кнопку Exit программа Draw.Exe завершится.
Связывание кода с событием WM_MOUSEMOVE диалоговой панели. Используйте диалоговую панель ClassWizard для выбора следующего события:
Class Name: CDrawDlg
31
Object ID: CDrawDlg
Messages: WM_MOUSEMOVE
Код функции OnMouseMove():
void CDrawDlg::OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
////////Мой код начинается здесь///////////
if( (nFlags & MK_LBUTTON)==MK_LBUTTON )
{
CClientDC dc(this);
dc.SetPixel(point.x, point.y, RGB(0,0,0));
}
//конец структуры IF
////////Мой код заканчивается здесь///////////
}
Функция OnMouseMove выполняется при любом передвижении мыши, ее параметр nFlags показывает была ли нажата какая-нибудь клавиша клавиатуры( типа ALT или Shift) и кнопка мыши. Операция & проверяет, прижата ли левая кнопка мыши при ее перемещении.
Код в блоке оператора IF CClientDC dc(this); создает объект контекстного устройства, c помощью него вы сможете рисовать, его можно назвать воображаемым экраном в памяти компьютера. Научно говоря, dc(this) - это экземпляр класса CClientDC c параметром конструктора this, с помощью экземпляра класса вы можете обращаться к функциям этого класса.
Следующий оператор рисует точку в заданном месте (место щелчка мыши), используя параметры point.x и point.y, которые ему передает функция OnMouseMove, и заданного цвета, с помощью функции RGB();.
Рисование изображения точка за точкой. Чтобы увидеть в действии свой код, выполните следующие действия:
1.Скомпонуйте и скомпилируйте программу.
2.Запустите ее.
3.Удерживая нажатой левую кнопку мыши, претащите ее в сторону.
4.Вы видите, что точки рисуются не слитно друг с другом, это происходит по тому, что WINDOWS должен выполнять и другие задачи и не может полностью следить за Draw. Модифицируем программу так, чтобы эти точки соединялись линиями.
Расширение возможностей программы DRAW. Модифицируем программу следующим образом.
Чтобы соединить точки линией функция OnMouseMove должна знать предыдущие координаты мыши, для этого нам нужно объявить две переменные m_PrevX и m_PrevY, для хранения координат по X и Y.
Выведем на экран файл DrawDlg.h, для этого откроем Project Workspace, щеклнем на закладке File View и выполним двойной щелчек на пункте DrawDlg.h.
Включите объявления переменных m_PrevX и m_PrevY следующим образом:
//DrawDlg.h : header file
//CDrawDlg dialog
class CDrawDlg : public CDialog
{
// Construction
public:
CDrawDlg(CWnd* pParent = NULL); // standard constructor
////////Мой код начинается здесь///////////
32
int m_PrevX; int m_PrevY;
////////Мой код заканчивается здесь///////////
}
Вы объявили две переменные целого типа для хранения предыдущих координат мыши. Заметьте, что вы их включили после слова public: - это означает, что эти переменные доступны всем функциям класса.
Теперь модифицируем функцию OnMouseMove в файле DrawDlg.cpp void CDrawDlg::OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
////////Мой код начинается здесь///////////
if((nFlags & MK_LBUTTON)==MK_LBUTTON)
{
CClientDC dc(this);
// dc.SetPixel(point.x, point.y, RGB(123,211,98)); CPen NewPen(PS_SOLID, 10, RGB(255,0,0) ; dc.SelectObject(&NewPen); dc.MoveTo(m_PrevX, m_PrevY); dc.LineTo(point.x, point.y);
m_PrevX=point.x; m_PrevY=point.y;
}
////////Мой код заканчивается здесь///////////
CDialog::OnMouseMove(nFlags, point);
}
Код вызова функции SetPixel(), помещен в комментарий, так как он нам больше не понадобиться.
Следующий код CPen NewPen(PS_SOLID, 10, RGB(255,0,0) ) создает новое перо с именем NewPen класса CPen c заданным размером шрифта 10 пикселов и красным цветом. Параметр PC_SOLID означает, что будет рисоваться сплошная линия.
После этого выполняется функция SelectObject, выбирающая новое перо: dc.SelectObject(&NewPen);
Этой функцией вы включаете перо в работу. Следующие два оператора:
dc.MoveTo(m_PrevX, m_PrevY); dc.LineTo(point.x, point.y);
рисуют линию, используя координаты начала(это определяет функция MoveTo()) и координат конца (LineTo).
И последнии два оператора:
m_PrevX=point.x; m_PrevY=point.y;
сохраняют в переменных m_PrevX и m_PrevY, текущие координаты, которые в следующий раз будут использоваться, как предыдущие(начальная позиция).
Теперь запустите программу и проверьте правильность ее работы.
Вы должны заметить, что при первом нажатии на кнопку мышки в любой области диалоговой панели, есть лишняя линия, которая выходит из краев окна. Дело в том, что вы при первом рисовании линии, т.е после первого щелчка мыши и ее передвижении, начальные координаты не определены, а будут известны только текущие.
Для решения этой задачи вы должны связать код событием WM_LBUTTONDOWN, которое происходит при нажатии на левую кнопку мыши.
Код в функции OnLButtonDown():
void CDrawDlg::OnLButtonDown(UINT nFlags, CPoint point)
33
{
// TODO: Add your message handler code here and/or call default
////////Мой код начинается здесь///////////
m_PrevX=point.x; m_PrevY=point.y;
////////Мой код заканчивается здесь///////////
}
Упражнение 1.
а) Сделайте так, чтобы рисуемая линия была шириной 5 пикселов. б) Сделайте так, чтобы рисуемая линия была голубого цвета.
в) Сделайте так, чтобы рисуемая линия была синего цвета. г) Сделайте так, чтобы рисуемая линия была желтого цвета. д) Сделайте так, чтобы рисуемая линия была зеленого цвета. е) Сделайте так, чтобы рисуемая линия была черного цвета.
ж) Сделайте так, чтобы рисуемая линия была фиолетового цвета. з) Сделайте так, чтобы рисуемая линия была белого цвета.
Часть 2. Одномерный динамический массив.
Как вы уже знаете, при стандартной декларации массивов компилятор воспользуется векторной организацией памяти и выделит фиксированный участок памяти, достаточный для хранения всех его элементов. Использование динамической памяти и списковой ее организации позволяет создавать массивы переменной длины. Помимо уже известных операций по захвату и освобождению динамической памяти new и delete для этих целей используют стандартные библиотечные функции, декларациюкоторыхсодержитзаголовочныйфайлalloc.h.
Приведемсведенияонаборефункцийманипулированияпамятью:
void *malloc (unsigned n); - выделение памяти для размещения блока размером п байт; возвращает указатель на распределенную область или NULL при неудаче;
void *calloc (unsigned n, unsigned size); - выделение памяти для размещения л объектов размером size байт и заполнение полученной области нулями; возвращает указатель на захваченную область памяти или NULL при неудаче;
unsigned coreleft (void); - получение размера свободной памяти в байтах: void free(void *b); - освобождение блока памяти, адресуемого указателем b;
void *realloc (void *b, unsigne n); - изменение размера размещенного по адресу b блока на новое значение п и копирование (при необходимости) содержимого блока; возвращает указатель на перераспределенную область памяти или NULL при неудаче.
Пример выделения памяти для массива действительных чисел размером n:
double *x; |
|
int n; |
// Количество элементов массива |
… |
// Захват памяти для п элементов |
х = (double*)calloc(n, sizeof(double)); |
|
free(x); |
// Освобождение памяти |
Общий формат операций new и delete для работы с динамической памятью следующий:
type *name; |
// Декларировали указатель на начало массива |
… |
|
name = new type[size]; |
// Захватили память |
delete [ ] name; |
// Освободили память |
где type - тип элементов, |
|
size - максимальное количество элементов массива пате.
34
Упражнение 2. Пользовательский класс Array должен содержать конструктор с параметром для создания динамических целочисленных массивов (операция new или стандартная библиотечная функция calloc) и установки начальных значений элементов: Array(…) (реальный размер массива передается через параметр);
Конструктор: |
X(…); |
Деструктор: |
~X( ); |
Метод печати текущего состояния массива: |
void Print(…);, |
Метод переустановки текущего состояния массива: |
void Set(...); |
Функция, решающая поставленную задачу: |
void Run(...); |
Код методов и функциидруга — вне пространства определения класса. Программа иллюстрирует косвенный способ обращения к элементам массива.
Варианты: составить метод Run, который позволит выполнить следующие действия и одномерными массивами
а) Найти произведение элементов массива, расположенных между максимальным и минимальным элементами.
б) Найти произведение элементов массива, расположенных между максимальным по модулю и минимальным по модулю элементами.
в) Найти сумму элементов массива, расположенных после минимального элемента. г) Найти сумму модулей элементов массива, расположенных после минимального по
модулю элемента.
д) Найти сумму элементов массива, расположенных до минимального элемента. е) Найти сумму элементов массива, расположенных после первого положительного
элемента.
ж) Преобразовать массив так, чтобы сначала располагались элементы, целая часть которых лежит в интервале [a, b], а потом – все остальные.
з) Сжать массив, удалив из него элементы, величина которых находится в интервале [a, b]. Освободившиеся в конце массива элементы заполнить нулями
Контрольные вопросы.
1)Перечислите сообщения, посылаемые мышью.
2)Что такое контекст устройства?
3)Опишите параметры функции OnMouseMove(…).
4)Как программно определить, что нажата левая клавиша мыши.
5)Опишите параметры функции RGB(…).
6)Формат и назначение библиотечной функции malloc().
7)Формат и назначение библиотечной функции calloc().
8)Формат и назначение библиотечной функции free().
9)Как создать и уничтожить динамический одномерный массив при помощи операций?
10)Как программно контролируется захват памяти под массив?
Лабораторная работа №4.
Работа с клавиатурой. Работа с динамической памятью. Использование дружественных функций.
Цель работы: Изучить методику создания и уничтожения двухмерного динамического массивов при помощи конструкторов с захватом динамической памяти и деструкторов для её освобождения. Научиться работать с классом через функции-друзья этого класса.
35

Часть 1. Среда разработки Microsoft Visual C++ 6.0. Работа с клавиатурой.
1. Создание нового проекта
Для изучения работы клавиатуры с помощью среды разработки Microsoft Visual C++ 6.0 создадим лабораторную программу, выполняющую следующие действия:
Когда в программе нажимаете на клавишу клавиатуры, то выводиться панель сообщения, показывающая различные флаги, представляющие клавишу, которая была нажата.
При запуске вашей программы, главное окно должно будет выглядеть так (рис 4.1):
Рис 4.1. Вид главного окна лабораторной программы №4
Создайте диалоговый проект со следующими параметрами:
Project Name - MyKey.
Please enter title of your dialog - The MyKey Program.
2. Проектирование диалоговой панели
Расставьте элементы управления как показано на рис. 4.1 и согласно таблице 4.1.
|
|
Таблица 4.1. Оконные элементы программы. |
Объект |
Свойство |
Установка |
Dialog Box |
ID |
IDD_MYKEY_DIALOG |
|
Caption |
The MyKey Program |
|
Font |
System, Size 10, страница Styles |
Static Text |
ID |
IDC_INSTRUCTION_STATIC |
|
Caption |
Press keys on the keyboard |
|
Align Text |
Center, страница Styles |
|
Client edge |
отмечен, страница Extended Styles |
|
Static edge |
отмечен, страница Extended Styles |
|
Disabled |
отмечен (General) |
3. Связывание событий с элементами управления
Свяжите код с событием WM_KEYDOWN клавиатуры. При нажатии на клавишу будет появляться окно сообщения, которое будет показывать ее флаг.
Используйте диалоговую панель ClassWizard для выбора следующего события: Class Name: CMyKeyDlg
Object ID: CMyKeyDlg Messages: WM_KEYDOWN
Добавьте в функцию следующий код
36
void CMyKeyDlg::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
// TODO: Add your message handler code here and/or call default
////Мой код начинается здесь////
char strnChar[10]; char strnRepCnt[10]; char strnFlags[10];
CString strKeyPressed;
itoa(nChar, strnChar, 10); itoa(nRepCnt, strnRepCnt,10); itoa(nFlags, strnFlags, 10);
strKeyPressed=(CString)"You pressed the key: "+"\n"+"nChar="+ strnChar+"\n"+"nReptCnt="+strnRepCnt+"\n"+"nFlags="+strnFlags; MessageBox(strKeyPressed);
////Мой код заканчивается здесь////
CDialog::OnKeyDown(nChar, nRepCnt, nFlags);
}
Параметры функции OnKeyDown (UINT nChar, UINT nRepCnt, UINT nFlags)
•nChar - код нажатой клавиши.
•nRepCnt - число повторных нажатий на клавишу.
•nFlags - число нажатой специальной клавишы(такие как ALT, SHIFT).
Код, который вы ввели объявляет три строки: char strnChar[10];
char strnRepCnt[10]; char strnFlags[10];
Они будут хранить значения переменных nChar, nRepCnt, nFlags соответственно. Затем вы объявили переменную strKeyPressed типа CString.
CString strKeyPressed;
Вконце программы, вы присваиваете этой переменной значение строки, которая будет выведена в сообщении. После этого, с помощью оператора itoa вы присваиваете переменным strnChar, strnRepCnt, strnFlags числовые значения соответствующих переменных. Функция itoa переводит число в текстовую строку. Первым аргументом функции itoa, является числовая переменная, которую надо перевести. Вторым аргументом является переменная типа char, в нее будет записываться число. Третий аргументом - число, показывающее систему счисления числовой переменной.
Теперь, когда все три переменные сохранены как строки, их можно объединить в одну строку strKetPressed:
strKeyPressed=(CString)"You pressed the key: "+"\n"+"nChar="+ strnChar+"\n"+"nReptCnt="+strnRepCnt+"\n"+"nFlags="+ strnFlags;
Упражнение 1. Добавьте в приложение кнопку выхода из программы.
Упражнение 2. Модифицируйте программу так, чтобы она завершала работу после нажатия клавиш.
Варианты:
а) “A” б) “S”
37

в) |
“F” |
г) |
“Alt”+“X” |
д) |
“Alt”+“C” |
е) |
“Alt”+“V” |
ж) |
“Shift”+“X” |
з) |
“Shift”+“C” |
Часть 2. Двумерный динамический массив. Дружественные функции.
Созданиедвухмерногодинамическогомассива
Учитывая тот факт, что имя двухмерного массива - это указатель на указатель int **m; двухмерный динамический массив создается и уничтожается за два шага. Например, требуется создать целочисленный массив m[3][4]:
m = new int* [3]; |
// Захват памяти дляуказателей - рис. а |
for (int i=0; i<3; i++) |
// Захват памяти для элементов - рис. б |
m[i] =new int [4]; |
|
for (i=0; i<3; i++) |
// Обработкаэлементов, напримеробнуление |
for (j=0; i<4; j++) |
|
m[i][j]=0; |
//или *(*(m+i)+j) = 0; |
… |
|
for (i=0; i<3; i++) |
// Освобождениепамяти, занятойподэлементы |
delete []m[i]; |
|
delete []m; |
// Освобождениепамяти, занятойподуказатели |
Вдинамическойпамятибыласозданатакаяконструкция:
Рис. 4.2. Схема размещения двухмерного массива в памяти а) размещение указателей, б – размещение элементов.
Участокпрограммы, вкоторомдлясозданиядвухмерногодинамическогомассива используютсябиблиотечныефункции:
int **a;
puts(“\n Input n,m: “); scanf(“%d %d”, &n, &m);
a=(int**)calloc(n, sizeof(int*)); //Захватпамяти for(i=0;i<n;i++)
a[i]=(int*)calloc(m, sizeof(int));
…
for (i=0;i<n;i++) free(a[i]); |
// Освобождениепамяти |
free(a);
…
Краткая характеристика функции-друга класса
Механизм «функции-друга» класса обеспечивает возможность доступа к любым элементам класса тем функциям, которые не входят в состав этого класса. То есть функция-друг класса - это обычная функция пользователя, которая благодаря данному механизму имеет полные права доступа
38
ко всем без исключения элементам класса, независимо от их степени защищенности. Чтобы обычная функциясталадругом класса, взаголовке еенеобходимоуказатьfriend.
Некоторыеособенности:
1 . Функциюдруга класса необходимо декларировать в описании этого класса. Декларация возможнавдвухформах:
-в форме описания (приводится прототип), а ее полное определение – вне шаблона класса, при этом не нужно указывать операцию привязки к данному классу, т.к. онанеявляетсячленом данного класса;
-в форме полного определения, в шаблоне класса приводится ее полный текст.
2.Приобращениикфункциидругуненадоиспользоватьоперациюпривязки(.) или(-
>).
3. Так как функция-друг - обычная функция, у нее отсутствует первый скрытый параметрthis.
Для обращения элементам класса из функции-друга используют или ссылку, или указатель, чтоииллюстрируетследующийпример:
class X {
int a, b; public:
void Print(void);
friend void f1Set (X &); friend void f2Set (X *); void X :: Print (void) {
cout « " a = " « a « " b = " « b « endl;
}
// flSet() иf2Set() - обычные функции, поэтому операцияпривязкиненужна void f1Set (X &r) {
r.a=l;r.b = 2;
}
void fZSet (X *p) { p -> a = 3; r -> b = 4;
}
}
void main(void) {
X xl; // Установили значение flSet(xl); xl.Print(); f2Set(&xl); xl.Print();
}
Отметим, что функции-друзья класса кроме ссылки или указателя на объекты класса могут иметь обычные параметры, например для инициализации данных объектов класса. Например, функция-друг класса X f2Set() может иметь следующий вид:
void f2Set (X *р, int i, int j) { p -> a = i; r->b =j;
} |
|
а обращение к ней: |
f2Set (&xl, 5, 6); |
Упражнение 3. Пользовательский класс Array должен содержать конструктор с параметрами для создания динамических целочисленных массивов (операция new или стандартная библиотечная функция calloc) и установки начальных значений их элементов: Array(…) (реальные размеры массива – число строк и столбцов передается в конструктор через параметры);
Конструктор: X(…); Деструктор: ~X( );
39
Метод печати текущего состояния массива: |
void Print(…);, |
Метод переустановки текущего состояния массива: |
void Set(...); |
Функция-друг, решающая поставленную задачу: |
friend void Run(...); |
Код методов и функции-друга – вне пространства определения класса. Программа иллюстрирует косвенный способ обращения к элементам массива.
Варианты: составить функцию Run, которая позволит выполнить следующие действия с двухмерными массивами:
а) Определить сумму элементов в тех строках, которые не содержат отрицательных элементов.
б) Определить количество строк, содержащих хотя бы один нулевой элемент. в) Определить номер первой из строк, не содержащих ни одного положительного
элемента.
г) Определить номер первого из столбцов, не содержащих ни одного отрицательного элемента.
д) Определить номер первого из столбцов, содержащих хотя бы один положительный
элемент
е) Определить номер первой из строк, содержащих хотя бы один положительный
элемент.
ж) Определить количество строк, среднее арифметическое элементов которые меньше заданной величины.
з) Найти сумму модулей элементов, расположенных выше главной диагонали.
Контрольные вопросы.
1)Перечислите сообщения, посылаемые клавиатурой.
2)Опишите параметры функции itoa(…).
3)Опишите параметры функции OnKeyDown(…).
4)Как определить программно, какая была нажата клавиша?
5)Как определить программно что была нажата комбинация клавиш Alt+, Shift+.
6)Чем является имя двумерного массива?
7)Как косвенно обратиться к элементу двумерного массива?
8)Объясните понятие “функция-друг” класса?
9)Какие существуют способы обращения к элементам класса из функции-друга?
10)Как освободить память, занимаемую двумерным динамическим массивом?
Лабораторная работа №5.
Работа с меню. Работа с динамической строкой и перегрузка операций.
Цель работы, изучить методику по созданию одномерных динамических символьных массивов при помощи конструкторов с захватом динамической памяти и деструкторов для их уничтожения, а также способа работы со строковыми объектами. Познакомиться с механизмом перегрузки операций.
Часть 1. Среда разработки Microsoft Visual C++ 6.0. Работа с меню.
1.Создание нового проекта
Для изучения элементов управления Microsoft Visual C++ 6.0 создадим лабораторную программу, выполняющую следующие действия:
•Программа Speed основана на диалоговом окне с меню: File и Help, в середине главного окна, расположено окно редактирования, в котором можно вводить только числа, а, если
40