- •6.050201 «Системная инженерия»
- •Донецк, 2012
- •1 Цели и задачи дисциплины
- •2 Теоретические основы программирования
- •2.1 Основные сведения в области информатики Общее понятие алгоритма
- •Алгоритмические языки
- •Типы переменных
- •Целочисленные переменные
- •Кольцо вычетов по модулю m
- •Интерпретация положительных и отрицательных чисел
- •Вещественные переменные
- •Машинный эпсилон
- •Запись вещественных констант
- •Символьные переменные
- •Логические переменные и выражения
- •Массивы
- •Текстовые строки
- •Оперативная память
- •Процессор
- •Cisc и risc-процессоры
- •Алгоритм работы компьютера
- •Аппаратный стек
- •Команды вызова подпрограммы call и возврата return
- •Аппаратный стек и локальные переменные подпрограммы
- •2.2. Стандарты построения блок-схем алгоритмов
- •4 Компиляция и выполнение программ
- •5 Структурное программирование
- •5.1 Описание переменных
- •Константы
- •Целые числа
- •Вещественные числа
- •Логические величины
- •Символы и байты
- •Кодировка, многобайтовые символы
- •5.2 Основные операции и их приоритет
- •Порядок вычисления выражений
- •5.3 Операторы
- •Операторы цикла
- •5.4 Организация ввода-вывода
- •Манипуляторы и форматирование ввода-вывода
- •Строковые потоки
- •Ввод-вывод файлов
- •5.5 Массивы
- •5.6. Указатели и операции над ними
- •5.7 Ссылки
- •5.8 Динамическое выделение памяти
- •5.9 Функции
- •Подставляемые функции
- •Имена функций
- •Необязательные аргументы функций
- •Рекурсия
- •Назначение шаблонов
- •Функции-шаблоны
- •5.10 Область видимости имен
- •5.11 Сложные структуры данных
- •5.11.1 Структуры
- •5.11.2 Перечисления
- •5.11.3. Объединения
- •5.12. Динамические структуры данных
- •6 Препроцессор
- •Определение макросов
- •Условная компиляция
- •Дополнительные директивы препроцессора
- •7 Объектно-ориентированное программирование
- •7.1 Основные понятия объектно-ориентированного программирования
- •Определение методов класса
- •Виртуальные методы
- •Виртуальные методы и переопределение методов
- •Преобразование базового и производного классов
- •Внутреннее и защищенное наследование
- •Абстрактные классы
- •Множественное наследование
- •Виртуальное наследование
- •Интерфейс и состояние объекта
- •Объявление friend
- •7.2 Конструктор и деструктор класса
- •Копирующий конструктор
- •Деструкторы
- •Инициализация объектов
- •Операции new и delete
- •7.3 Перегрузка операций
- •Как определять операции
- •Преобразования типов
- •Явные преобразования типов
- •Стандартные преобразования типов
- •Преобразования указателей и ссылок
- •Преобразования типов, определенных в программе
- •7.4 Использование включаемых файлов
- •7.5. Шаблоны классов
- •"Интеллигентный указатель"
- •Задание свойств класса
- •8 Обработка исключительных ситуаций
- •Примеры обработки исключительных ситуаций
- •Список использованных источников
7.3 Перегрузка операций
Язык Си++ позволяет определять в классах особого вида методы – операции. Они называются операциями потому, что их запись имеет тот же вид, что и запись операции сложения, умножения и т.п. со встроенными типами языка Си++.
Определим две операции в классе String – сравнение на меньше и сложение:
class String
{
public:
. . .
String operator+(const String& s) const;
bool operator<(const String& s) const;
};
Признаком того, что переопределяется операция, служит ключевое слово operator, после которого стоит знак операции. В остальном операция мало чем отличается от обычного метода класса. Теперь в программе можно записать:
String s1, s2;
. . .
s1 + s2
Объект s1 выполнит метод operator с объектом s2 в качестве аргумента.
Результатом операции сложения является объект типа String. Никакой из аргументов операции не изменяется. Описатель const при описании аргумента говорит о том, что s2 не может измениться при выполнении сложения, а описатель const в конце определения операции говорит то же самое об объекте, выполняющем сложение.
Реализация может выглядеть следующим образом:
String
String::operator+(const String& s) const
{
String result;
result.length = length + s.length;
result.str = new char[result.length + 1];
strcpy(result.str, str);
strcat(result.str, s.str);
return result;
}
При сравнении на меньше мы будем сравнивать строки в лексикографической последовательности. Проще говоря, меньше та строка, которая должна стоять раньше по алфавиту:
bool
String::operator<(const String& s) const
{
char* cp1 = str;
char* cp2 = s.str;
while (true) {
if (*cp1 < *cp2)
return true;
else if (*cp1 > *cp2)
return false;
else {
cp1++;
cp2++;
if (*cp2 == 0) // конец строки
return false;
else if (*cp1 == 0) // конец строки
return true;
}
}
}
Как определять операции
Если для класса определяют операции, то обычно определяют достаточно полный их набор, так, чтобы объекты этого класса могли участвовать в полноценных выражениях.
Прежде всего, определим операцию присваивания. Операция присваивания в качестве аргумента использует объект того же класса и копирует значение этого объекта. Однако, в отличие от копирующего конструктора, у объекта уже имеется какое-то свое значение, и его нужно аккуратно уничтожить.
class String
{
public:
// объявление операции присваивания
String& operator=(const String& s);
};
// Реализация присваивания
String&
String::operator=(const String& s)
{
if (this == &s)
return *this;
if (str != 0) {
delete [] str;
}
length = s.length;
str = new char[length + 1];
if (str == 0) {
// обработка ошибок
}
strcpy(str, s.str);
return *this;
}
Обратим внимание на несколько важных особенностей операции присваивания. Во-первых, в качестве результата операции присваивания объект возвращает ссылку на самого себя. Это дает возможность использовать строки в выражениях типа:
s1 = s2 = s3;
Во-вторых, в начале операции проверяется, не равен ли аргумент самому объекту. Таким образом, присваивание s1 = s1 выполняется правильно и быстро.
В-третьих, перед тем как скопировать новое значение, операция присваивания освобождает память, занимаемую старым значением.
Аналогично операции присваивания можно определить операцию +=.
Набор операций, позволяющий задействовать класс String в различных выражениях, представлен ниже:
class String
{
public:
String();
String(const String& s);
String(const char*);
String& operator=(const String& s);
String& operator+=(const String& s);
bool operator==(const String& s) const;
bool operator!=(const String& s) const;
bool operator<(const String& s) const;
bool operator>(const String& s) const;
bool operator<=(const String& s) const;
bool operator>=(const String& s) const;
String operator+(const String& s) const;
};