Заглавная страница Избранные статьи Случайная статья Познавательные статьи Новые добавления Обратная связь FAQ Написать работу КАТЕГОРИИ: ТОП 10 на сайте Приготовление дезинфицирующих растворов различной концентрацииТехника нижней прямой подачи мяча. Франко-прусская война (причины и последствия) Организация работы процедурного кабинета Смысловое и механическое запоминание, их место и роль в усвоении знаний Коммуникативные барьеры и пути их преодоления Обработка изделий медицинского назначения многократного применения Образцы текста публицистического стиля Четыре типа изменения баланса Задачи с ответами для Всероссийской олимпиады по праву
Мы поможем в написании ваших работ! ЗНАЕТЕ ЛИ ВЫ?
Влияние общества на человека
Приготовление дезинфицирующих растворов различной концентрации Практические работы по географии для 6 класса Организация работы процедурного кабинета Изменения в неживой природе осенью Уборка процедурного кабинета Сольфеджио. Все правила по сольфеджио Балочные системы. Определение реакций опор и моментов защемления |
Использование пользовательских событий в программахСодержание книги
Поиск на нашем сайте
Для организации событийного управления объектами, определенными пользователями необходимо: 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; просмотров: 215; Нарушение авторского права страницы; Мы поможем в написании вашей работы! infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 216.73.217.21 (0.009 с.) |