Структура событийно-управляемой программы для платформы Win32
Рассмотрим механизм на примере двух потоков. В каждом из таких потоков работают по одному “циклу выборки сообщений”. Код таких циклов на С++ приведен ниже:
While (GetMessage(…)) {
TranslateMessage(…);
DispatchMessage(…); // определяем, кому и как передать сообщение
}
Функция GetMessage в качестве параметров передает структуру, в которой хранится идентификатор сообщения, его название, дата и время, а так же другие данные. Метод DispatchMessage направляет сообщение тому окну, которое активно и над кем происходит событие.
Каждый запущенный поток, по мимо цикла, имеет в распоряжении собственную очередь сообщений. В такую очередь сообщения сыпаться из общей очереди, называемой – “сырая” (RIT, Raw Input Thread).
Механизм функционирует следующим образом: пользователь вызывает события, например, щелчок левой клавиши мыши. Задачи системы, отреагировать на это, и выработать управляющее воздействие. Событие обрабатывает ОС Windows. Далее, она помещает ее в очередь RIT, откуда сообщение рассылается в очереди всех активных потоков. Цикл выборки сообщений считывает его из очереди, и определяет адресата. Если это компонент формы Кнопка, то просмотреть, определен ли для него обработчик в программе. Если он переопределен, то передать ему управление (событие OnMouseClick). Замечание: цикл выборки сообщений работает, пока метод GetMessage возвращает true. В случае получения системного сообщения WM_CLOSE цикл завершается, связанный с ним поток – тоже.
12. Основные элементы объектно-ориентированных методов создания программных систем: абстрагирование, инкапсуляция, модульность, иерархия, типизация, параллелизм, устойчивость, полиморфизм. Понятие объектно-ориентированного программирования.
ООП – это методология программирования, основанная на представлении программы в виде совокупности объектов, каждый из которых является экземпляром определенного класса, а классы образуют иерархию наследования. В ООП выделяют три части: 1) базовые элементы являются объекты, а не алгоритмы; 2) каждый объект является экземпляром какого-либо определенного класса; 3) классы организованны иерархически. Программа будет ОО только при соблюдении всех трех условий.
Концептуальная база для ООП является – объектная модель. Она имеет 4 основных элемента: абстрагирование, инкапсуляция, модульность и иерархия. Кроме главных, имеются еще три дополнительных (не обязательных, но полезных в объектной модели): типизация, параллелизм и сохраняемость.
Абстрагирование выделяет существенные характеристики некоторого объекта, отличающие его от всех других видов объектов и, таким образом, четко определяет его концептуальные границы с точки зрения наблюдателя.
Существует целый спектр абстракций, начиная с объектов, которые почти точно соответствуют реалиям предметной области, и кончая объектами, не имеющими право на существование:
Абстракция сущности – объект представляет собой полезную модель, некой сущности в предметной области.
Абстракция поведения – объект состоит из обобщенного множества операций.
Произвольная абстракция – объект включает в себя набор операций, не имеющих друг с другом ничего общего.
Инкапсуляция – это процесс отделения друг от друга элементов объекта, определяющих его устройство и поведение; инкапсуляция служит для того, чтобы изолировать абстракцию от их реализации.
Модульность – это свойство системы, которая была разложена на внутренне связанные, но слабо связанные между собой модули. В ООП, под модульностью, понимается физическое разделение классов в группы, составляющие логические структуры проекта.
Иерархия – это упорядочение абстракций, расположение их по уровням. Принято делить иерархию на два способа: структура классов (иерархия «is-a») и структура объектов (иерархия «part of»). Рассмотрим каждый вариант.
Структура классов «is-a» есть наследование. Наследование означает такое отношение между классами (между родителем и потомком), когда один класс заимствует структурную и функциональную часть одного или нескольких других классов. Заимствование у одного класса есть одиночное наследование, у совокупности – множественное. Пример: картина «животного мира», выделение царств, классов и подклассов.
Структура объектов «part of» есть агрегация. Позволяет физически сгруппировать логически связанные структуры. Пример: устройство обогревателя, как совокупность устройств: греющий механизм, термодатчик, регулятор.
Типизация – это способ защититься от использования объектов одного класса вместо другого, или по крайне мере управлять таким использованием. Выделяют сильную, слабую типизацию и ее отсутствие.
Сильная типизация предполагает явно указывать допустимые операции над объектом, и декларирование механизмов взаимодействия с другими объектами. Слабая типизация предполагает частичное объявление списка допустимых операций, механизмов, и существование других способов взаимодействия с другими объектами. Как правило, большая часть таких механизмов представляется «по умолчанию». В некоторых ОО языках (например, Smalltalk) типов нет вообще. Во время исполнения любое сообщение может быть послано любому объекту, и если класс объекта не понимает сообщение, то генерируется сообщение об ошибке.
Параллелизм – это свойство, отличающее активные объекты от пассивных. ООП основано на абстракции, инкапсуляции и наследовании. Однако, параллелизм в ООП предполагает выделение таких свойств как абстрагирование и синхронизация процессов. Объект есть понятие, а следовательно, каждый объект (полученный из абстракции реального мира) может представлять собой отдельный поток управления (абстракция процесса). Такой объект называется активным. Для систем, построенных на основе OOП, мир может быть представлен, как совокупность взаимодействующих объектов, часть из которых является активной и выступает в роли независимых вычислительных центров.
Сохранаемость (устойчивость) – способность объекта существовать во времени, переживая породивший его процесс, и (или) в пространстве, перемещаясь из своего первоначального адресного пространства.
Полиморфизм – это механизм ОО подхода, в котором предполагается наличие в некоторый момент времени объекта, обозначающего (относящегося) к одному из классов. И у этих классов есть общий суперкласс и они, хотя и по разному, могут реагировать на одно и то же сообщение, одинаково понимая его смысл. Суть полиморфизма можно продемонстрировать на примере: суперкласс “Птица” (абстрактный). Для него определен чисто виртуальный метод “Летать”. От данного класса наследуют классы “Пингвин”, “Ласточка” и “Курица” – все потомки птицы, но каждый из таких классов по своему определит способ поведения “Летать”. Например, курица начнет бежать с бешенной скоростью, пингвин переваливаясь с одной ноги на другую, дойдет до края берега и в воду, а вот ласточка – полетит, оторвавшись от земли в небо.
13. Понятие объекта и класса. Свойства объекта: состояние, поведение, идентичность. Свойства класса: структура и поведение. Описание классов в языке C++. Объект, класс и инкапсуляция как связанные понятия.
Термин Объект. Неформальное определение: объект моделирует часть окружающей действительности и таким образом существует во времени и пространстве. Другое определение – объект представляет собой конкретный опознаваемый предмет, единицу или сущность (реальную или абстрактную), имеющую четко определенные функциональное назначение в данной предметной области. В еще более общем плане объект может быть определен как нечто, имеющее четко очерченные границы. В ПО впервые термин «объект» был введен в языке Simula и применялся для моделирования реальности.
Объект обладает состоянием, поведением и идентичностью; структура и поведение схожих объектов определяет общий для них класс. Термины «экземпляр класса» и «объект» взаимозаменяемые.
Термин Класс. В общепонятных терминах, класс это группа, множество или вид с общими свойствами или общим свойством, разновидностями, отличиями по качеству, возможностями или условиями. Если объект обозначает конкретную сущность, определенную во времени и пространстве, то класс определяет абстракцию существенного в объекте. В контексте ООП, класс – это некое множество объектов, имеющих общую структуру и общее поведение.
Различие терминов класс и объект: это отдельные, но тесно связанные понятия. В частности, каждый объект является экземпляром какого-либо класса; класс может порождать любое число объектов. В большинстве практических случаев классы статичны, то есть все их особенности и содержание определенны в процессе компиляции программы. Из этого следует, что любой созданный объект относится к строго фиксированному классу. Сами объекты, напротив, в процессе выполнения программы создаются и уничтожаются. Например, существует класс «млекопитающие», а указание на конкретного представителя («Мой кот, Мурзик») – это объект или экземпляр класса «млекопитающих».
Свойства объекта: состояние есть перечень (обычно статические) всех свойств конкретного объекта и текущими (обычно динамические) значениями каждого из этих свойств. Например, статическое свойство Лифта есть декларированная способность ездить вверх-вниз, а не горизонтально. И значение свойства есть состояние (едет, стоит). Если едет, то откуда и куда. Если стоит, то номер этажа.
Свойства объекта: поведение определяет как объект действует и реагирует; поведение выражается в терминах состояния объекта и передачи сообщений. Иными словами, поведение объекта – это его наблюдаемая и проверяемая из вне деятельность.
Свойства объекта: идентичность – это такое свойство объекта, которое отличает его от всех других объектов.
Свойства класса: структура. Выделяют две составляющие класса – интерфейс (облик) и реализация (внутренне устройство). Главное в интерфейсе – объявление операций, востребованных другими классами. Сюда же относят объявление других классов, переменных, констант и исключительных ситуаций, уточняющих абстракцию. Реализация, напротив – ни кому из вне класса не интересна, а значит – она направлена на определении операций, объявленных в интерфейсе. Интерфейс класса принято делить на три части:
Открытая (public) – видимая всем клиентам. Защищенная (protected) – видимую самому классу, его подклассам и друзьям. Закрытая (private) – видимую т. самому классу и его друзьям.
Свойства класса: поведение – задает шаблон поведения, присущий всем без исключений экземплярам (объектам). Поведение класса его объявляет (описание заголовка метода: имя, список параметров и их типы) и определяет (содержание метода: алгоритм).
Описание классов в языке С++. В стандарте ANSI/ISO языка С++ класс объявляется с помощью ключевого слова class. Синтаксис объявления класса похож на синтаксис объявления структуры.
Объявление | Пример |
class имя_класса { // закрытые члены класса public: // открытые члены класса } список_объектов; | class myClass { int a; public: void set_a(int num); int get_a();}; |
В объявление класса список_объектов не обязателен.
Объект, класс и инкапсуляция как связанные понятия: Объект является экземпляром класса. Класс определяет поведение объекта, по средством задания его интерфейса и реализации. Интерфейс отражает внешнее поведение объекта, описывая его абстракцию. А внутренняя реализация описывает представление этой абстракции и механизмы достижения желаемого поведения. Внутренняя реализация скрывает от других объектов все детали, не имеющие отношения к процессу взаимодействия объектов (т.е. это инкапсуляция).
14. Создание объектов в языке C++. Распределение объектов в динамической памяти (куче) и автоматическое распределение памяти под объекты (на стеке). Сильные и слабые стороны.
В С++ распределение памяти для переменных осуществляется в стеке и в куче. Когда переменные распределяются в стеке, то при распределении вызывается их конструктор и при выходе их из области видимости вызывается их деструктор. Наибольшее распространение для объекта получил способ выхода из области видимости ч/з возврат функции. Например:
void main {
MyClass Object; // MyClass
SomeFunction(Object); // вызываем функцию SomeFunction с
// параметром типа MyClass
Return 0;}
В данном тексте сначала объект создается в стеке при объявлении (вызов конструктора), затем используется конструктор копирования для передачи параметра в функцию (в области видимости функции появляется экземпляр объекта типа MyClass), а затем переменная Object уничтожается (выход за пределы видимости – процедуры Main). Кроме того, деструктор вызывается в SomeFunction после возврата функции (оператора return).
Замечание: нет необходимости указывать ключевое слово auto перед объявлением имени переменной. Компилятор в его отсутствие автоматически определяет, что распределение идет на стеке. Пример аналогичных конструкций: 1) auto int a; 2) int a;
Второй способ – создание объекта в куче с использованием оператора new:
myClass *pObject = new MyClass;
someFunction(*pObject);
delete pObject;
Использование оператора new приводит к вызову конструктора класса myClass. Для передачи параметра в функцию надо разадресовать указатель pObject. Далее опять происходит вызов конструктора копирования и деструктора в теле функции. Delete pObject освобождает память. Если же определить функцию someFunction(myClass *c), в которую передается указатель на объект, то при ее использовании конструктор копии не будет вызван, т.к. new объект не создается. Поэтому и при возвращении управления функцией не вызывается деструктор.
Использование оператора new подразумевает необходимость освобождения памяти с помощью delete. Иначе происходит утечка памяти – область памяти, использованная для данного объекта, становится недоступной до окончания программы. Часто такие ошибки приводят к замедлению или даже завершению программы, они малозаметны. В случае обработки исключений необходимо дублировать операторы delete для всех используемых указателей, что не является идеальным решением. Кроме того, копирование указателей (Н-Р, при передаче их в функцию) усложняет управление памятью – может случайно удалить уже удаленный указатель. Для того, чтобы избежать таких ошибок, рекомендуется удаленные указатели устанавливать в NULL. Работа с указателями часто бывает небезопасна: передача указателя подразумевает возможность изменения объекта, что может быть нежелательно.
В свою очередь, использование автоматического распределения (в стеке) часто приводит к уменьшению производительности и доступной памяти: при каждой передаче объекта в функцию по значению создается копия этого объекта (конструктором копий), а при возврате управления функцией создается другая копия. Это занимает время и память. Во избежание этого рекомендуется использовать передачу указателя const. В этом случае копирование объекта не происходит, а объект не может быть изменен.
15. Методы (члены-функции) в классах языка C++. Специальные методы: статические (static) методы, виртуальные методы и неизменные (immutable) методы в C++.
Внутри класса можно объявить функции, которые обычно, называются функциями-членами (memberfunction). В визуальном программировании этому понятию соответствуют методы.
Поскольку разные структуры могут иметь функции-члены с одинаковыми именами, при определении функции-члена нужно указывать имя структуры. В теле функции-члена имена членов можно использовать без указания имени объекта. В таком случае имя относится к члену того объекта, для которого была вызвана функция.
Функции-члены можно объявлять статическими (static), но обычно это не делается. Доступ к объявленной статической функции — члену класса возможен только для других статических членов этого класса. У статической функции-члена нет указателя this. Статические функции-члены не могут быть виртуальными. Статические функции-члены не могут объявляться с идентификаторами const (постоянный) и volatile (переменный).
Виртуальная функция(virtual function) является членом класса. Она объявляется внутри базового класса с ключевым словом virtual и переопределяется в производном классе. Если класс, содержащий виртуальную функцию, наследуется, то в производном классе виртуальная функция переопределяется. По существу, виртуальная функция реализует идею "один интерфейс, множество методов", которая лежит в основе полиморфизма. Виртуальная функция внутри базового класса определяет вид интерфейса этой функции. Каждое переопределение виртуальной функции в производном классе определяет ее реализацию, связанную со спецификой производного класса.
Виртуальная функция может вызываться так же, как и любая другая функция-член. Однако наиболее интересен вызов виртуальной функции через указатель, благодаря чему поддерживается динамический полиморфизм. Если виртуальная функция не подменяется в производном классе, то используется версия функции, определенная в базовом классе.
Функции – члены класса могут объявляться постоянными(с идентификатором const). Если функция объявлена постоянной, она не может изменить вызывающий ее объект. Кроме этого, постоянный объект не может вызвать непостоянную функцию-член. Тем не менее, постоянная функция-член может вызываться как постоянными, так и непостоянными объектами. Пример:
class X {
int some_var; public:
int f1 () const; // постоянная функция-член };
Ключевое слово const указывают следом за списком параметров функции, а не перед именем функции. Возможна ситуация, когда понадобится, чтобы функция-член, оставаясь постоянной, тем не менее была способна изменить один или несколько членов класса. Это достигается заданием модифицируемых членов класса (ключевое слово mutable). Модифицируемый член класса можно изменить с помощью постоянной функции-члена.
16. Конструкторы и деструкторы в языке C++. Соглашения относительно специальных функций-членов класса. Порядок вызова при наследовании. Виртуальные деструкторы.
Конструктор – операция создания объекта и /или его инициализация. Вызывается всякий раз при создании объекта класса. Т.о., любая необходимая объекту инициализация при наличии конструктора выполняется автоматически. Конструктор может быть реализован программистом. Если программист не задал свой конструктор класса, создаётся конструктор по умолчанию. Допустимо создание нескольких конструкторов (перегрузка).
Существует два типа конструкторов: конструктор по умолчанию и конструктор копирования. Первый используется для создания и инициализации объекта, может не иметь параметров или использовать список значений для инициализации переменных класса. Конструктор копирования используется для инициализации объекта с помощью другого объекта того же класса, то есть копирует один объект в другой. Конструктор не возвращает значений.
Для глобальных объектов конструктор объекта вызывается тогда, когда начинается выполнение программы. Для локальных объектов конструктор вызывается всякий раз при выполнении инструкции объявления переменной. Если класс имеет базовый класс или объекты члены с конструкторами, их конструкторы вызываются до конструктора производного класса.
Деструктор (функция, обратная конструктору) – операция, освобождающая состояние объекта и/или разрушающая сам объект. Деструктор не имеет входных параметров, не возвращает значений. Деструктор должен быть только один.
Локальные объекты удаляются тогда, когда они выходят из области видимости. Глобальные объекты удаляются при завершении программы.
Конструктор и деструктор объявляются как члены-функции класса. Имя конструктора совпадает с именем класса. Имя деструктора начинается с символа ~ (тильда), за которым следует имя класса. Замечание: применяется для языка С++.
Адреса (указатель) конструктора и деструктора получить невозможно.
Согласно синтаксису C++ нет никаких ограничений на выполняемые в конструкторе и деструкторе действия. То есть там могут встречаться любые допустимые в языке операторы (кроме return). Предполагается, что в этих функциях выполняются только действия необходимые для конструкции и инициализации класса, или для уничтожения объекта класса. Помещение сюда не относящихся к делу действий – признак дурного тона при программировании.
При наследовании вызов конструктора производного класса приводит к цепочке вызовов конструкторов от непосредственного родителя до базового предка-класса. Эта цепочка вызовов строится автоматически при одинарном наследовании. При множественном наследовании (несколько цепочек вызова) она строится слева направо. Если переменные класса также являются объектами какого-то класса, то для их создания будут вызваны соответствующие конструкторы, что может привести к порождению новых цепочек вызовов.
В отличие от конструктора деструктор может быть виртуальным. Если он не объявлен виртуальным можно столкнуться с ситуацией неправильной ликвидацией объекта. Деструктор объявляется с ключевым словом virtual – при уничтожении объекта, будет автоматически определен его деструктор, исходя из его типа. Ключевое слово virtual позволяет указать на то, что вызовы деструкторов будут компоноваться уже во время выполнения программы.
17. Понятие модуля. Модуль как средство борьбы со сложностью программной системы. Принципы проектирования модулей. Модули в языке C++. Модульность и инкапсуляция как связанные понятия.
Приступая к разработке каждой программы, следует иметь ввиду, что она, как правило, является большой системой, поэтому нужно принять меры для ее упрощения. Для этого программу разрабатывают по частям, которые называются программными модулями. Программный модуль - это любой фрагмент описания процесса, оформляемый как самостоятельный программный продукт, пригодный для использования в описаниях процесса. Это означает, что каждый программный модуль программируется, компилируется и отлаживается отдельно от других модулей программы, и тем самым, физически разделен с другими модулями программы. Более того, каждый разработанный программный модуль может включаться в состав разных программ, если выполнены условия его использования, декларированные в документации по этому модулю. Т.о., программный модуль может рассматриваться и как средство борьбы со сложностью программ, и как средство борьбы с дублированием в программировании.
Модульное программирование является воплощением в процессе разработки программ обоих общих методов борьбы со сложностью и обеспечение независимости компонент системы, и использование иерархических структур. Для воплощения первого метода формулируются определенные требования, которым должен удовлетворять программный модуль, т.е. выявляются основные характеристики "хорошего" программного модуля. Для воплощения второго метода используют древовидные модульные структуры программ (включая деревья со сросшимися ветвями).
Модульность – это свойство системы, которая была разложена на внутренне связные, но слабо связанные между собой модули.
Т.о., принципы абстрагирования, инкапсуляции и модульности являются взаимодополняющими. Объект логически определяет границы определенной абстракции, а инкапсуляция и модульность делают их физически незыблемыми.
Модули в языке C++ позволяют программисту оформлять собственные функции, константы и типы данных в независимые программные единицы, которые могут быть использованы как в программах, так и в других модулях. Желательно, чтобы набор функций, констант и типов данных в модуле был логически связан. Например, функции и типы данных для работы с комплексными числами следует размещать одном модуле, а функции и типы данных с матрицами в другом.
При создании модуля используются два типа файлов: с телом модуля (*.c) и заголовочный (*.h). Имена файлов относительно одного модуля должны совпадать.
В файле тела модуля описываются функции, а также константы и типы данных, которые эти функции используют. Все описанные в теле модуля константы и типы данных не будут доступны в используемой этот модуль программе. Поэтому экспортируемые типы данных и константы описываются в заголовочном файле, который может быть включен в код программы. Для того, чтобы экспортировать функции необходимо использовать оператор extern.
Для того, чтобы не было проблем с компиляцией модулей, все файлы с телом этих модулей помещают в тот же проект что и основную программу. В тоже время не следует в проект помещать заголовочные файлы. Пример реализации модуля. Заголовочный файл
// complex.h - Пример реализации заголовочного файла модуля.
// Модуль содержит тип данных комплексного числа,
// а также функцию вывода комплексного числа на экран.
typedef struct {
double Re, Im;
} complex;
extern void OutComplex(complex);
Для использования модуля в программе достаточно включить в текст программы директиву перепроцессора #include с указанием соответствующего заголовочного файла. В отличие от стандартных модулей собственные модули указываются в двойных кавычках.
18. Типизация (декларация) данных в языках программирования. Задачи типизации. Слабая и сильная типизация. Достоинства и недостатки каждой. Типизация в языке C++. Встроенные типы данных. Определение new типов данных.
Существует два полюса типизации – слабая и сильная. Каждый язык программирования сочетает в себе черты обоих типов, больше склоняясь к одному из них. Примеры языков со слабой типизацией – SmallTalk, 8-2425.php">⇐ Назад