Заглавная страница Избранные статьи Случайная статья Познавательные статьи Новые добавления Обратная связь FAQ Написать работу КАТЕГОРИИ: АрхеологияБиология Генетика География Информатика История Логика Маркетинг Математика Менеджмент Механика Педагогика Религия Социология Технологии Физика Философия Финансы Химия Экология ТОП 10 на сайте Приготовление дезинфицирующих растворов различной концентрацииТехника нижней прямой подачи мяча. Франко-прусская война (причины и последствия) Организация работы процедурного кабинета Смысловое и механическое запоминание, их место и роль в усвоении знаний Коммуникативные барьеры и пути их преодоления Обработка изделий медицинского назначения многократного применения Образцы текста публицистического стиля Четыре типа изменения баланса Задачи с ответами для Всероссийской олимпиады по праву Мы поможем в написании ваших работ! ЗНАЕТЕ ЛИ ВЫ?
Влияние общества на человека
Приготовление дезинфицирующих растворов различной концентрации Практические работы по географии для 6 класса Организация работы процедурного кабинета Изменения в неживой природе осенью Уборка процедурного кабинета Сольфеджио. Все правила по сольфеджио Балочные системы. Определение реакций опор и моментов защемления |
Использование пользовательских событий в программах↑ ⇐ ПредыдущаяСтр 4 из 4 Содержание книги
Поиск на нашем сайте
Для организации событийного управления объектами, определенными пользователями необходимо: 1. Объявить делегат. 2. Создать класс-издатель, содержащий: – событие, соответствующее объявленному делегату; – метод, включающий логику порождения этого события и собственно его генерацию. 3. Определить функции обработки данного события со списком параметров и типом возвращаемого значения, определенными делегатом (определения этих функций можно разместить внутри некоторого класса). 4. Создать объект класса, содержащего объявление события, а затем выполнить подписку на это событие и связать его с функцией-обработчиком.
Пример 14.18. Комплексное использование различных членов класса и событий, определенных пользователем.
#include "stdafx.h" using namespace System; // Объявление делегатов public delegate void NameChangedHandler(String^ NewName); public delegate void AgeChangedHandler(short NewAge); public ref class Human { // Определение класса Human private: String^ HumanName; // Определение поля Имя short HumanAge; // Определение поля Возраст public: Human () { HumanName = ""; HumanAge = 0; } // Конструктор // Объявление событий смены имени и возраста event NameChangedHandler^ NameChanged; event AgeChangedHandler^ AgeChanged; property String ^ Name { // Определение свойства Имя String ^ get () { return HumanName; // Возврат значения, хранимого в поле } void set(String^ value) { HumanName = value; // Сохранение значения в поле NameChanged (value); // Порождение события смены имени } } property short Age { // Определение свойства Возраст short get () { return HumanAge; // Возврат значения, хранимого в поле } void set(short value) { if (value < 0 || value > 200) { // Вывод сообщения об ошибке изменения возраста Console:: WriteLine ("Возраст должен быть между " + "0 и 200 годами"); } else if (HumanAge!= value) { HumanAge = value; // Сохранение значения в поле // Порождение события смены возраста AgeChanged (value); } } } void OutputName () { // Определение метода вывода имени Console:: WriteLine ("ФИО: {0}", HumanName); } }; public ref class OutputHumanData { // Определение класса public: void NameChanged(String^ name) { // Обработка события смены имени Console:: WriteLine ("Имя изменено на {0}", name); } void AgeChanged (short age) { // Обработка события смены возраста Console:: WriteLine ("Возраст изменен на {0}", age); } }; int main () { Human ^ h = gcnew Human; // Создание объекта класса Human OutputHumanData ^ ohd = gcnew OutputHumanData; // Создание объекта класса OutputHumanData // Подписка на события и определение функций-обработчиков h->NameChanged += gcnew NameChangedHandler(ohd, &OutputHumanData::NameChanged); h->AgeChanged += gcnew AgeChangedHandler(ohd, &OutputHumanData::AgeChanged); Console::WriteLine(" Имя: {0}, возраст: {1}", h->Name, h->Age); // Вывод имени и возраста (исходные значения) h -> Name = "Иванов А.П."; // Изменение имени. Вызывает // обработку события изменения имени h -> OutputName (); // Вывод имени h -> Age = 25; // Изменение возраста. Вызывает // обработку события изменения возраста Console:: WriteLine ("Возраст: {0}", h -> Age); // Вывод возраста h -> Age = 25; // Не вызывает обработку события, // т.к. возраст не изменился h->Age = -20; // Не вызывает обработку события, // т.к. возраст не может быть // отрицательным. Выводит сообщение Console:: WriteLine ("Возраст: {0}", h -> Age); // Вывод возраста. Результат не изменен Console:: ReadLine (); return 0; } /* Вывод: Имя:, возраст: 0 Имя изменено на Иванов А.П. ФИО: Иванов А.П. Возраст изменен на 25 Возраст: 25 Возраст должен быть между 0 и 200 годами Возраст: 25 */
Функции, объявленные в классе OutputHumanData и являющиеся обработчиками событий, могут и не входить в этот класс, а объявляться в области видимости файла вместе с основной функцией main(). В этом случае внутри функции main() не нужно объявлять объект класса, который должен был содержать функции-обработчики. Вследствие этого в операторе добавления делегату функции-обработчика этот делегат будет иметь только один параметр, которым является имя функции обработки соответствующего события. Например:
h->NameChanged += gcnew NameChangedHandler(NameChanged); h->AgeChanged += gcnew AgeChangedHandler(AgeChanged);
Пример 14.19. Предположим, нужно определить класс, в котором имеется метод, считающий от 0 до 100. Но когда счетчик досчитает, например, до 69 функция-обработчик этого события должна вывести на экран сообщение «Пора действовать, уже 69!».
#include "stdafx.h" using namespace System; public ref class ClassCounter { // Определение класса-издателя public: // Объявление делегата внутри класса-издателя delegate void MethodContainer (); // Объявление события OnCount c типом делегата MethodContainer event MethodContainer^ OnCount; void Count() { // Метод, инициирующий событие for (int i = 0; i <= 100; i++) { // Счет до 100 if (i == 69) { // Если i = 69, то... OnCount (); // Порождение события } } Console:: WriteLine ("Счет завершен!"); } }; void Message () { // функция-обработчик события Console:: WriteLine ("Пора действовать, уже 69!"); // Сообщение } int main() { ClassCounter^ counter = gcnew ClassCounter; // Создание объекта класса ClassCounter // Подписка на событие и определение функции-обработчика counter->OnCount += gcnew ClassCounter::MethodContainer(Message); counter->Count(); // Запуск счетчика до 100 Console::ReadLine(); return 0; } /* Вывод: Пора действовать, уже 69! Счет завершен! */
Наследование
Одиночное наследование Пример 14.20. Создание иерархии классов при наследовании.
#include "stdafx.h" using namespace System; class A { // Базовый класс public: void func1() { Console::WriteLine("A::func1()"); } // Метод }; class B: public A { // Класс B наследуется от класса A public: void func2() { Console::WriteLine("B::func2()"); } // Метод }; class C: public B { // Класс С наследуется от классов А и B public: void func3() { Console::WriteLine("C::func3()"); } // Метод }; int main () { C c; // Создание экземпляра класса C c.func1(); // Вывод: A::func1() c.func2(); // Вывод: B::func2() c.func3(); // Вывод: C::func3() Console:: ReadLine (); return 0; }
При наследовании используется следующий формат объявления класса:
class <Производный_класс: [<Спецификатор_доступа>] <Базовый_класс { <Объявления_членов_класса>; } [<Объявления_переменных_через_запятую>];
В параметре <Спецификатор_доступа> можно указать следующие спецификаторы: public – открытое наследование. Все открытые и защищенные члены базового класса становятся соответственно открытыми и защищенными членами производного класса; private – закрытое наследование. Все открытые и защищенные члены базового класса становятся закрытыми членами производного класса; protected – защищенное наследование. Все открытые и защищенные члены базового класса становятся защищенными членами производного класса.
При использовании закрытого наследования можно изменить уровень доступа некоторых открытых и защищенных членов базового класса. Сделать это можно двумя способами:
<Базовый_класс>::<Член_класса>; using <Базовый_класс>::<Член_класса>;
Пример 14.21. Изменение уровня доступа отдельных членов класса при закрытом наследовании.
#include "stdafx.h" using namespace System; class A { // Базовый класс public: void func1() { Console::WriteLine("A::func1()"); } void func2() { Console::WriteLine("A::func2()"); } void func3() { Console::WriteLine("A::func3()"); } }; class B: private A { // Закрытое наследование класса public: A::func2; // Открываем доступ к func 2() using A::func3; // Открываем доступ к func 3() void func4() { func1(); } }; int main() { B obj; // obj.func1(); // Ошибка. Метод func 1() – закрытый член класса obj. func 2(); // Вывод: A:: func 2() obj.func3(); // Вывод: A::func3() obj.func4(); // Вывод: A::func1(). Вызов метода func 1() // из B:: func 4() Console:: ReadLine (); return 0; }
Для передачи параметров конструкторам базовых классов используется следующий синтаксис:
<Название_конструктора_производного_класса>(<Параметры>): <Название_конструктора_базового_класса>(<Значения>) { // Тело конструктора }
Пример 14.22. Переопределение метода при наследовании класса.
#include "stdafx.h" using namespace System; class A { // Базовый класс public: void func1() { Console::WriteLine("A::func1()"); } // Метод void func2() { Console::WriteLine("A::func2()"); } // Метод }; class B: public A { // Класс B наследуется от класса A public: void func2() { Console::WriteLine("B::func2()"); } // Переопределенный метод void func3() { Console::WriteLine("B::func3()"); } // Метод }; int main () { B b; // Создание экземпляра класса B b. func 1(); // Вызов унаследованного метода func 1() b. func 2(); // Вызов переопределенного метода func 2() b. func 3(); // Вызов добавленного в класс метода func 3() Console::ReadLine(); return 0; } /* Вывод: Вывод: A::func1() Вывод: B::func2() Вывод: B::func3() */
Для указания, что класс не может использоваться в качестве базового класса, применяется ключевое слово sealed в объявлении класса. Например:
public sealed class A {}
Указание, что класс может использоваться только в качестве базового класса и нельзя создать экземпляр этого класса, можно записать следующим образом:
public abstract class B {}
Использование конструкторов и деструкторов при наследовании. Пример 14.23. Порядок вызова конструкторов и деструкторов, а также передача значений конструкторам базовых классов.
#include "stdafx.h" using namespace System; class A { // Базовый класс public: int x; A(int a) { // Конструктор x = a; Console::WriteLine("A::A()"); } ~A() { Console::WriteLine("A::~A()"); } // Деструктор }; class B: public A { // Класс B наследуется от класса A public: int y; B (int a, int b): A (b) { // Конструктор y = a; Console:: WriteLine (" B:: B ()"); } ~ B () { Console:: WriteLine (" B::~ B ()"); } // Деструктор }; class C: public B { // Класс C наследуется от классов A и B public: int z; C (int a, int b, int с): B (b, с) { // Конструктор z = a; Console:: WriteLine (" C:: C ()"); } ~ C () { Console:: WriteLine (" C::~ C ()"); } // Деструктор }; int main () { C obj (10, 20, 30); Console:: WriteLine (" A:: x = {0} B:: y = {1} C:: z = {2}", obj. x, obj. y, obj. z); Console:: ReadLine (); return 0; } /* Вывод (для просмотра после вывода нажмите < Ctrl + F 5>): A::A() B::B() C::C() A::x = 30 B::y = 20 C::z = 10 C::~ C () B::~ B () A::~ A () */
Множественное наследование При множественном наследовании используется следующий формат объявления производного класса:
class <Производный_класс>: [<Спецификатор_доступа>] <Базовый_класс1>, [<Спецнфнкатор_доступа>] <Базовый_класс2>, ..., [<Спецификатор_доступа>] <Базовый_класс N > { <Объявления_членов_класса>; } [<Объявления_переменных_через_запятую>];
Для передачи параметров конструкторам базовых классов используется следующий синтаксис:
<Название_конструктора_производного_класса>(<Параметры>): <Название_конструктора_базового_класса1>(<Значения>), <Название_конструктора_базового_класса2>(<3начения>), ..., <Название_конструктора_базового_класса3>(<Значения>) { // Тело конструктора }
Пример 14.24. Порядок вызова конструкторов и деструкторов при множественном наследовании, а также передача значений конструкторам базовых классов.
#include "stdafx.h" using namespace System; class A { // Базовый класс public: int x; A(int a) { // Конструктор x = a; Console::WriteLine("A::A()"); } ~A() { Console::WriteLine("A::~A()"); } // Деструктор void func1() { Console::WriteLine("A::func1()"); } // Метод }; class B { // Базовый класс public: int y; B(int a) { // Конструктор y = a; Console::WriteLine("B::B()"); } ~B() { Console::WriteLine("B::~B()"); } // Де структор void func2() { Console::WriteLine("B::func2()"); } // Метод }; class C: public A, public B { // Класс C наследуется от классов A и B public: int z; C (int a, int b, int c): A (b), B (c) { // Передаем значения z = a; Console:: WriteLine (" C:: C ()"); } ~ C () { Console:: WriteLine (" C::~ C ()"); } // Деструктор }; int main () { C obj (10, 20, 30); obj. func 1(); obj. func 2(); Console:: WriteLine (" A:: x = {0} B:: y = {1} C:: z = {2}", obj. x, obj. y, obj. z); Console:: ReadLine (); return 0; } /* Вывод (для просмотра после вывода нажмите < Ctrl + F 5>): A::A() B::B() C::C() A::func1() B::func2() A::x = 20 B::y = 30 C::z = 10 C::~ C () B::~ B () A::~ A () */
Пример 14.25. Неоднозначность при множественном наследовании.
#include "stdafx.h" using namespace System; class A { // Базовый класс public: void func1() { Console::WriteLine("A::func1()"); } // Метод }; class B: public A { // Класс B наследуется от класса A public: void func2() { Console::WriteLine("B::func2()"); } // Метод }; class C: public A { // Класс C наследуется от класса A public: void func3() { Console::WriteLine("C::func3()"); } // Метод }; class D: public B, public C { // Класс D наследуется от классов public: // A, B и C }; int main() { D obj; // obj.func1(); // Неоднозначность. Из B или из C? obj.B::func1(); // Берем из класса B obj.C::func1(); // Берем из класса C obj.func2(); // Однозначно obj.func3(); // Однозначно Console::ReadLine(); return 0; } /* Вывод: A::func1() A::func1() B::func2() C::func3() */
Один из способов разрешения неоднозначности является явное указание класса и оператора :: перед названием метода при вызове:
|
||||
Последнее изменение этой страницы: 2019-05-20; просмотров: 168; Нарушение авторского права страницы; Мы поможем в написании вашей работы! infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 18.227.46.202 (0.007 с.) |