- •Издано в рамках Инновационной образовательной программы ннгу: Образовательно-научный центр «Информационно-телекоммуникационные системы: физические основы и математическое обеспечение»
- •Глава 1. Основные понятия 13
- •Глава 3. Работа с числовыми данными 42
- •Глава 4. Операторы. Ключевые слова 52
- •Глава 5. Управление и циклы 64
- •Глава 6. Массивы 77
- •Глава 7. Функции 84
- •Глава 8. Символы и строки 102
- •Глава 9. Препроцессор 113
- •Глава 10. Указатели и ссылки 119
- •Глава 11. О файлах и командной строке 133
- •Глава 12. Работа с экраном дисплея 145
- •Глава 13. Внутреннее представление чисел 157
- •Глава 14. Структуры, перечисления, объединения 179
- •Глава 15. Классы 204
- •Глава 16. Программы из нескольких файлов 233
- •Глава 21. Шаблоны, исключения 321
- •Предисловие
- •Глава 1.Основные понятия
- •1.1.Элементы языка программирования
- •Алфавит
- •Лексемы
- •Выражения
- •Функции
- •Комментарии
- •1.2.Процесс создания программы
- •1.3.Первая программа Программа 1. Приветствие
- •1.4.Состав программы
- •Загрузка
- •Работа с окнами
- •Настройка среды
- •Указание каталогов библиотек
- •Подключение графической библиотеки
- •Назначение текущего каталога
- •Работа с блоками текста в редакторе
- •Выполнение программы
- •Отладка программ
- •Программа 2. Деление чисел
- •Синтаксические ошибки
- •Ошибки в процессе работы программы
- •Трассировка программ
- •Просмотр текущих значений выражений
- •Разработка консольных приложений
- •Программа 3. Hello
- •Выполнение и отладка программы
- •Файлы проекта
- •Автоматическая генерация кода
- •Особенности ввода и вывода
- •Глава 3.Работа с числовыми данными
- •3.1.Целые типы
- •Целые константы
- •Программа 4. Операции над целыми
- •3.2.Числа с плавающей точкой
- •Плавающие константы
- •3.3.Ввод и вывод чисел
- •Программа 5. Точность плавающих чисел
- •3.4.Логический тип и логические операции
- •3.5.Математические функции
- •Глава 4.Операторы. Ключевые слова
- •4.1.Операторы
- •Унарные операторы
- •Бинарные операторы
- •Оператор запятая
- •Условное выражение
- •Операторы присваивания
- •4.2.Приоритеты операторов
- •4.3.Ключевые слова
- •Продолжение таблицы 23. Ключевые слова стандарта языка Cи
- •4.4.Структура программы
- •Объявления переменных
- •Объявления и определения
- •Инструкции и блоки
- •4.5.Константы
- •Задачи 1-17 . Простейшие вычисления
- •Глава 5.Управление и циклы
- •5.1.Условный оператор
- •Программа 6. Максимальное из двух чисел
- •5.2.Операторы цикла
- •Цикл с предусловием while
- •Программа 7. Суммирование цифр целого
- •Цикл for
- •Программа 8. Поиск максимума и минимума
- •Цикл do-while
- •Программа 9. Вычисление квадратного корня
- •5.3.Переключатель
- •Программа 10. День недели
- •5.4.Операторы break и continue
- •Программа 11. Сумма положительных чисел
- •Задачи 18-52. Выбор и циклы
- •Глава 6.Массивы
- •6.1.Одномерные массивы
- •Программа 12. Проверка упорядоченности массива
- •6.2.Двумерные массивы
- •Программа 13. Подсчет выручки
- •Задачи 53-69. Одно- и двумерные массивы
- •Глава 7.Функции
- •7.1.Определение функции
- •7.2.Формальные параметры и фактические аргументы
- •Пpограмма.14. Степени целых чисел
- •7.3.Автоматические и статические переменные
- •Программа 15. Автоматические и статические переменные
- •7.4.Прототипы функций
- •7.5.Массивы как аргументы функций
- •7.6.Внешние переменные
- •Программа 16. Сортировка массива
- •7.7.Рекурсия
- •Программа 17. Рекурсивная печать целого
- •7.8.Перегруженные имена функций
- •Программа 18. Перегрузка функций
- •7.9.Аргументы функций по умолчанию
- •Программа 19. Аргументы по умолчанию
- •Задачи 70-96. Функции
- •Глава 8.Символы и строки
- •8.1.Символы
- •Символьные константы
- •Программа 20. Представления символов
- •Ввод и вывод символов
- •Программа 22. Печать текста по словам
- •8.2.Строки символов
- •Строковые константы
- •Ввод и вывод строк
- •Средства работы со строками
- •Программа 23. Реверсирование строк
- •Задачи 97-121. Символы и строки
- •Глава 9.Препроцессор
- •9.1.Директивы препроцессора
- •9.2.Макросы
- •Программа 24. Возможности препроцессора
- •Задачи 122-124. Макросы
- •Глава 10.Указатели и ссылки
- •10.1.Указатели и адреса
- •Программа 25. Расчет треугольника
- •10.2.Указатели и массивы
- •10.3.Адресная арифметика
- •10.4.Символьные указатели
- •10.5.Массивы указателей
- •Программа 26. Названия месяцев
- •10.6.Указатели на функции
- •Программа 27. Поиск максимума функции
- •10.7.Ссылки
- •Программа 28. Использование ссылок
- •10.8.Операторы new и delete
- •Программа 29. Выделение и освобождение памяти
- •Задачи 125-134. Указатели и ссылки
- •Глава 11.О файлах и командной строке
- •11.1.Знакомство с файлами
- •Программа 30. Копирование файлов
- •11.2.Командная строка
- •11.3.Перенаправление стандартного ввода и вывода на файл
- •11.4.Аргументы командной строки
- •Программа 31. Эхо аргументов командной строки
- •Программа 32. Печать строк, содержащих образец
- •Задачи 135-147. Файлы и командная строка
- •Глава 12.Работа с экраном дисплея
- •12.1.Текстовый режим
- •Программа 33. Российский флаг
- •12.2.Графический режим
- •Графические драйверы и режимы
- •Инициализация графики
- •Функции рисования
- •Программа 34. Звезда
- •Задачи 148-158. Работа с экраном
- •Глава 13.Внутреннее представление чисел
- •13.1.Двоичная система счисления
- •13.2.Беззнаковые целые
- •13.3.Двоичный дополнительный код
- •13.4.Двоичный код с избытком
- •13.5.Побитовые операторы
- •Программа 35. Побитовые операторы
- •13.6.Дробные числа в двоичной системе
- •13.7. Внутреннее представление плавающих типов
- •13.8.Преобразование типов
- •Значения логических выражений
- •Арифметические преобразования
- •Преобразование при присваивании
- •Явное приведение типа
- •Задачи 159-166. Побитовые операторы
- •Глава 14.Структуры, перечисления, объединения
- •14.1.Объявление структур
- •14.2.Структуры и функции
- •14.3.Указатели на структуры
- •Программа 36. Точки и прямоугольники на экране
- •14.4.Массивы структур
- •Программа 37. Подсчет ключевых слов
- •14.5.Перечисления
- •Программа 38. Использование перечислений
- •14.6. Объединения
- •Программа 39. Внутреннее представление float
- •14.7.Битовые поля
- •14.8.О бинарных файлах
- •Программа 40. Анализ успеваемости
- •Задачи 167-174. Структуры
- •Глава 15.Классы
- •Программа 41. Время как структура
- •15.2.Встроенные функции
- •15.3.Классы. Скрытие данных
- •Программа 42. Класс дат
- •15.4.Конструкторы
- •Программа 43. Конструкторы в классе дат
- •15.5.Статические члены класса
- •Программа 44. Размер класса и объектов класса
- •15.6.Друзья класса
- •Программа 45. Статические члены и друзья класса
- •15.7.Копирование объектов класса
- •Программа 46. Копирование объектов
- •15.8.Управление доступом
- •Структуры и классы
- •Правила доступа
- •15.9.Ссылка на себя
- •Программа 47. Модификация дат
- •15.10.Деструкторы
- •Программа 48. Деструктор в классе дат
- •Программа 49. Многоугольники
- •Задачи 175-185. Работа с классами
- •Глава 16.Программы из нескольких файлов
- •16.1.Работа с проектами
- •16.2.Область действия имен
- •Программа 50. Глобальные и локальные имена
- •Статические имена
- •Программа 51. Сумматор чисел
- •16.3.Заголовочные файлы
- •Страж включения
- •Понятие стека
- •Программа 52. Реализация стека в виде массива
- •16.4.Пространства имен
- •Стандартные пространства имен
- •Задачи 186-189. Работа со стеком
- •Глава 17.Перегрузка операторов
- •Программа 53. Обыкновенные дроби
- •17.1.Правила перегрузки операторов
- •Программа 54. Комплексные числа
- •Задачи 190-196. Перегрузка операторов
- •Глава 18.Конструктор копирования и оператор присваивания
- •18.1.Проблемы при копировании
- •Программа 55. Вектора на плоскости
- •Задачи 197-198. Конструктор копирования
- •Глава 19.Ввод и вывод
- •19.1.Вывод
- •19.2.Ввод
- •19.3.Ввод и вывод определяемых пользователем типов
- •Программа 56. Перегрузка операторов ввода/вывода
- •19.4.Работа с файлами
- •Программа 57. Сравнение текстового и бинарного файлов
- •Задачи 199-202. Ввод и вывод
- •Глава 20.Взаимоотношения классов
- •20.1.Объекты как члены класса
- •20.2.Конструкторы встроенных типов
- •Программа 58. Личные данные
- •20.3.Наследование
- •Пример наследования
- •Программа 59. Наследование
- •Управление доступом при наследовании
- •Наследование и конструкторы
- •Программа 60. Производный класс личных данных
- •20.4. Виртуальные функции
- •Программа 61. Невиртуальные функции
- •Программа 62. Виртуальные функции
- •20.5.Абстрактные классы
- •Программа 63. Абстрактный класс фигур
- •Вызов виртуальных функций
- •20.6. Совместимость типов
- •20.7.Множественное наследование
- •Программа 64. Системы уравнений Класс алгебраических векторов Vector
- •Класс прямоугольных матриц
- •Объявление класса Matrix
- •Реализация класса Matrix
- •Класс систем линейных уравнений
- •Пример использования классов
- •Задачи 203-212. Наследование классов
- •Глава 21.Шаблоны, исключения
- •21.1.Шаблоны
- •21.2.Шаблоны функций
- •Программа 65. Объявление и определение шаблона функции
- •21.3.Классы и шаблоны
- •Программа 66. Шаблон классов векторов
- •Программа 67. Шаблон классов динамических массивов
- •21.4.Обработка исключений
- •Программа 68. Расчет нод
- •21.5.Стандартная библиотека шаблонов
- •Программа 69. Использование шаблона векторов
- •Литература
- •Предметный указатель
- •603950, Н. Новгород, пр. Гагарина, 23
- •603000, Н. Новгород, ул. Б. Покровская, 37.
17.1.Правила перегрузки операторов
Перегружены могут быть любые операторы языка C++ (они перечислены в табл.20), за исключением операторов:
. .* :: ?:
Нельзя менять синтаксис операторов, например, нельзя определить оператор перемножения сразу трех дробей, так как встроенный оператор умножения – бинарный:
Fraction operator*(Fraction a, Fraction b, Fraction c); // Ошибка,
// 3 сомножителя
Для перегруженных операторов сохраняются приоритеты и порядок выполнения, указанные в табл.20.
Функция-оператор должна или быть членом класса, или иметь аргумент типа класса. Нельзя определить функцию-оператор, имеющую аргументы только встроенных типов, например, нельзя определить функцию-оператор сложения int и double:
int operator+(int, double); // Ошибка, аргументы только
// встроенных типов
Нельзя изобрести новый знак оператора, например,
Fraction operator@(); // Ошибка, несуществующий оператор @
Программа 54. Комплексные числа
В данной программе приводятся дополнительные примеры использования перегрузки операторов.
Назовем модуль для класса комплексных чисел UnComplex. В файле UnComplex.h разместим объявление класса комплексных чисел:
// Файл UnComplex.h
#ifndef UnComplexH
#define UnComplexH
#include <math.h>
class Complex
{ // Данные класса
double re, im; // Действительная и мнимая части комплексного числа
public: // Методы класса
Complex() // Конструктор по умолчанию
{ re = 0; im = 0; }
Complex(double x) // Конструктор с одним аргументом, формирование
{ re = x; im = 0; } // комплексного числа по одному вещественному
Complex(double x, double y) // Конструктор с двумя аргументами
{ re = x; im = y; }
double Arg(); // Аргумент комплексного числа
double Abs(); // Модуль комплексного числа
Complex& operator+=(Complex z) // Сложение с присваиванием
{
re += z.re; im += z.im; return *this;
}
Complex& operator-=(Complex z) // Вычитание с присваиванием
{
re -= z.re; im -= z.im; return *this;
}
Complex operator*(Complex); // Перемножение комплексных чисел
Complex operator*(double);// Умножение комплексного на вещественное
Complex operator/(Complex); // Деление комплексных чисел
Complex operator-(); // Унарный минус
void Roots(int m, Complex* rts); // Извлечение корней степени m
void Print(); // Вывод комплексного числа
};
// Объявление функций, не являющихся членами класса Complex
Complex operator+(Complex z, Complex t); // Сложение
Complex operator-(Complex z, Complex t); // Вычитание
Complex operator*(double a, Complex z); // Умножение
Complex Pow(Complex z, int m); //Возведение комплексного в степень m
// Получение комплексного числа по его модулю и аргументу
Complex Polar(double mod, double arg);
#endif
В классе Complex предусмотрены три конструктора, чтобы можно было создавать комплексные числа любым из следующих способов:
Complex z1(1, 2); // z1.re = 1, z1.im = 2
Complex z2(1); // z2.re = 1, z2.im = 0
Complex z3; // z3.re = 0, z3.im = 0
Наличие конструктора позволяет инициализировать комплексные числа при их определении:
Complex z4 = 13; // z4.re = 13, z4.im = 0
Здесь сначала создается безымянное комплексное число Complex(13) с использованием конструктора, которое затем используется для инициализации переменной z4.
Реализацию функций для работы с комплексными числами разместим в файле UnComplex.cpp.
// Файл UnComplex.cpp
#include "UnComplex.h"
#include <iostream.h>
// Функции-члены класса Complex
double Complex::Arg() // Аргумент комплексного числа
{ return atan2(im, re); }
Функция математической библиотеки (заголовочный файл math.h)
double atan2(double y, double x);
возвращает значение arctg(y/x). Она работает корректно, даже когда угол близок к π/2 или -π/2 (x близко к 0).
double Complex :: Abs() // Модуль комплексного числа
{ return sqrt(re * re + im * im); }
Complex Complex :: operator*(Complex z) // Умножение двух комплексных
{
Complex t(re * z.re - im * z.im, re * z.im + im * z.re);
return t;
}
Так как функция умножения является членом класса, ей доступно комплексное число, для которого она вызывается. Это число, представленное re и im, рассматривается как первый сомножитель. Второй сомножитель z передается в функцию как аргумент.
В следующей функции число с плавающей точкой a преобразуется в комплексное число конструктором, а затем используется функция умножения двух комплексных:
Complex Complex :: operator*(double a) // Умножение на double
{
return *this * Complex(a);
}
В функции деления реализованы обычные формулы деления комплексных чисел:
Complex Complex :: operator/(Complex z) // Деление
{
double r = (re * z.re +im * z.im) / (z.re * z.re + z.im * z.im);
double i = (-re * z.im + im * z.re) / (z.re * z.re + z.im * z.im);
return Complex(r, i);
}
Функция получения противоположного по знаку комплексного числа реализована как функция-член без аргументов:
Complex Complex :: operator-() // Унарный минус,
{ // получение комплексного числа
return Complex(-re, -im); // с противоположным знаком
}
Напомним, что комплексное число можно представить в алгебраической, показательной или тригонометрической форме:
.
Здесь x – действительная часть, y – мнимая часть, ρ – модуль комплексного числа, φ – аргумент. Корень степени m находится по формуле:
Функция Roots находит все корни m-й степени из комплексного числа и заносит их в массив rts
void Complex::Roots(int m, Complex rts[]) // Извлечение корней
{ // степени m
double angle = Arg(); // Аргумент
double mod = Abs(); // Модуль
mod = pow(mod, 1.0 / m); // Корень m-й степени из модуля
for(int k = 0; k < m; k++) // Получение m корней
rts[k] = Polar(mod, (angle + 2 * k * M_PI) / m);
}
void Complex::Print() // Функция вывода комплексного числа
{ cout << "(" << re << ", " << im << ")"; }
Функции, не являющиеся членами класса, используют функции-члены для доступа к закрытому представлению комплексного числа.
Complex operator+(Complex z, Complex t) // Сложение
{ return z += t; }
Для реализации сложения двух комплексных использован перегруженный оператор +=, аналогично, для реализации вычитания используется оператор -=.
Complex operator-(Complex z, Complex t) // Вычитание
{ return z -= t; }
//Умножение вещественного на комплексное
Complex operator*(double a, Complex z)
{
return z * a; // Умножение комплексного на double
}
В данной функции используется определенный ранее оператор умножения комплексного числа на действителное.
Следующая функция обеспечивает получение комплексного числа по его модулю и аргументу:
Complex Polar(double mod, double arg)
{ return Complex(mod * cos(arg), mod * sin(arg)); }
Целую степень комплексного числа можно найти по формуле:
.
Функция Pow реализует эту формулу.
Complex Pow(Complex z, int m) // Возведение комплексного числа
{ // в степень m
double angle = z.Arg(); // Аргумент
double mod = z.Abs(); // Модуль
angle *= m; // Увеличение аргумента в m раз
double mp = 1.0; // m-я степень модуля
for(int k = 0; k < m; k++) // находится с помощью
mp *= mod; // произведения
return Polar(mp, angle);
}
В качестве примера использования класса комплексных чисел решим приведенное кубическое уравнение:
.
Его корни можно выразить формулой Кардано:
.
Решение уравнения дают такие комбинации кубических корней, произведение которых равно –p/3.
Функцию main поместим в файле UnMainComplex.cpp.
#include ”UnComplex.h”
#include <iostream.h>
#include <conio.h>
#include "Rus.h"
int main()
{
const double eps = 0.1E-4; // Малое число (точность)
double x, y;
cout << Rus("Решаем приведенное кубическое уравнение \n”
” z^3 + p*z + q = 0\n");
cout << Rus("Введите действительную и мнимую части p: ");
cin >> x >> y;
Complex p(x, y); // Создание коэффициента p
cout << Rus("Введите действительную и мнимую части q: ");
cin >> x >> y;
Complex q(x, y); // Создание коэффициента q
Complex inner[2]; // Массив для квадратных корней
// Массивы для первого и второго кубического корня
Complex root3_1[3], root3_2[3];
Complex D; // Дискриминант кубического уравнения
D = q * q / 4 + p * p * p / 27;
D.Roots(2, inner); // Квадратный корень из дискриминанта
// Первое выражение под куб. корнем
Complex D1 = (-0.5) * q + inner[0];
// Второе выражение под куб. корнем
Complex D2 = (-0.5) * q - inner[0];
D1.Roots(3, root3_1); // Извлечение первого кубического корня
D2.Roots(3, root3_2); // Извлечение второго кубического корня
Complex p3 = -p / 3; // Критерий для отбора корней
Complex eq; // Левая часть уравнения
Complex z; // Переменная для корня
Complex prod; // Произведение кубических корней
// Перебор возможных комбинаций кубических корней
for(int i = 0; i < 3; i++) // Перебор значений первого кубич. корня
for(int j = 0; j < 3; j++){ // Перебор значений второго кубич. корня
prod = root3_1[i] * root3_2[j]; //Произведение кубических корней
double err = (prod - p3).Abs(); //Отклонение произведения от -p/3
if( err < eps){ //Если отклонение мало,
z = root3_1[i] + root3_2[j]; //это корень
cout << Rus("\nКорень z = "); z.Print();
eq = Pow(z, 3) + p * z + q; //Подстановка корня в уравнение
cout << Rus("\nПроверка: z^3 + p*z + q = "); eq.Print();
}
}
getch();
return 0;
}
В качестве примера решим уравнение
,
имеющее корни:
.
Далее приводится диалог с программой.
Решаем приведенное кубическое уравнение
z^3 + p*z + q = 0
Введите действительную и мнимую части p: -2 0
Введите действительную и мнимую части q: 1 0
Корень z = (1, 0)
Проверка: z^3 + p*z + q = (0, 0)
Корень z = (-1.61803, 1.94289e-16)
Проверка: z^3 + p*z + q = (0, 1.13739e-15)
Корень z = (0.618034, 0)
Проверка: z^3 + p*z + q = (0, 0)
