Середня вага тварин заданого виду в зоопарку

35. Середня водотоннажність усіх вітрильників на верфі (у порту).

Лабораторна робота №4.

Обробка подій.

Мета. Одержати практичні навички розробки об’єктно-орієнтованої програми, що керується подіями.

Короткі теоретичні відомості.

· Об’єктно-орієнтована програма як програма, що керується подіями.

При використанні ООП всі об'єкти є в деякому змісті відособленими один від одного і виникають визначені труднощі в передачі інформації від об'єкта до об'єкта. В ООП для передачі інформації між об'єктами використовується механізм обробки подій.

Події найкраще уявити собі як пакети інформації, якими обмінюються об'єкти і які створюються об’єктно-орієнтованим середовищем у відповідь на ті чи інші дії користувача. Натискання на клавішу чи маніпуляція мишею породжує подію, що передається по ланцюжку об'єктів, поки не знайдеться об'єкт, що знає як обробляти цю подію. Для того, що б подія могла передаватися від об'єкта до об'єкта, всі об'єкти програми повинні бути об'єднані в групу. Звідси випливає, що прикладна програма повинна бути об'єктом-групою, у яку повинні бути включені всі об'єкти, які використовуються в програмі.

Таким чином об’єктно-орієнтована програма – це програма, що керується подіями. Події самі по собі не роблять ніяких дій у програмі, але у відповідь на подію можуть створюватися нові об'єкти, модифікуватися чи знищуватися існуючі, що і приводить до зміни стану програми. Іншими словами всі дії по обробці даних реалізуються об'єктами, а події лише керують їхньою роботою.

Принцип незалежності обробки від процесу створення об'єктів приводить до появи двох паралельних процесів у рамках однієї програми: процесу створення об'єктів і процесу обробки даних.

Це означає, що дії по створенню, наприклад, інтерактивних елементів програми (вікон, меню й ін.) можна здійснювати, не піклуючись про дії користувача, що будуть зв'язані з ними.

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

· Подія.

Подія з погляду мови С++ – це об'єкт, окремі поля якого характеризують ті чи інші властивості переданої інформації, наприклад:

struct TEvent

{int what

union{

MouseEventType mouse;

KeyDownEvent keyDown;

MessageEvent message;

};

Об'єкт TEvent складається з двох частин. Перша (what) задає тип події, що визначає джерело даної події. Друга задає інформацію, передану з подією. Для різних типів подій зміст інформації різний . Поле what може приймати наступні значення:

evNothing– це порожня подія, яка означає, що нічого робити не треба. Полю what привласнюється значення evNothing, коли подія оброблена яким -небудь об'єктом.

evMouse – подія від “миші”.

Подія від “миші” може мати, наприклад, таку структуру:

struct MouseEventType

{int buttons;

int doubleClick;

TPoint where;

};

де buttons вказує натиснуту клавішу;

doubleClick вказує чи був подвійний щиглик;

where вказує координати “миші”.

evKeyDown -подія від клавіатури.

Подія від клавіатури може мати, наприклад, таку структуру:

struct KeyDownEvent

{union{int keyCode;

union{char charCode;

char scanCode;

};

};

};

evMessage- подія-повідомлення від об'єкта.

Для події від об'єкта (evMessage) задаються два параметри :

command – код команди, яку необхідно виконати з появою даної події;

infoPtr – передається з подією (повідомлення) інформація.

struct MessageEvent

{int command;

void infoPtr;

};

· Методи обробки подій.

Наступні методи необхідні для організації обробки подій(назви довільні).

GetEvent – формування події;

Execute – реалізує головний цикл обробки подій. Він постійно одержує подію шляхом виклику GetEvent і обробляє їх за допомогою HandleEvent. Цей цикл завершується, коли надійде подія “кінець”.

HandleEvent – оброблювач подій. Обробляє кожну подію потрібним для нього чином. Якщо об'єкт повинен обробляти визначену подію (повідомлення), то його метод HandleEvent повинен розпізнавати цю подію і реагувати на неї належним чином. Подія може розпізнаватися, наприклад, по коду команди (поле command).

ClearEvent – очищає подію, коли вона оброблена, щоб вона не оброблялася далі.

· Оброблювач подій (метод HandleEvent)

Одержавши подію (структуру типу TEvent) оброблювач подій для класу TDerivedClass обробляє його за наступною схемою:

void TDerivedClass::HandleEvent(TEvent& event)

{ //Виклик оброблювача подій базового класу

TBaseClass::handleEvent( event );

if( event.what == evCommand ) // Якщо оброблювач подій базового класу

// подію не обробив

{

switch( event.message.command )

{

case cmCommand1:

// Обробка команди cmCommand1

// Очищення події

СlearEvent( event );

break;

case cmCommand2:

// Обробка команди cmCommand2

СlearEvent( event );

break;

case cmCommandN:

// Обробка команди cmCommand

СlearEvent( event );

break;

default: // подія не оброблена

break;

}

};

}

Оброблювач подій групи спочатку обробляє команди групи, а потім, якщо подія не оброблена, передає його своїм елементам, викликаючи їх оброблювачі подій.

void TGroup::HandleEvent(TEvent& event)

{ if( event.what == evCommand )

{switch( event.message.command )

// обробка подій об'єкта-групи

default: // подія не оброблена групою

//одержати доступ до першого елемента групи

while((event.what != evNothing)!!( /* переглянуті не всі елементи */)

{

//викликати HandleEvent поточного елемента

//перейти до наступного елементу групи

}

break;

}

}

· Метод ClearEvent-очищення події.

ClearEvent очищає подію, привласнюючи полю event.What значення evNothing.

· Головний цикл обробки подій (метод Execute)

Головний цикл обробки подій реалізується в методі Execute головної групи – об'єкта “прикладна програма” за наступною схемою:

int TMyApp::Execute()

{do{endState=0;

GetEvent(event); //одержати подію

HandleEvent(event); //обробити подію

if(event.what!=evNothing) //подія залишилася не обробленою

EventError(event);

}

while(!Valid());

return endState;

}

Метод HandleEvent програми обробляє подію “кінець роботи”, викликаючи метод EndExec. EndExec змінює значення private – змінної EndState. Значення цієї змінної перевіряє метод – функція Valid, що повертає значення true, якщо “кінець роботи”. Такий трохи складний спосіб завершення роботи програми зв'язаний з тим, що в активному стані можуть знаходитися кілька елементів групи. Тоді метод Valid групи, викликаючи методи Valid своїх піделементів, поверне true, якщо усі вони повернуть true. Це гарантує, що програма завершить свою роботу, коли завершать роботу всі її елементи.

Якщо подія залишилася не обробленим, то викликається метод EventError, що у найпростішому випадку може просто видати повідомлення.

· Приклад обробки подій.

Розглянемо найпростіший калькулятор, що сприймає команди в командному рядку. Тут приводиться спрощений варіант. Варіант, за схемою якого варто виконати лабораторну роботу, приведений у Додатку.

Формат команди:

знак параметр

Знаки +, –, *, /, =, ?, q

Параметр – ціле число

Константи-команди:

сonst int evNothing = 0;

сonst int evMessage = 100;

сonst int cmSet = 1; //занести число

сonst int cmGet = 2; //подивитися значення

сonst int cmAdd = 3; //додати

і т.д.

сonst int cmQuit = 101; //вихід

Клас-подія

struct TEvent

{int what

union{

int evNothing;

union{int command;

int a;}

}

}

Об'єкт-калькулятор, що працює з цілими числами

class TInt{

int EndState;

public

int x;

Int(int x1);

virtual ~Int();

virtual void GetEvent (TEvent &event);

virtual int Exicute();

virtual void HandleEvent (TEvent& event);

virtual void ClearEvent (TEvent& event);

int Valid();

void EndExec();

int GetX();

void SetX (int newX);

void AddY (int Y);

};

Розглянемо можливу реалізацію основних методів.

void TInit::GetEvent(TEvent &event)

{char* OpInt = “+-*/=?q”; //рядок містить коди операцій

char s[20];

char code;

cout<<‘>’;

cin>>s; code = s[1];

if(Test(char code,char*OpInt) //Функції Test перевіряє, чи входить символ

//code у рядок OpInt

{event.what = evMessage;

swith(code)

{case ‘+’: event.command=cmAdd;

break;

case‘q’: event.command = cmQuit;

break;

}

//виділити другий параметр, перевести його в тип int і привласнити полю A

};

else event.what= evNothing

};

 

int TMyApp::Execute()

{do{endState=0;

GetEvent(event); //одержати подію.

HandleEvent(event); //обробити подію.

if(event.what!=evNothing) //подія залишилася не обробленою.

while(!Valid());

return endState;

}

void TInt::HandleEvent(TEvent& event)

{

if( event.what == evMessage)

{

switch( event.message.command )

{

case cmAdd:Add(event.A);

СlearEvent( event );

break;

case cmQuit:EndExec();

СlearEvent( event );

break;

};

};

}

int TInt::Valid();

{ if (EndState == 0) return 0;

else return 1;

}

void TInt::ClearEvent(TEvent& event)

{

Event. what:= evNothing;

}

void TInt::EndExec()

{

EndState= 1;

}

void TInt::AddY(int Y)

{

x+=Y;

і т.д.

void main()

{

TInt MyApp;

MyApp.Execute();

}

Основний зміст роботи.

Написати інтерактивну програму, що виконує команди, що вводяться користувачем із клавіатури.

Порядок виконання роботи.

1.Розібрати приклад, представлений у ДОДАТКУ. Відповісти на наступні питання:

а) Яка тут ієрархія класів?

б) Яка тут ієрархія об'єктів?

в) Як КАЛЬКУЛЯТОРУ передаються аргументи операції? Де вони зберігаються? Яким чином одержують до них доступ пристрої ДОДАВАННЯ, ВІДНІМАННЯ і т.д. ?

г) Як обробляються події групою?

д) Які всі маршрути події TEvent?

е) Як виконуються HandleEvent усіх класів?

2.Вибрати групу об'єктів, що будуть обробляти події (це не можуть бути об'єкти, приведені в додатку).

3.Для обраної групи об'єктів визначити перелік операцій, що повинні виконуватися по командах користувача.

4.Визначити вид командного рядка <код_операції><параметри>. Вирішити питання:

Як кодуються операції? Які передаються параметри?

5.Визначити ієрархію об'єктів. Якщо необхідно, додати нові об'єкти (групи об'єктів).

6.Визначити ієрархію класів. Якщо необхідно, додати нові класи.

7.Визначити який об'єкт у програмі відіграє роль додатка. У разі потреби додати в ієрархію класів клас TApp. Вирішити в якому класі буде метод Execute, що організує головний цикл обробки подій.

8.Визначити і реалізувати необхідні для обробки подій методи.

9.Написати основну функцію(main).

Методичні вказівки.

1.Як групу, для якої організується обробка подій вибрати групу з лабораторної роботи №3.

2.Кількість різних оброблюваних команд повинне бути не менш 5.

2.Визначення класів помістити у файл *.h. Визначення функцій – членів класу помістити у файл *.cpp.

3.Для констант, зв'язаних з командами, використовувати мнемонічні імена cmXXXX.

Зміст звіту.

1.Титульний лист.

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

3.Схема ієрархії класів.

4.Схема ієрархії об'єктів.

5.Опис маршруту, що проходить подія TEvent від формування до очищення.

6.Визначення класів.

7.Реалізація методів обробки подій GetEvent, Exicute, EndExec, Valid.

8.Реалізація всіх методів(для всіх класів) HandleEvent.

9.Лістінг функції main().

Додаток.

Об'єкт КАЛЬКУЛЯТОР виконує додавання, вирахування, множення, розподіл дійсних чисел.

Ієрархія об'єктів

У прикладі приведені визначення основних класів і типів і реалізації тільки деяких компонентних функцій.

class TShema;

class TObject //абстрактий клас- стоїть на чолі ієрархії класів

{protected:

TShema* owner;

public:

TObject();

~TObject();

virtual void HandleEvent(TEvent&);

virtual void ClearEvent(TEvent&);

};

class TShema::public TObject // абстрактна група

{protected:

TItem* last;

public:

TShema();

~TShema();

virtual void Insert(TObject*);

virtual void HandleEvent(TEvent&);

};

class TDevice: public TShema // абстрактний пристрій керування

{protected:

int EndState;

public:

virtual void GetEvent(TEvent&);

virtual void Execute();

virtual int Valid();

virtual void EndExec();

};

classTRec: public TObject // пристрій для збереження даних - регістр

{protected:

float x;

public:

TReg();

~TReg();

float GetX();

void Set(float&);

};

class TCalc : public TDevice //калькулятор

{pritected:

TReg* sum; // покажчик на суматор

TReg* reg; // покажчик на регістр

public:

TCalc();

void HamdleEvent(TEvent&);

void GetEvent(TEvent&);

void Execute();

float GetSum(); // одержати значення суматора

void PutSum(float); //занести число в суматор

voit Help();

};

class TAdd : public TObject // схема додавання

{public:

void HandleEvent(TEvent&);

void Add();

};

TObject::TObject()

{owner=0;}

TShema::TShema()

{last=0;}

TCalc::TCalc()

{TObject* r;

sum=new TReg;

reg=new TReg;

r=new TAdd;

Insert(sum);

// і так далі для всіх схем

};

TCalc::HandleEvent(TEvent& event)

{if(event.what==evMessage)

switch(event.command)

{cmQuit:

EndExec();

ClearEvent(event);

break;

cmGet:

cout<<GetSum()<<endl;

ClearEvent(event);

break;

cmSet:

PutSum(event.A);

ClearEvent(event);

break;

default:

TSheme::HandleEvent(event);

} }

TSheme::HandleEvent(TEvent&event)

{TItem* r;

if(event.what==evMassage)

{r=last;

while(event.what!=evNothing&&r!=0)

{r->HandleEvent(event);

r=r->next;}

} }

TAdd::HandleEvent(TEvent&event)

{if(event.what==evMessage)

switch(event.command)

{cmAdd:

//занести в регістр число

(owner->reg)->Set(event.A);

//викликати метод додавання

Add();

ClearEvent(event);

break;

} }

TAdd::Add() //у суматор додати вміст регістра

{float a,b;

//одержати значення суматора

a=(owner->sum)->Get();

//одержати значення регістра

b=(owner->reg)->Get();

//змінити значення суматора

(owner->sum)->SetX(a+b);

}

Лабораторна робота №5.

Перевантаження операцій.

Мета.Одержати практичні навички роботи в середовищі BC++5.02 і створення EasyWin програми. Одержати практичні навички створення абстрактних типів даних і перевантаження операцій у мові С++.

Основний зміст роботи.

Визначити і реалізувати клас — абстрактний тип даних. Визначити і реалізувати операції над даними цього класу. Написати і виконати EasyWin програму повного тестування цього класу.

Короткі теоретичні відомості.