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

Перегрузка операторов




Классы в языке С++ предоставляют возможность переопределять работу некоторых операторов таких как «=», «+», «*», «new», «delete», «==», «>», «<» и др. Это дает возможность упрощать текст программы и повышать качество программирования. Преимущества от перегрузки операторов удобно продемонстрировать при работе со строками, которые в базовом языке С++ представляют собой массивы символов и операции присваивания, добавления и сравнения строк становятся сложными. Зададим класс TString, в котором будут описаны алгоритмы обработки строковой информации.

#define MAX_LENGTH 1024class TString { public: TString() { buff[0]='\0'; } TString(const char* str) { strcpy(buff,str); } ~TString() {} char* Get() { return buff; } void Set(const char* str) { strcpy(buff,str); } void operator = (const char* str) { strcpy(buff,str); } private: char buff[MAX_LENGTH]; };

В данном классе описано два конструктора для возможности создания пустой и некоторой начальной строк. Кроме того, задано два метода: Get() и Set(), через которые осуществляется доступ к массиву buff[], являющимся частным свойством класса.

TString str; str.Set(“Hello World”); printf(“%s”,str.Get());

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

Обратите внимание, что перед оператором ставится возвращаемый им тип, в данном случае void. После перегрузки оператора присваивания с классом TString становятся возможны следующие действия:

TString str; str = “Hello World”;

Здесь при выполнении операции присваивания активизируется алгоритм, записанный в теле оператора «=», а именно функция strcpy(), в которой указатель str указывает на строку символов, стоящих справа от оператора присваивания.

Особенностью перегрузки данного оператора является то, что он будет работать только в том случае, когда его правый аргумент является массивом символов, и не будет выполняться в случае присваивания одного класса TString другому:

TString str, dst(“Hello”); str = dst; // код в этой строке работать не будет

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

void operator = (const char* str) { strcpy(buff,str); } void operator = (TString & str) { strcpy(buff, str.Get()); }

В итоге, при реализации строки

str = dst;

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

В представленном примере перегрузки аргументом является ссылка на класс TString, а не представитель этого класса. Это сделано, для того чтобы при реализации оператора присваивания не происходило копирование класса TString при передаче аргумента и (см. § 4.1), таким образом, экономилась память ЭВМ и увеличивалась скорость работы.

Следующим шагом оптимизации работы со строками выполним перегрузку оператора добавления одной строки другой, которая будет определяться символом «+». Желательно использовать для вызова оператора «+» запись вида

str = str + “ добавление”;

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

char* operator + (const char* str) { return strcat(buff,str); } char* operator + (TString& str) { return strcat(buff, str.Get()); }

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

bool operator == (const char* str) { if(strcmp(str,buff) == 0) return true; else return false; }bool operator == (TString str) { if(strcmp(str.Get(),buff) == 0) return true; else return false; }

В результате получаем следующее описание класса TString:

class TString { public: TString() { buff[0]='\0'; } TString(const char* str) { strcpy(buff,str); } ~TString() {} char* Get() { return buff; } void SetString(const char* str) { strcpy(buff,str); } void operator = (const char* str) { strcpy(buff,str); } void operator = (TString& str) { strcpy(buff,str.Get()); } char* operator + (const char* str) {return strcat(buff,str);} char* operator + (TString& str) { return strcat(buff, str.Get(); } bool operator == (const char* str) { if (strcmp(str,buff) == 0) return true; else return false; } bool operator == (TString str) { if (strcmp(str.Get(),buff) == 0) return true; else return false; } private: char buff[MAX_LENGTH]; };

который можно использовать следующим образом:

int main() { TString str; str = “Hello World”; string dst; dst = dst + str; if(str == dst) printf(“src is equal dst”); else printf(src is’nt equal dst”); return 0; }

Лабораторная работа № 12. Наследование

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

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

Цель работы

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

Закрепить навыки конструирования классов, выделения памяти под динамические объекты класса, освобождения памяти, обращения к их свойствам и методам.

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

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

2. В базовом классе обязательно создать конструктор_по_умолчанию и конструктор_с_параметрами, а также деструктор класса. Продемонстрировать применение в конструкторах классов-потомков соответствующих конструкторов базового класса.

3. Сделать базовый класс абстрактным. Продемонстрировать вызов методов абстрактного класса через объекты класса-потомка.

4. Продемонстрировать использование дружественной функции.

5. Продемонстрировать реализацию виртуальной функции в базовом классе и в классах-потомках.

6. Продемонстрировать перегрузку хотя бы одного оператора.

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

Варианты индивидуальных заданий

Внимание! Варианты индивидуальных заданий составлены таким образом, чтобы продолжать выполнение индивидуального задания из предыдущей лабораторной работы (Лабораторная работа № 11. Классы). Рекомендуется выполнять тот же вариант индивидуального задания, что и в предыдущей работе (Таблица 14).

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

Задание
1. Классы, реализующие операции с матрицами (3х3), составленными из комплексных чисел[1]. Написать метод, вычисления определителя.
2. Классы, производящие полный расчет треугольника1: вычисление длинн его сторон, и углов между ними, а также определяющий, является ли треугольник равнобедренным, равносторонним и/или прямоугольным.
3. Классы для хранения массива из 10 окружностей1. Написать метод, выбирающий пары пересекающихся окружностей и вычисляющий площадь их пересечения.
4. Классы для работы с судейским секундомером1. Хранить время и отсчитанное число секунд для каждого круга (до 10) и для каждого спортсмена (до 10).
5. Классы для построчного сравнения1 двух файлов. Создать метод, определяющий, равны ли файлы и возвращающий файл несовпадений в противном случае.
6. Классы для хранения байта (в виде битовых полей)1. Создать такой метод, чтобы ноль перемещался от разряда к разряду слева направо.
7. Классы для планирвания затрат на подарки к дням рождений1 ваших друзей. Задать Имена друзей, планируемые подарки, их стоимость и выводить оставшиеся в этом году дни рождения и объем необходимых средств.
8. Классы для работы с расписанием событий на день1 – ежедневник. Создать метод, выводящий на экран время, оставшееся до всех еще не прошедших событий.
9. Классы для задания прямой траектории в трехмерном пространстве1 по известному направляющему векторух и стартовой точке А. Создать метод, рассчитывающий, проходит ли траектория через введенную пользователем точку В.
10. Классы для хранения дней рождений1 всех студентов группы, и вычисляющий количество дней до ближайшего. Вычислите суммарный день рождения группы.
11. Классы для определения координат точки1, движущейся по Архимедовой спирали с постоянной скоростью. Написать метод, определяющий, в каком квадранте находится точка в заданный момент времени.
12. Классы для кодирования символьных строк1, последовательно заменяя каждый символ кодовой комбинацией. Создать метод, призводящие закодировать и раскодировать строку по заданному шифру.
13. Классы для хранения дней рождений1 всех студентов группы, и вычисляющий количество дней прожитых каждым. Вычислите сколько дней прожила вся группа.
14. Классы для управления 4 однобайтными выходными портами микроконтроллера (МК) состояние порта хранить в виде битовых полей1. Создать метод, реализующий эффект «бегущего огонька» по всем портам микроконтроллера.
15. Классы для работы с расписанием занятий на неделю1. Создать метод, выводящий на экран время, оставшееся до всех еще не прошедших сегодня занятий.
16. Классы для описания движения метеорита в пространстве1, определить, на каком расстоянии он пройдет от Земли (начало координат).
17. Классы для описания движения планет в пространстве1 по эллиптической орбите вокруг Солнца (начало координат). Вычислять расстояния от Земли (ищи на третьей планете) до других планет Солнечной системы.
18. Классы, позволяющие определить, встретятся ли летящие из заданных точек по заданным векторами1 траекториям космические корабли и на каком минимальном расстоянии друг от друга они пролетят.
19. Классы для базы данных отдела кадров предприятия1. Обрабатывать информацию о должности, отделе, разряде и окладе сотрудника.
20. Классы для кодирования символьных строк1 последовательностью символов азбуки Морзе. Создать метод, призводящие закодировать и раскодировать строку. Учитывать пробелы, концы слов.
21. Классы управления взрывом ракеты, летящей по баллистической траектории и имеющей определенный радиус поражения1. Задав угол наклона траектории, направление и стартовую скорость снаряда, рассчитать момент взрыва для поражения цели с заданными координатами.
22. Классы для хранения массива прямоугольных окон на экране1. Написать метод, выбирающий пары пересекающихся окон и вычисляющий площадь их пересечения.

Шаблоны

- Вот представь: у тебя есть 1000 рублей... Или нет, для круглого счета, пусть у тебя 1024 рубля...

Шаблоны функций

Шаблоны – это средство языка C++, предназначенное для кодирования обобщённых алгоритмов, без привязки к некоторым параметрам (например, типам данных, размерам буферов, значениям по умолчанию). В C++ возможно создание шаблонов функций и классов.

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

template <class T> template <typename T> template <typename T1, typename T2>

Ключевое слово typename говорит о том, что в шаблоне будет использоваться встроенный тип данных, такой как: int, double, float, char и т. д. А ключевое слово class сообщает компилятору, что в шаблоне функции в качестве параметра будут использоваться пользовательские типы данных.

Например, нам нужно запрограммировать функцию, которая выводила бы на экран элементы массива. Задача не сложная, но, чтобы написать такую функцию, мы должны задать тип данных массива, который будем выводить на экран. А если требуется, чтобы функция выводила массивы различных типов – int, double, float и char? Можно воспользоваться перегрузкой функций (см. § 4.2), но придется написать целых 4 функции, которые отличаются только заголовком функции, тело у них абсолютно одинаковое!

Для этого в С++ и придуманы шаблоны функций. Мы создаем один шаблон, в котором описываем все типы данных. А какой тип данных использовать в конкретной реализации, будет определено позже при компиляции функции.

template <typename T> void print_array(const T *array, int count) { for (int ix = 0; ix < count; ix++) cout << array[ix] << " "; cout << endl; }int main() { int iArray[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; double dArray[6] = {1.2345, 2.234, 3.57, 4.67876, 5.346, 6.1545}; float fArray[5] = {1.34, 2.37, 3.23, 4.8, 5.879}; char cArray[4] = {"MARS"}; cout << "\nМассив типа int:\n"; print_array(iArray, 10); cout << "\nМассив типа double:\n"; print_array(dArray, 6); cout << "\nМассив типа float:\n"; print_array(fArray, 5); cout << "\nМассив типа char:\n";print_array(cArray, 4); return 0; }

В листинге перед объявлением функции стоит запись template <typename T>. Как раз эта запись и говорит о том, что функция print_array() на самом деле является шаблоном функции, так как в первом параметре print_array() стоит тип данных const T*. Это определение шаблона с одним параметром – T, причем этот параметр будет иметь один из встроенных типов данных, так как указано ключевое слово typename.

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

// шаблон функции для поиска максимального значения в массиве template <typename myType> myType searchMax(const myType * array, int size) { myType max = array[0]; // максимальное значение в массиве for (int ix = 1; ix < size; ix++) if (max < array[ix]) max = array[ix]; return max; }

Шаблоны классов будут рассмотрены ниже в применении к динамическим структурам.

Поделиться:





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



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