Лабораторная работа № 6. Программирование шаблона классов - Технология разработки программного обеспечения систем управления

Цель Работы - изучить приемы создания и использования шаблонов классов.

- Теоретические сведения

Достаточно часто встречаются классы, объекты которых должны содержать элементы данных произвольного типа (в том смысле, что их тип определяется отдельно для каждого конкретного объекта). В качестве примера можно привести любую структуру данных (массив указателей, список, дерево). Для этого в С++ предлагаются средства, позволяющие определить некоторое множество идентичных классов с параметризованным типом внутренних элементов. Они представляют собой особого вида заготовку класса, в которой в виде параметра задан тип (класс) входящих в него внутренних элементов данных. При создании конкретного объекта необходимо дополнительно указать и конкретный тип внутренних элементов в качестве фактического параметра. Создание объекта сопровождается созданием соответствующего конкретного класса для типа, заданного в виде параметра. Принятый в С++ способ определения множества классов с параметризованным внутренним типом данных (иначе - макроопределение) называется шаблоном (template).

Синтаксис шаблона рассмотрим на примере шаблона класса векторов, содержащих динамический массив указателей на переменные заданного типа.

// <class T> - параметр шаблона - класс "T", внутренний тип данных

// vector - имя группы шаблонных классов

Template <class T> class vector

{

Int tsize; // Общее количество элементов

Int csize; // Текущее количество элементов

T **obj; // Массив указателей на параметризованные //объекты типа "T"

Public:

T *operator[](int); // оператор [int] возвращает указатель на

// параметризованный объект класса "T"

Void insert(T*); // включение указателя на объект типа "T"

Int index(T*);

};

Данный шаблон может использоваться для порождения объектов-векторов, каждый из которых хранит объекты определенного типа. Имя класса при этом составляется из имени шаблона "vector" и имени типа данных (класса), который подставляется вместо параметра "Т":

Vector<int> a;

Vector<double> b;

Extern class time;

Vector<time> c;

Заметим, что транслятором при определении каждого вектора с новым типом объектов генерируется описание нового класса по заданному шаблону (естественно, неявно в процессе трансляции). Например, для типа int транслятор получит:

Class vector<int>

{

Int tsize;

Int csize;

Int **obj;

Public:

Int *operator[](int);

Void insert(int*);

Int index(int*);

};

Далее следует очевидное утверждение, что функции - методы шаблона также должны быть параметризованы, т. е. генерироваться для каждого нового типа данных. Действительно, это так: функции-методы шаблона классов, в свою очередь, также являются шаблонными функциями с тем же параметром. То же самое касается переопределяемых операторов:

// параметр шаблона - класс "T", внутренний тип данных

// имя функции-элемента или оператора - параметризовано

//

Template <class T> T* vector<T>::operator[](int n)

{

If (n >=tsize) return(NULL);

Return (obj[n]);

}

Template <class T> int vector<T>::index(T *pobj)

{

Int n;

For (n=0; n<tsize; n++)

If (pobj == obj[n]) return(n);

Return(-1);

}

Заметим, что транслятором при определении каждого вектора с новым типом объектов генерируется набор методов - функций по заданным шаблонам (естественно, неявно в процессе трансляции). При этом сами шаблонные функции должны размещаться в том же заголовочном файле, где размещается определение шаблона самого класса. Для типа int сгенерированные транслятором функции-методы будут выглядеть так:

Int* vector<int>::operator[](int n)

{

If (n >=tsize) return(NULL);

Return (obj[n]);

}

Int vector<int>::index(int *pobj)

{

Int n;

For (n=0; n<tsize; n++)

If (pobj == obj[n]) return(n);

Return(-1);

}

- Задание К Лабораторной Работе

Общая постановка.

Даны: число N и последовательность a1, a2, ... aN. Создать шаблон класса, порождающий динамические одномерные массивы с элементами различных типов (вещественные, целочисленные, символьные). Тип данных и результат являются параметрами по отношению к классу, программа должна иметь методы инициализации, конструктор, деструктор, метод просмотра значений созданного массива согласно заданному алгоритму.

Для реализации шаблона использовать библиотеку STL.

    - Варианты заданий 1. a1, (a1+a2), ... ,(a1+a2+...+aN); 2. (a1*a1), (a1*a2), ..., (a1*aN); 3. |a1|, |a1+a2|, ..., |a1+a2+...aN|; 4. a1, - a1*a2, +a1*a2*a3, ... ,(-1)N*a1*a2*...aN; 5. - a1, +a2, - a3, ... , (-1)N*aN; 6. (a1+1), (a2+2) , (a3+3), ..., (aN+N); 7. a1*1, a2*2, a3*3, ..., aN*N; 8. a1*a2, a2*a3, ... , aN-1*aN; 9. a1/1, a2/2, a3/3, ... ,aN/N; 10. (a1+a2), (a2+a3), ... ,(aN-1+aN); 11. (a1+a2+a3), (a2+a3+a4), (a3+a4+a5), ... (aN-2+aN-1+aN); 12. (N+a1), ( N-1+a2), ... ,(1+aN); 13. (N*a1), ( (N-1)*a2), ... ,(1*aN); 14. a1/N, a2/N, ... ,aN/1. - Контрольные вопросы 1. С какой целью используются шаблоны классов? 2. Какие существуют виды параметров шаблона класса? 3. В чем заключается особенность использования функций - методов шаблона? 4. Может ли использоваться шаблон для параметризованных объектов? 7. Лабораторная Работа7. Множественное Наследование С Использованием Абстрактных Базовых Классов, Файлового Ввода - Вывода С Применением Потоков С++, Функций Обработки Исключительных Ситуаций

Цель Работы - изучить методику создания множественного наследования, использование абстрактного базового класса, файловый ввод - вывод и использование функций обработки исключительных ситуаций.

- Теоретические сведения

Абстрактные Классы

Если базовый класс используется только для порождения производных классов, то виртуальные функции в базовом классе могут быть "пустыми", поскольку никогда не будут вызваны для объекта базового класса. Базовый класс, в котором есть хотя бы одна такая функция, называется Абстрактным. Виртуальные функции в определении класса обозначаются следующим образом:

Classbase

{

Public:

Virtual print()=0;

Virtual get() =0;

};

Определять тела этих функций не требуется.

Множественное Наследование

Множественным наследованием называется процесс создания производного класса из двух и более базовых. В этом случае производный класс наследует данные и функции всех своих базовых предшественников. Существенным для реализации множественного наследования является то, что адреса объектов второго и последующих базовых классов не совпадают с адресом объекта производного класса. Этот факт должен учитываться транслятором при преобразовании указателя на производный класс в указатель на базовый и наоборот:

Class d : public a, public b, public c { };

D D1;

Pd = &D1; // #define dbsizeof(a)

Pa = pd; // #define dc sizeof(a)+sizeof(b)

Pb = pd; // pb = (char*)pd + db

Pc = pd; // pc = (char*)pd + dc

33

Такое действие выполняется компилятором как явно, при преобразовании в программе типов указателей, так и неявно, когда в объекте производного класса наследуется функция из второго и последующих базовых классов. Для вышеуказанного примера при определении в классе bb функции f() и ее наследовании в классе "d" вызов D1.f() будет реализован следующим образом:

This = &D1; // Указатель на объект производного класса

This = (char*)this + db // Смещение к объекту базового класса

B::f(this); // Вызов функции в базовом классе

Механизм виртуальных функций при множественном наследовании имеет свои особенности.

Во-первых, на каждый базовый класс в производном классе создается свой массив виртуальных функций (в нашем случае - для aa в d, для bb в d и для ccв d).

Во-вторых, если функция базового класса переопределена в производном, то при ее вызове требуется преобразовать указатель на объект базового класса в указатель на объект производного. Для этого транслятор включает соответствующий код, корректирующий значение this в виде "заплаты", передающей управление командой перехода к переопределяемой функции, либо создает отдельные таблицы смещений.

Файловые Потоки. Классы файловых потоков:

Ifstream - файл ввода, производный от istream,

Ofstream - файл вывода, производный от ostream,

Fstream - файл ввода-вывода, производный от iostream.

Флаги Режимов Работы С Файлом:

Enum ios::open_mode

{

In = 0x01, // Открыть файл только для чтения

Out = 0x02, // Открыть файл только для записи

Ate = 0x04, // При открытии позиционироваться в конец файла

App = 0x08, // Открыть существующий для дополнения

Trunc = 0x10, // Создание нового файла взамен существующего

Nocreate=0x20, // Не создавать новый файл при его отсутствии

Noreplace=0x40, // Не создавать новый файл, если он существует

Binary= 0x80 // Двоичный файл ("прозрачный" ввод-вывод без

// преобразования символов конца строки)

};

Конструкторы объектов (для классов ifstream, ofstream, fstream) и функции открытия/закрытия файлов:

Ifstream(); // Без открытия файлов

Ifstream( // С открытием файла в заданном

Char *name, // режиме imode

Intimode=ios::in,

Intprot=filebuf::openprot);

Ifstream(intfd); // Сприсоединениемфайласдескриптором fd

Ifstream( // То же, с явно заданным буфером

Intfd,

Char *buf, intsz);

Void ifstream::open(

Char *name, // Открытие файла в заданном режиме

Intimode=ios::in,

Intprot=filebuf::openprot);

Void close(); // Закрытьфайл

Void setbuf(

Char *p, intsz);// Установитьбуферпотока

Int fd(); // Дескриптор открытого в потоке файла

Int is_rtl_open(); // 1 - файл открыт в потоке

Унаследованные переопределения операторов позволяют проверять наличие ошибок в потоках в виде:

Fstream ss;

If (ss) ... или if (!ss)

Обработка Исключительных Ситуаций

Средства обработки ошибочных ситуаций позволяют передать обработку исключений из кода, в котором возникло исключение, некоторому другому программному блоку, который выполнит в данном случае некоторые определенные действия. Таким образом, основная идея данного механизма состоит в том, что функция проекта, которая обнаружила непредвиденную ошибочную ситуацию, которую она не знает, как решить, генерирует сообщение об этом (бросок исключения). А система вызывает по этому сообщению программный модуль, который перехватит исключение и отреагирует на возникшее нештатное событие. Такой программный модуль называют "обработчик" или перехватчик исключительных ситуаций. И в случае возникновения исключения в его "обработчик" передается произвольное количество информации с контролем ее типа. Эта информация и является характеристикой возникшей нештатной ситуации.

Обработка исключений в С++ - это обработка с завершением. Это означает, что исключается невозможность возобновления выполнения программы в точке возникновения исключения.

Для обеспечения работы такого механизма были введены следующие ключевые слова:

Try - проба испытания;

Catch - перехватить (обработать);

Throw - бросать.

Кратко рассмотрим их назначение.

Try- открывает блок кода, в котором может произойти ошибка; это обычный составной оператор:

Try

{

Код

};

Код содержит набор операций и операторов, который и будет контролироваться на возникновение ошибки. В него могут входить вызовы функции пользователя, которые компилятор также возьмет на контроль. Среди данного набора операторов и операций обязательно указывают операцию броска исключения: Throw.

Операция броска Throwимеет следующий формат:

Throw выражение;

Где "выражение" определяет тип информации, которая и описывает исключение (например, конкретные типы данных).

Catch - сам обработчик исключения, который перехватывает информацию:

Catch ( тип, параметр)

{

Код

}

Через параметр обработчику передаются данные определенного типа, описывающие обрабатываемое исключение.

Код определяет те действия, которые надо выполнить при возникновении данной конкретной ситуации. ВС++ используют несколько форм обработчиков. Такой обработчик получил название "параметризованный специализированный перехватчик".

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

В этом случае их необходимо расположить сразу же за контролирующим блоком последовательно друг за другом.

Кроме того, запрещены переходы, как извне в обработчик, так и между обработчиками.

Можно воспользоваться универсальным или абсолютным обработчиком:

Catch ( )

{

Код

},

Где (...) означают способность данного перехватчика обрабатывать информацию любого типа.

Такой обработчик располагают последним в пакете специализированных обработчиков. Тогда, если исключение не будет перехвачено специализированными обработчиками, то будет выполнен последний - универсальный.

В случае не возникновения исключения набор обработчиков будет обойден, т. е. проигнорирован.

Если же исключение было брошено, при возникновении критической ситуации, то будет вызван конкретный перехватчик при совпадении его параметра с выражением в операторе броска, т. е. управление будет передано найденному обработчику. После выполнения кода вызванного обработчика управление передается оператору, который расположен за последним перехватчиком, или проект корректно завершает работу.

Существенное отличие вызова конкретного обработчика от вызова обычной функции заключается в следующем: при возникновении исключения и передаче управления определенному обработчику система осуществляет вызов всех деструкторов для всех объектов классов, которые были созданы с момента начала контроля и до возникновения исключительной ситуации с целью их уничтожения.

Блоки Try, как составные блоки могут быть вложены:

Try {

Try

{

}

}

Тогда, в случае возникновения исключения в некотором текущем блоке, поиск обработчика последовательно продолжается в блоках, предшествующих уровням вложенности с продолжением вызова деструкторов.

Задание к контрольной работе

Общая постановка. Создать программу с абстрактным базовым классом и множественным наследованием,(либо иерархией классов) реализовать в нем:

    - конструктор, - деструктор, - виртуальную функцию просмотра текущего состояния объекта print(), - friend - функцию Run ().

Производные классы должны содержать переопределенную функцию просмотра состояния объектов, а также при вводе - выводе данных использовать функции обработки исключительных ситуаций. Используя стандартные файловые потоки, информацию об объектах вывести в файл. Для корректной работы с файлом использовать обработку исключительных ситуаций.

    - Варианты Заданий - 1. Список товаров, имеющихся на складе, включает в себя наименование товара, количество единиц товара, цену единицы и дату поступления товара на склад. Вывести в алфавитном порядке список товаров, хранящихся больше месяца, стоимость которых превышает 1000000 руб. - 2. Для получения места в общежитии формируется список студентов, который включает Ф. И.О. студента, группу, средний балл, доход на члена семьи. Общежитие в первую очередь предоставляется тем, у кого доход на члена семьи меньше двух минимальных зарплат, затем остальным в порядке уменьшения среднего балла. Вывести список очередности предоставления мест в общежитии. - 3. В справочной автовокзала хранится расписание движения автобусов. Для каждого рейса указаны его номер, тип автобуса, пункт назначения, время отправления и прибытия. Вывести информацию о рейсах, которыми можно воспользоваться для прибытия в пункт назначения раньше заданного времени. - 4. На междугородной АТС информация о разговорах содержит дату разговора, код и название города, время разговора, тариф, номер телефона в этом городе и номер телефона абонента. Вывести по каждому городу общее время разговоров с ним и сумму. - 5. Информация о сотрудниках фирмы включает: Ф. И.О., табельный номер, количество проработанных часов за месяц, почасовой тариф. Рабочее время свыше 144 часов считается сверхурочным. Вывести сотрудников фирмы, которые имеют сверхурочные часы. - 6. Информация об участниках спортивных соревнований содержит: наименование страны, название команды, Ф. И.О. игрока, игровой номер, возраст, рост, вес. Вывести информацию о самой молодой, рослой и легкой команде. - 7. Для книг, хранящихся в библиотеке, задаются регистрационный номер книги, автор, название, год издания, издательство, количество страниц. Вывести список книг с фамилиями авторов в алфавитном порядке, изданных после заданного года. - 8. Различные цеха завода выпускают продукцию нескольких наименований. Сведения о выпущенной продукции включают: наименование, количество, номер цеха. Для заданного цеха необходимо вывести количество выпущенных изделий по каждому наименованию в порядке убывания количества. - 9. Информация о сотрудниках предприятия содержит Ф. И.О., номер отдела, должность, дату начала работы. Вывести списки сотрудников по отделам, которые проработали меньше года. - 10. Ведомость абитуриентов, сдавших вступительные экзамены в университет, содержит Ф. И.О., адрес, оценки. Вывести абитуриентов, проживающих в г. Минске и сдавших экзамены со средним баллом не ниже 8. - 11. В налоговой инспекции содержатся данные о предприятиях, которые определяют название, УНП, ФИО директора, вид деятельности, дата регистрации. Вывести все предприятия по видам деятельности (исключать ликвидированные). - 12. В справочной аэропорта хранится расписание вылета самолетов на следующие сутки. Для каждого рейса указаны: номер рейса, тип самолета, пункт назначения, время вылета. Вывести все номера рейсов, типы самолетов и времена вылета для заданного пункта назначения в порядке возрастания времени вылета. - 13. Транспорт (наименование, тип, год выпуска, максимальная скорость, объем двигателя, расход, объем бензобака, расстояние без подзаправки-функция Run ()). - 14. Продовольственные товары (наименование, отдел магазина, дата выпуска, срок хранения, последний срок реализации - функция Run (), вес). - 15. Объекты недвижимости (адрес, тип, этажность, квартир на этаже, подъездов, всего квартир - функция Run ()). - 16. Периодические издания (название, тип, страниц, частота выпуска, тираж, выпусков в год - функция Run ()). - 17. Отдел кадров (ФИО, отдел, должность, дата приема на работу, внутренний стаж - функция Run (), ставка). - 18. Научно-исследовательские разработки (наименование, дата начала, дата завершения, срок работы - функция Run(), область исследования, количество сотрудников, ФИО сотрудников). - 19. Программное обеспечение (наименование, тип, количество дисков, объем после установки (полной, минимальной, типичной версий), процент сжатия - функция Run ()). - 20. Комплектующие ЭВМ (наименование, тип, модель, частота, объем памяти, стоимость, количество, итоговая стоимость - функция Run ()). - 21. Аудио - студия (группа/исполнитель, количество человек, стиль, количество альбомов, стоимость записи диска [], стоимость диска [], тираж[], общая прибыль группы - функция Run (), доход исполнителя - функция Run1()). - 22. Мобильные телефоны (наименование, фирма, стандарт связи, заряд аккумулятора, потребление при ожидании, потребление при разговоре, время ожидания - функция Run (), время разговора - функция Run1 ()). - 23. Сетевое оборудование (наименование, скорость передачи данных, тип, стоимость, количество, общая стоимость - функция Run (), максимальная скорость передачи (байт/с)). - 24. Гостиница (информация о номерах, клиентах, счетах, поиск - функция Run() - по номеру в гостинице). - 25. Установка и обслуживание ЛВС. (информация о сетевых конфигурациях, клиентах, договорах, поиск - функция Run() - по клиенту). - 26. Фирма-поставщик медицинской техники. (ассортимент, заказчики, контракты, поиск - функция Run() - по наименованию медицинской техники). - 27. Автозаправочная станция. (горюче-смазочные материалы, поставщики, накладные, поиск - функция Run() - по номеру накладной). - 28. Студия видеозаписи. (режиссеры/Актеры, фильмы, продажи. поиск - функция Run() - по названию фильма). - 29. Музей (экспонаты, авторы, экспозиции. поиск - функция Run() - по автору). - 30. Страховая фирма. (Виды страховок, Клиенты/объекты страховки, Страховая деятельность, поиск - функция Run() - по клиенту). 8. Лабораторная работа №8. Мастера Сlassview и Сlasswizard в Visual C++

Цель Работы - изучить методы работы с мастерами Сlassview и Сlasswizard и их возможности.

- Теоретические сведения

При начальном знакомстве с концепциями и возможностями объектно - ориентированного стиля программирования на базе языка С++ как правило методологию данного стиля изучают на простых, часто не несущих практической значимости примерах.

Так, например, проиллюстрировать ключевые понятия пользовательского типа данных "класс", положенного в основу ООП можно на следующем простом примере.

Программа создает целочисленные объекты класса "Х", который помимо целочисленных трех закрытых элементов-данных имеет в своем составе три общедоступных метода (элементы-функции класса): для инициализации объектов, просмотра их текущего состояния, а так же для суммирования значений первых двух элементов с сохранением результата в третьем.

Консольное приложение для демонстрации ключевых понятий ООП может быть, например таким:

// подключили заголовочные файлы

#include <iostream. h>

#include <conio. h>

// декларируем класс"Х"

Class X

{

// закрытая часть - реализация класса

Int a, b, c; // три целочисленные элементы-данные класса(состав будущих объектов

// данного класса)

// открытая часть - интерфейс класса

Public:

// метод для инициализации класса

Void set(int i, int j)

{

A=i; b=j;

Cout<<"Object created!"<<endl;

}

// метод для просмотра текущего состояния существующего объекта

Void print(void)

{

Cout<<"for а="<<a<<" b="<<b<<" summa="<<c<<endl;

}

// метод для взаимодействия с объектами

Void run(void)

{

C=a+b;

}

};

// основная функция программы

Void main(void)

{

X x1; // объект создан

X1.set(2,3); //объект использован: проинициализирован

X1.run(); //объект использован: определено значение третьего элемента

X1.print();//объект использован:просмотр текущего состояния

Getch();

}

//по окончании работы программы объект автоматически уничтожается

Запускаем и получаем:

Object created!

For a=2 b=3 summa=5

Но еще более наглядной иллюстрацией ключевых понятий ООП можно получить, создав, например, при помощи AppWizard простую диалоговую панель с командной кнопкой. Участок кода по созданию и использованию объектов класса разместить в обработчике щелчка на данной кнопке, а сам класс "Х" и его элементы добавить при помощи мастера ClassView.

Рассмотрим этот мастер Visual C++ более подробно.

Используя ClassView можно быстро и наглядно добавлять к существующим классам новые классы, новые для них элементы, просматривать структуру наследования, а так же выполнять некоторые другие полезные операции.

Итак, создадим простую диалоговую панель (Имя проекта - CMy).

    1) Создайте при помощи MFC AppWizard(exe) новый проект тип Dialog based, 2) убираем для упрощения на втором шаге "About box", 3) Используя панель Controls, нанесите на заготовку формы 1 кнопку - Button (рисунок 1).
заготовка формы

Рисунок 1 - Заготовка формы

4) В выпадающем меню пункт Properties, выбираем закладку General и в поле Caption вводим нужное имя элемента: название или надпись: "Выполнить", в закладке Styles - нужные свойства элемента.

Обратите внимание, для того, чтобы ввести пояснения на русском языке нужно в окне Workspase перейти на закладку ResourseView, раскрыть папку Lab1resources, папку Dialog, щелкнуть правой клавишей на IDD_My_DIALOG, активизировать Properties и в списке Language выбрать Russian (Русский).

5) Через ClassWizard cвязываем ее с обработчиком события одинарного щелчка BN_CLICKED. Для этого щелкнув правой клавишей мыши в любом месте диалоговой панели в появившемся меню опять выбираем пункт ClassWizard, затем выбираем закладку Message Maps, увязываем идентификатор IDC_Button1 с событием BN_CLICKED (один щелчок на кнопке), и добавляем обработчик на данное событие: щелчок на кнопке Add Function, щелчок на "OK" для подтверждения, щелчок на кнопке Edit Code и среда добавит в конец файла MyDlg. cpp пустой обработчик:

Void CMyDlg::OnButton1()

{

// TODO: Add your control notification handler code here

}

6) Теперь переходим на закладку "Class view" и щелкаем на любом классе, который нужно, например просмотреть или изменить (выберем, например CCMyDlg). На экране появится временное меню с пунктами, которые позволяют выполнять над классами все основные действия.

Например, строка "Go to definition" дает возможность просмотреть в окне редактирования исходный код класса. Можно редактировать класс непосредственно, а для добавления в класс новых методов и данных удобно пользоваться пунктами меню "Add Function" и "Add Variable".

Добавление К Проекту Нового Класса

Добавим к нашему проекту класс "Х". Для этого: выбираем пункт меню "Insert"/New class, далее, заполняем появившуюся диалоговую панель и щелкаем "OK".

В составе классов появляется новый пользовательский класс "Х" Щелкаем правой клавишей мыши на нем и выбираем "Go to definition". Имеем его первоначальный состав (файлы X. h и X. cpp):

// X. h: interface for the X class

Class X

{

Public:

X();

Virtual ~X();

};

// X. cpp: implementation of the X class.

// Construction/Destruction

X::X()

{

}

X::~X()

{

}

Т. е. средство ClassView создало пользовательский класс с декларацией в нем конструктора и деструктора. Реализация их в файле X. cpp отсутствует.

Добавление К Классу Элементов Данных

Процедура добавления в класс новых данных довольно простая. Нам нужно по условию добавить три целочисленных элемента данные. Присвоим им идентификаторы m_a, m_b и m_c. Для их добавления нужно воспользоваться пунктом меню "Add Variable".

добавление данных

Рисунок 2. - Добавление данных

Щелкаем правой клавишей мыши на только что добавленном классе "Х" и выбираем данный пункт меню. На экране - диалоговая панель "Add Member Variable", представленная на рисунке 2. Вводим тип, идентификатор, в переключателе с зависимой фиксацией Access выбираем уровень защищенности "частный" (закрытый) и нажимаем "ОК". Аналогично добавим оставшихся два элемента m_b и m_c.

В файле X. h появится декларация этих трех элементов данных класса "Х".

Добавление К Классу Методов

Методы класса добавляются аналогично добавлению элементов данных. Для того, чтобы добавить в класс новый метод, нужно выбрать из временного меню строку' "Add Function". На экране теперь появится диалоговая панель "Add Member Function", представленная на рисунке 3.

добавление функций

Рисунок 3. - Добавление функций

В поле Function Туре следует ввести тип значения, возвращаемого методом. Как и раньше и в этой диалоговой панели можно определить область видимости, но теперь уже метода.

Он, как и элемент - данное может находиться в трех положениях: или Public(общедоступный), или Protected (защищенный), или Private (закрытый). Как правило, большинство методов общедоступные из любой точки программы. Кроме того, переключатель Static и Virtual позволяют определить, что добавляемый метод должен быть объявлен соответственно как статический или виртуальный. Последние возможности здесь игнорируем, так как добавляются обычные методы класса.

Когда все поля диалоговой панели заполнены, щелкните на кнопке ОК. И в декларацию класса будет добавлен новый метод. А идентификатор метода появится в списке элементов класса в окне ClassView. Рисунок 3. иллюстрирует добавление к классу "Х" метода "print" просмотра текущего состояния существующих объектов класса "Х". По аналогичной методике добавляем метод "set" для инициализации созданного объекта класса и метод "run" для определения суммы m_a и m_b.

Теперь в файле X. h будут добавлены и прототипы этих методов и окончательный его вид будет таким:

// X. h: interface for the X class.

Class X

{public:

Void run(void);

Void set(int i, int j);

Void print(void);

X();

Virtual ~X();

Private:

Int m_c;

Int m_b;

Int m_a;

};

А в файле X. cpp ClassView разместит пустые определения этих добавленных в класс "Х" методов. Заполняем их следующим образом:

#include "stdafx. h"

#include "CMy. h"

#include "X. h"

// Construction/Destruction

X::X()

{

}

X::~X()

{

}

Void X::set(int i, int j)

{

M_a=i; m_b=j;

AfxMessageBox("Объект создан и проинициализирован!");

}

Void X::print(void)

{

CString str;

// объявили строковый объект класса библиотеки MFC, и при помощи его вызвали метод,

// который работает как стандартная функция printf(...), но выводит значения объектов из // списка вывода в указанную строку

Str. Format("Для m_a=%d, m_b=%d, их сумма=%d",m_a, m_b, m_c);

AfxMessageBox(str);

}

Void X::run(void)

{

M_c=m_a+m_b;

}

Теперь открываем файл проекта CMyDlg. cpp и в его начале подключаем заголовочный файл с декларацией построенного класса

// CMyDlg. cpp : implementation file

#include "stdafx. h"

#include "CMy. h"

#include "CMyDlg. h"

#include "X. h"

А в его конце оживляем обработчик щелчка на командной кнопке "Выполнить"

Void CCMyDlg::OnButton1()

{

X x1;

X1.set(2,3);

X1.run();

X1.print();

}

Запускаем, щелкаем на кнопке и получаем (рисунок 4):

результат работы программы

Рисунок 4. - Результат работы программы

Дополнительные Возможности Мастера

1. С помощью ClassView можно просмотреть список названий файлов, в которых используется данный класс. Для этого надо выбрать из временного меню строку "References". На экране появится диалоговая панель Definitions and References. Щелкаем правой клавишей мыши на классе "Х", выбираем вышеназванную опцию меню, получаем:

диалоговая панель definitions and references

Рисунок 5. - Диалоговая панель Definitions and References

2. ClassView предоставляет пользователю полезную возможность: просмотреть деревья наследования классов приложения при наличии в нем иерархии классов, связанных между собой на основе концепции наследования. Для этого нужно выбрать название интересующего вас класса из списка классов, открыть временное меню щелкнув как и раньше правой кнопкой мыши. Пункты "Derived Classes" и "Base Classes" позволяют просмотреть последовательность классов, порожденных от данного класса и последовательность базовых для него классов.

На рисунке 6. показана иерархия классов дляCCMyApp

иерархия классов для ccmyapp

Рисунок 6. - Иерархия классов для CCMyApp

Данная диалоговая панель не имеет кнопок "OK" и "Cancel" и закрывается при выборе из нее какого-либо элемента класса или при переходе в другое окно. Иногда удобно, чтобы эта панель постоянно присутствовала на экране. Прикрепить ее к главному окну можно щелчком на самой левой кнопке заголовка этой панели (которая при этом изменит свой вид).

В левой части панели отображается список классов в порядке наследования. Видим, что для класса CCMyApp верхушка иерархии - класс библиотеки MFC CObject. В правой части панели отображаются элементы-данные и элементы-функции выбранного из списка класса. Они разделены на группы в зависимости от степени защиты.

Панель Base Classes and Members позволяет легко перейти к редактированию любого элемента класса. Для этого нужно выбрать название этого элемента из списка и сделать по нему двойной щелчок левой кнопкой мыши. Чтобы легко различать методы и данные класса, перед методами располагается символ f, а перед данными - d. Непосредственно перед именем метода или данных расположен символ, позволяющий отличил статические и данные, и функции, а также виртуальные методы. Перед названиями статических данных и методов расположен символ S, а перед виртуальными методами - символ V.

Если список методов и данных класса слишком велик, вы можете отображать в диалоговой панели только их часть. Выберите из поля "Functions" типы методов, имена которых надо отобразить. Доступны следующие типы методов:

Поле Functions Методы

All Все

Virtual Виртуальные

Static Статические

Non - Static Все. кроме статических

Non - Virtual Все. кроме виртуальных

Non - Static Все. кроме статических и виртуальных

Non-Virtual Все. кроме статических и виртуальных None He отображать методы класса

Аналогично из поля "Data" можно выбрать типы элементов для элементов-данных класса, которые надо отображать на экране. В следующей таблице приведены типы данных, представленные в списке "Data".

Поле Data Элементы данных

All Все

Static Статические

Non - Static Все. Кроме стастатических None He отображать

В нижней правой части диалоговой панели "Base Classes and Members" отображены названия файлов, в которых определен (группа Definitions) и в которых используется (группа References) выбранный элемент. Двойной щелчок левой кнопкой мыши позволяет открыть в редакторе соответствующий файл. Курсор при этом сразу устанавливается в то место, где объявляется или используется выбранный элемент класса.

3. Редактирование методов класса. Выбираем из списка элементов класса метод и щелкаем правую кнопку мыши. На экране - временное меню. Это меню позволяет перейти к редактированию объявления или определения метода, просмотреть те строки исходного текста приложения, в которых вызывается метод, получить список функций и методов, вызываемых выбранным методом. Например, чтобы открыть в редакторе файл, в котором объявляется метод, и перейти к его редактированию, выбираем из меню метода пункт "Go to Definition".

Возможности Classyiew можно использовать даже на этапе отладки приложения. Так, из временного меню метода можно установить точку прерывания непосредственно на начало метода. Для этого выбирают из меню "Set Breakpoint".

    4. Редактирование элементов данных класса. Временное меню данных класса представляет собой сокращенный вариант временного меню метода. - Задание к лабораторной работе

По изложенной выше методике работы с ClassView создайте проект типа Dialog based, позволяющий вычислять и отображать два значения Z1 Z2 (в случае успеха они должны совпасть).

    - Варианты Заданий 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. . 11. 12. 13. . 14. . 15. - Контрольные вопросы 1. Перечислите возможности мастера ClassView. 2. Назовите этапы добавления к проекту нового класса, данных, методов. 3. Какие мастера проектов существуют в VC++? 9. Лабораторная работа № 9. Интерфейс графических устройств Windows

Цель Работы - изучить методы работы с графическим интерфейсом (GDI). Научиться строить простые геометрические фигуры.

- Теоретические сведения

Любая Windows - программа выводит информацию на доступное графическое устройство с помощью множества специальных функций, образующих так называемый GDI-интерфейс (от анг. graphics device interface). GDI-интерфейс является аппаратно - независимым. Windows абстрагирует вывод на графическое устройство от технических особенностей его работы. Таким образом, графическое устройство в Windows - это монитор, принтер, плоттер.

В MFC интерфейсу GDI соответствует Класс CDC. Данный класс содержит методы для вывода разнообразной графической информации: прямоугольников, линий, эллипсов, текста. Он также позволяет устанавливать цвет и масштаб изображений. Методы, обеспечивающие вывод, например на экран монитора, используют контекст устройства и этот контекст устройства в приложении на базе MFC является объектом класса CDC. Таким образом, класс CDC является базовым классом контекста устройств, содержит ряд атрибутов контекста устройств и методы управляющие ими. И для того, использовать контекст устройства, необходимо создать объект CDC.

На практике пользуются следующими классами, производными от CDC:

    - CClientDC - управляет контекстом экрана монитора, связанного с клиентской областью окна; - CWindowDC - управляет контекстом экрана монитора, связанного и с клиентской областью окна и с его системной частью.

Ниже приведен список часто используемых функций класса СDC:

Ellipse-рисует эллипс.

Polygon - рисует многоугольник.

Rectangle - рисует пряпоугольник.

RoundRect - прямоугольник со скругленными углами.

Chord - сегмента эллипса.

Pie - сектора эллипса.

LineTo - рисует линию.

При рисовании линии при помощи функции LineTo рисование осуществляется с текущей позиции пера. Для ее изменения существует функция MoveTo.

Для управления цветом фона и цветом линий существуют специальные объекты GDI. Цветом фона управляет объект - "кисть", которому соответствует класс CBrush, а цветом линий управляет объект - "перо", которому соответствует класс CPen.

Рассмотрим создание объекта "перо". Создание может происходить в два этапа: сначала объявляется переменная типа CPen, потом вызывается функция функция CreatePen, в которую предают тип линии, ширину и цвет.

Для указания типов линии используют константы:

PS_SOLID - сплошная линия;

PS_DASH - штриховая линия;

PS_DASHDOT - штрих пунктирная линия;

После создания объекта перо его необходимо выбрать в контекст устройства рисования. Для этого вызывают метод SelctObject класса СDC, передавая ему указатель на объект "перо".

Рассмотрим типовой пример: Написать программу, после нажатия кнопки выводящую картинку усеченного эллипса красного цвета с синими гранями (рисунок 1).

Для решения задачи необходимо создать приложение на основе диалогового окна.

Поместить на форму кнопку, при нажатии которой будет выполняться функция рисования.

результат программы

Рисунок 1. - Результат программы

Обработчик нажатия кнопки приведен ниже:

Void CDraw::OnButton1()

{

// TODO: Add your control notification handler code here

CClientDC dc(this); //объявляем класс, производный от класса CDC

// класс CСlientDC предназначен для рисования в диалоговом окне

CBrush br; // объявляем класс кисти br. CreateSolidBrush(RGB(255,0,0)); //создаем сплошную красную кисть

Dc. SelectObject(&;br);// выбираем кисть в контекст устройства

CPen p; //объявляем класс пера

P. CreatePen(PS_SOLID,1,RGB(0,0,255));

//создаем сплошное перо, толщиной 1, синего цвета

Dc. SelectObject(&;p); // выбираем перо в контекст устройства

For(int x=0,int y=0;x<100;x+=3,y+=4)

Dc. Ellipse(x, y,300,300); //рисуем эллипс с заданными координатами

}

- Задание К Лабораторной Работе

Требуется нарисовать одну из фигур, представленных на рисунке 2. в соответствии со своим вариантом. Фигуры должны быть окрашены в произвольные цвета.

    - Варианты заданий 33 - Контрольные вопросы 1. Дайте характеристику GDI-интерфейсу 2. В чем заключается роль класса CDС в MFC? 3. Назовите основные функции класса CDС для рисования фигур, линий. 10. Лабораторная работа № 10. Элементы управления радиокнопки (Radio Button) и переключатели (Check Box)

Цель работы - Изучить принципы работы элементов управления: радиокнопок (Radio Button) и переключателей (Check Box), позволяющих устанавливать тот или иной режим работы.

- Теоретические сведения

Элементы Управления Radio Button И Check Box

Элемент Check Box организует кнопку независимого переключателя, с помощью которой пользователь может указать свое решение типа - да/нет. В программе состояние кнопки может быть связано со значением булевской переменной, которая проверяется с помощью оператора if.

Элемент Radio Button организует группу кнопок - зависимых переключателей. При нажатии одной из кнопок группы все остальные кнопки отключаются. В программе элемент Radio Button связывается с переменной типа int, при этом в программу будет передаваться номер включенной кнопки, который анализируется с помощью оператора switсh или if. Номер первой кнопки равен 0, второй 1 и т. д. Но для этого нужно в тексте программы найти объявлении привязанной к этим кнопкам переменной и задать ее нулевое начальное значение, так как по умолчанию система программирования установит для нее значение -1.

Пример Реализации Программы

Задание: В поля ввода вводятся 2 целых числа, "Радиокнопка" выбирает действие: или суммирование или разность. "Переключатель" при не активности устанавливает вывод в одну строку при многократном выполнении приложения, а при его активизации результаты выводятся списком. Интерфейс программы приведен на рисунке 1.

интерфейс программы

Рисунок 1. - Интерфейс программы

Для решения задачи необходимо сделать следующие действия:

    1) Создать при помощи MFCAppWizard(exe) новый проект (предварительно выбрав путь и имя - например Lab2) типа Dialog based. 2) Используя панель Controls, нанести на диалоговую панель 3 элемента типа Edit Box, 4 - Static Text, 1 - Button, 2- Radio Button, 1 - Check Box и установить нужные свойства и надписи (для Radio Button с идентификатором IDC_RADIO1 нужно установить свойство Group). 3) При помощи ClassWizard через закладку Member Variables связать поле Edit1 с переменной m_a тип: int, Edit2 - с m_b тип: int, Edit3 - с m_c тип: СString. Для Edit3 установить в закладке свойств Styles: свойство Multiline. 4) При помощи ClassWizard через закладку Member Variables связать идентификатор "переключателя" IDC_CHECK1 с переменной m_s тип: BOOL, а "радиокнопки IDC_RADIO1 с переменной m_r тип: int. Кроме того, в самом начале метода BOOL Clab2Dlg::OnInitDialog() нужно установить значение переменной m_r в 0 т. е. m_r=0; 5) Теперь необходимо активировать кнопку "Выполнить". Для этого: выполнить щелчок правой клавишей мыши в любом месте диалоговой панели и в меню выбрать ClassWizard, выбрать закладку Message Maps, связать идентификатор IDC_Button1 с событием BN_CLICKED (один щелчок на кнопке), и добавить обработчик на данное событие: последовательно Add Function/OK/ Edit Code, среда добавит в конец файла Lab2Dlg. cpp пустой обработчик:

Void Clab2Dlg::OnButton1()

{

// TODO: Add your control notification handler code here

}

И, как и ранее, вместо этой фразы:

Добавляем код решение поставленной задачи:

{

Int r; CString str;

UpdateData(TRUE);

If (m_r==0) r=m_a+m_b; // если выбрана первая радиокнопка - // "суммирование"

If (m_r==1) r=m_a-m_b; // если выбрана вторая

// радиокнопка -

// "вычитание"

If (m_s)

// если переключатель активен - вывод списком

{

Str. Format("c=%d%c%c",r,13,10);

M_c=m_c+str;

}

Else

// если переключатель не активен - вывод в одну строку

M_c. Format("c=%d",r);

UpdateData(FALSE);

}

- Задание К Лабораторной Работе

В индивидуальном задании составить программу для вычисления составной функции в соответствии со своим вариантом. Требуется самостоятельно выбрать необходимое количество исходных данных для того, чтобы в программе выполнялись все возможные ветви алгоритма. Перед выводом полученного результата программа должна сообщать о ветви, для которой он получен. В качестве f(x) использовать по выбору: "радиокнопками" функции cos(x), sin(x), tg(x). Программа должна через "переключатели" запоминать или не запоминать min и max найденные значения. Вариант интерфейса приведен на рисунке 2.

вариант интерфейса

Рисунок 2. - Вариант интерфейса

- Варианты заданий

Таблица 1. - Индивидуальные задания

1

2

3

4

5

6

7

8

9

10

11

12

13

14

    - Контрольные вопросы 1. В чем заключается принцип работы элементов управления - радиокнопок (Radio Button)? 2. В чем заключается принцип работы элементов управления - переключателей (Check Box)? 3. Для чего служит мастер ClassWizard?

Похожие статьи




Лабораторная работа № 6. Программирование шаблона классов - Технология разработки программного обеспечения систем управления

Предыдущая | Следующая