Главная | Обратная связь | Поможем написать вашу работу!
МегаЛекции

Препроцессорная обертка




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

//Ошибка 1 error C2011: CppStudio: переопределение типа "class"

Чтобы не возникало такого рода ошибок, в С++ существует специальная структура кода, которую ещё называют препроцессорная обёртка:

// структура препроцессорной обёртки #ifndef /*ИМЯ_ЗАГОЛОВОЧНОГО_ФАЙЛА_H*/ #define /*ИМЯ_ЗАГОЛОВОЧНОГО_ФАЙЛА_H*/ // определение класса #endif /*ИМЯ_ЗАГОЛОВОЧНОГО_ФАЙЛА_H*/

Данная препроцессорная обёртка предотвращает попытку многократного включения заголовочных файлов. Препроцессорные директивы обрабатываются до этапа компиляции, программой-препроцессором, который не допускает многократного определения одного и того же класса. Директива #ifndef проверяет, определено ли имя DATA_H, если нет, то управление передаётся директиве #define и определяется интерфейс класса. Если же имя DATA_H уже определено, управление передаётся директиве #endif, пропуская определение класса.

// препроцессорная обёртка, заголовочный файл data.h с интерфейсом класса #ifndef DATA_H // если имя DATA_H ещё не определено #define DATA_H // определить имя DATA_H class data // определить класс data { // * * * // спецификаторы, свойства и методы класса дата }; // конец объявления класса data #endif DATA_H // если имя DATA_H уже определено, повторно не определять

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

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

Лабораторная работа № 11. Классы

Продолжительность – 4 часа.

Максимальный рейтинг – 8 баллов.

Цель работы

Научиться создавать класс и описывать его свойства и методы. Изучить спецификаторы доступа private и public. Освоить применение конструктора, деструктора, set- и get- методов. Освоить работу с объектами класса: корректно создавать, инициализировать, получать значения свойств, визуализировать и удалять. Научиться выделять память под динамические объекты класса и освобождать ее. Освоить обращение к свойствам и методам динамических объектов. Научиться программировать интерфейс класса и реализацию класса в соответствующих *.h и *.cpp файлах, корректно подключать их к проекту, используя препроцессорную обертку.

Задание на лабораторную работу

1. Задать класс, реализующий операции с данными, в соответствии с индивидуальным заданием (Таблица 14).

2. Написать конструктор и деструктор класса.

3. Свойства объектов класса хранить со спецификатором private. Написать методы set и get обращения ко всем свойствами класса.

4. Написать метод визуализации (вывода на экран) свойств класса.

5. Интерфейс, реализацию и вызов объектов класса запрограммировать в трех различных файлах: класс.h, класс.cpp и main.cpp – соответственно.

6. В главной программе продемонстрировать работу со статическими и динамическими переменными – объектами класса: корректно создать, заполнить данными, визуализировать и удалить.

7. В отчете привести листинг программы, скриншоты тестирования программы, рисунок структуры класса. Листинг программы без комментариев не принимается.

 

 

Таблица 14 Варианты индивидуальных заданий

Задание
1. Класс, реализующий операции с комплексными числами (z=x+iy). Вычислять модуль комплексного числа.
2. Класс, хранящий вершины треугольника (x1, y1; x2, y2 и x3, y3) и производящий вычисление длинн его сторон, а также определяющий прямоугольный он или нет.
3. Класс для рисования кругов (хранить радиус R и координаты x,y центра). Вычислять площадь круга и длину окружности.
4. Класс для работы с секундомером. Хранить время и отсчитанное число секунд. Считать секунды до нажатия клавиши, результат переводить в минуты и часы.
5. Класс, хранящий две строки символов s1 и s2. Создать метод, призводящий посимвольное сравнение строк и возвращающий строку несовпадений символов.
6. Класс, хранящий 8 бит информации (флагов) в виде битовых полей. Выполнять поразрядное отрицание "~" хранимого байта, а также операции поразрядное И "&", ИЛИ "|" и исключающее ИЛИ "^" с вводимым байтом.
7. Класс, хранящий два целых аргумента (месяц m и день d) и вычисляющий количество дней, прошедших с начала года.
8. Класс, хранящий три целых аргумента (часы h, минуты m и секунды s) и вычисляющий количество секунд, прошедших с начала дня.
9. Класс, хранящий вектор в трехмерном пространстве (x, y, z) и вычисляющий модуль этого вектора.
10. Класс, хранящий дату дня рождения (месяц m и день d) и вычисляющий количество дней, оставшихся до дня рождения от текущей даты (m1, d1)
11. Класс, хранящий координаты точки (x,y) на плоскости. Написать метод, определяющий, в каком квадранте находится точка.
12. Класс, хранящий строку s1 символов. Создать метод, призводящий посимвольное сравнение s1 c вводимой строкой s2 и возвращающий строку совпадающих символов, если они есть.
13. Класс, хранящий дату рождения человека. Написать метод, вычисляющий число прожитых дней.
14. Класс, хранящий 8 бит информации – байт флагов b1. Создать методы, выполняющие поразрядный сдвиг влево "<<" и поразрядный сдвиг вправо ">>" на заданное число позиций N. Производить проверку условия N<8.
15. Класс, хранящий (часы h, минуты m и секунды s) и вычисляющий количество секунд, оставшихся до конца суток.
16. Класс, хранящий вектор - пару точек пространства (x1, y1, z1 и x2, y2, z2) и вычисляющий площадь треугольника с вершинами в этих точках и начале координат.
17. Класс, для операций с точками в пространстве (хранить x, y, z - координаты). Вычислять расстояние до начала координат.
18. Класс для хранения координат вершин вектора на плоскости (x1, y1 и x2, y2). Вычислить длину этого вектора и его координаты.
19. Класс, хранящий фамилию, имя и отчество человека. Написать метод вывода на экран полной информации и сокращенной – в формате «Фамилия И. О.».
20. Класс, хранящий две строки символов s1 и s2 разной длины. Создать метод, выводящий на экран наибольшую из них и вычисляющий количество символов в каждой.
21. Класс, хранящий параметры сфер в пространстве (радиус R и координаты центра – x, y, z). Написать метод, определяющий пересекается ли заданная сфера с другой – координаты которой (R2, x2, y2, z2).
22. Класс для хранения координат прямоугольных «окон» на экране (хранить координаты левого верхнего и правого нижней вершин x1, y1 и x2, y2). Вычислять площадь окна.

Наследование

Наследование – это механизм создания нового класса на основе ранее созданного. Наследование имеет смысл, если множество разнородных объектов имеют общие характеристики или функции. Рассмотрим пример классов для работы с графическими примитивами (прямая линия, эллипс, прямоугольник и пр.). Для любых графических объектов тип, цвет и толщина линии, координаты описываются одинаково на уровне языка программирования и логически отностятся к одной категории – свойства графического примитива. Поэтому эти элементы целесообразно выделить в отдельный класс – базовый и на основе него создавать новые классы – дочерние для более детального описания линии, эллипса и прямоугольника.

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

#define MAX_SIZE 1024 class CPos { protected: CPos() {} // конструктор по умолчанию CPos(int x1, int y1, int x2, int y2) // конструктор с параметрами { SetParam(x1,y1,x2,y2); } ~CPos() {} // деструктор public: void SetParam(int x1, int y1, int x2, int y2); protected: int X1, Y1; // левая верхняя точка графического объекта int X2, Y2; // правая нижняя точка графического объекта }; void CPos::SetParam(int x1, int y1, int x2, int y2) { if(x1 >= 0 && x1 <= MAX_SIZE) X1 = x1; if(y1 >= 0 && y1 <= MAX_SIZE) Y1 = y1; if(x2 >= 0 && x2 <= MAX_SIZE) X2 = x2; if(y2 >= 0 && y2 <= MAX_SIZE) Y2 = y2; }

Cоздадим дочерний класс с именем CLine для работы с линией на основе базового CPos. Для этого после имени дочернего класса CLine ставится символ «:», а затем пишется имя базового класса CPos с указанием уровня доступа:

class CLine: public CPos { public: CLine() {} CLine(int x1,int y1, int x2, int y2) {SetParam(x1,y1,x2,y2);} ~CLine() {} void Draw() { printf("Рисование линии от (%d, %d) до (%d, %d)\n", X1, Y1, X2, Y2); } };

Уровень наследования public определяет доступ класса CLine ко всем переменным и функциям класса CPos, которые не являются частными (private). Переменные X1, Y1, X2 и Y2 описаны в разделе protected для возможности их использования в методе Draw() дочернего класса CLine, но они недоступны извне.

Метод Draw() предназначен для визуализации графического объекта, но, изучение графических библиотек не входит в данный курс, и программирование ведется на уровне консольных приложений, в методе Draw() выводится текст, а не рисунок.

Метод SetParam(int, int, int, int) задания координат графического объекта целиком находится в базовом классе CPos и по мере необходимости используется в дочернем классе CLine.

В классе CLine два конструктора, при создании объекта line1 (экземпляра) класса CLine, выполняется сначала конструктор по умолчанию CPos() базового класса, а затем тело конструктора дочернего – CLine().

CLine* line1 = new CLine(); // динамический объект типа CLine CLine line2(10,10,20,20); // статический объект типа CLine

В случае вызова конструктора с параметрами CLine(int, int, int, int) для создания экземпляра line2, выполняется конструктор по умолчанию CPos() базового класса, а затем тело конструктора CLine(int, int, int, int) дочернего класса, в котором выполняется функция SetParam(int, int, int, int) для записи значений координат графического объекта.

Использовать только конструктор по умолчанию не всегда удобно. Можно указать явно, какой конструктор базового класса вызывать из конструктора класса-потомка:

class CLine: public CPos { public: CLine(): CPos() {} CLine(int x1,int y1, int x2, int y2): CPos(x1,y1,x2,y2) {} ~CLine() {} void Draw() { printf("Рисование линии от (%d, %d) до (%d, %d)\n", X1, Y1, X2, Y2); } };

Теперь конструктор CLine() будет вызывать конструктор CPos() базового класса, а конструктор с параметрами CLine(int, int, int, int) будет вызывать конструктор CPos(int, int, int, int). При этом функция SetParam() в теле конструктора CLine(int, int, int, int) не нужна, т.к. необходимая инициализация переменных будет выполнена при вызове конструктора с параметрами CPos(int, int, int, int) базового класса.

В рассматриваемой задаче, класс CPos является вспомогательным, при этом нет необходимости создавать его экземпляр для непосредственной работы с ним. Поэтому целесообразно защитить его от возможности создания, поместив конструкторы данного класса в раздел protected. Такие классы называются абстрактнымиклассами, т.е. они не могут существовать как самостоятельные объекты, а служат для создания новых, дочерних классов. Public- функции абстрактных классов CPos можно вызывать, например, через объект класса-потомка CLine:

CLine line; line.SetParam(10,10,20,20); // вызов метода абстрактного класса CPos line.Draw();

Для работы с другими графическими примитивами (прямоугольником и эллипсом) подобным образом можно создать дочерние классы от CPos, отличающиеся друг от друга реализацией функции Draw():

class CRect: public CPos { public: CRect(): CPos() {} CRect(int x1,int y1, int x2, int y2): CPos(x1,y1,x2,y2) {} ~CRect() {} void Draw() { printf("Рисование прямоугольника (%d, %d):(%d, %d)", X1, Y1, X2, Y2); } }; class CEllipse: public Cpos { public: CEllipse(): CPos() {} CEllipse(int x1,int y1, int x2, int y2): CPos(x1,y1,x2,y2) {} ~CEllipse() {} void Draw() { printf("Рисование эллипса (%d, %d):(%d, %d)", X1, Y1, X2, Y2); } };
Поделиться:





Воспользуйтесь поиском по сайту:



©2015 - 2024 megalektsii.ru Все авторские права принадлежат авторам лекционных материалов. Обратная связь с нами...