Int foreground; // Цвет символа
Int background; // Цвет фона
Bool blink; // Мигание включено/выключено
};
Void main()
{
Cell screen[25][80];
...
}
Перегрузка операторов
В 3-й лекции (п. 4) были описаны средства перегрузки функций. Си++ допус-
кает перегрузку не только функций, но и операторов, таких, как _______"+", "-", "*" (и боль-
шинство других – "+=", "->" и даже "()"). Средства перегрузки операторов полезны
Тогда, когда желательно, чтобы пользовательские типы данных в исходном тексте
программ выглядели в выражениях подобно встроенным типам Си++. Поясним это на
Нескольких примерах.
Для сложения комплексных чисел (описание структуры см. п.2) можно приме-
нить функцию:
Complex C_add(const Complex& x, const Complex& y)
{
Complex t;
t.re = x.re + y.re;
t.im = x.im + y.im;
return t;
}
Параметры функции "C_add(...)" передаются по ссылке, и, кроме того, опи-
Саны как константы, чтобы запретить изменения параметров внутри функции. Пере-
Дача по ссылке обеспечивает эффективный вызов функции, без копирования парамет-
|
|
Ров, а константное описание защищает параметры от изменений.
106
Допустим, в программе реализована также функция "C_mult(...)" для умно-
Жения двух комплексных чисел. Ниже приведен пример использования этих функ-
ций:
Complex u, v, w, z, t;
...
t = C_add(u, v);
w = C_mult(z, t);
Конечно, более естественной является запись:
Complex u, v, w, z;
...
w = z * (u + v);
Тип "Complex" является типом, введенным пользователем, и, естественно, в
языке Си++ арифметические операторы для этого типа не определены. Поэтому для
естественной записи выражений с числами в виде структур "Complex" надо перегру-
зить операторы сложения и умножения:
Complex operator +(const Complex& x, const Complex& y)
{
Complex t;
t.re = x.re + y.re;
t.im = x.im + y.im;
return t;
}
Complex operator *(const Complex& x, const Complex& y)
{
Complex t;
t.re = x.re*y.re - x.im*y.im;
t.im = x.re*y.im + x.im*y.re;
return t;
}
Правила размещения перегруженных операторов в исходном тексте программ
Аналогичны правилам размещения функций: прототипы отдельно, определения от-
Дельно (возможно, прототипы операторов расположены в заголовочном файле, а оп-
Ределения – в файле реализации).
Аналогично арифметическим операторам, в Си++ допускается перегружать
операторы потокового ввода/вывода ">>" и "<<". Например, вывести комплексное
число на экран можно так:
Void main()
{
Complex u, v;
u.re = 2.1; u.im = 3.6;
v.re = 6.5; v.im = 7.8;
cout << "Числа равны (" << u.re << " + " << u.im << "i) и ";
cout << " (" << v.re << " + " << v.im << "i).\n";
}
107
В результате выполнения этой программы на экране будет напечатана строка:
|
|
Числа равны (2.1 + 3.6i) и (6.5 + 7.8i).
Для упрощения записи операции печати комплексного числа на экране можно
перегрузить оператор вывода в поток:
ostream& operator <<(ostream& s, const Complex& x)
{
s << "(" << x.re << " + " << x.im << "i)";
return s;
}
Void main()
{
Complex u, v;
u.re = 2.1; u.im = 3.6;
v.re = 6.5; v.im = 7.8;
cout << "Числа равны " << u << " и " << v << ".\n";
}
В определении оператора фигурирует тип "ostream". Это класс "поток выво-
да", объектом которого является стандартный поток вывода на экран "cout". Для по-
Токового ввода/вывода в файл необходимо перегружать операторы применительно к
классам "ofstream" и "ifstream" (см. 4-ю лекцию).
Применение структур для реализации стека
Абстрактный тип данных "стек" кратко рассматривался в 8-й лекции (компиля-
Тор использует стек для организации вызовов функций). Стек встречается не только в
Компиляторах, но и во многих численных алгоритмах. В данном параграфе рассмат-
риваются два варианта реализации стека на Си++ с помощью структур.
Среди значений английского слова "stack" есть значения "пачка" и "стопа". Аб-
страктный тип данных, соответствующий принципу "последним прибыл – первым
обслужен" получил свое название из-за своего сходства со стопкой тарелок (рис. 1).
Рис. 1..Поведение стека при записи и чтении элементов.
Основные свойства стека:
Элементы добавляются или удаляются только сверху стека.
2) Для добавления элемента применяется функция "push()".
3) Для удаления элемента применяется функция "pop()".
108
Реализация стека на основе статического массива
В качестве задачи поставим разработку стека для хранения вещественных чи-
Сел. Свойства стека очень просты, поэтому для работы со стеком, например, из 20-ти
Вещественных чисел достаточно несложно написать программу, похожую на про-
Грамму 6.1.
#include <iostream.h>
struct Stack {
double v[20];
int top;
};
void push(Stack& s, double val)
{
s.v[s.top] = val;
s.top++;
}
double pop(Stack& s)
{
return s.v[--(s.top)];
}
void init(Stack& s)
{
s.top = 0;
}
bool full(Stack& s)
{
return s.top >= 20;
}
Void main()
{
Stack s;
Init(s); // Инициализация стека
Push(s, 2.31); // Помещение в стек первого элемента
Push(s, 1.19); // Помещение в стек второго элемента
cout << pop(s) << '\n'; // Извлечение верхнего элемента
// и вывод его на экран
Push(s, 6.7); // Помещение в стек элемента
push(s, pop(s)+pop(s)); // Замена двух верхних элементов
// стека их суммой
}
Программа 6.1.
В программе 6.1 стек реализован на базе статического массива, один из элемен-
Тов которого играет роль верхушки стека. Индекс этого элемента хранится в компо-
Ненте top. (рис. 2).
109
Рис. 2..Стек на основе массива с фиксацией верхушки стека. Серым цветом
Обозначены помещенные в стек элементы.
Недостатки структуры данных Stack
Приведенному в п. 6.1 простейшему варианту реализации стека (в виде струк-
туры "Stack") присущи ряд недостатков, которые можно разбить на две группы:
1) Малая гибкость применения
• У стека ограниченный размер (20 элементов).
• В стеке могут храниться только значения типа double.
• Имена функций наподобие "full()" и "init()" очень распростра-
Нены и может возникнуть конфликт этих имен с именами функций из
Других библиотек.
2) Безопасность использования стека
• Внутренние переменные стека не защищены от изменений извне. По-
Этому стек легко повредить путем изменения значений компонент