- •Программирование и основы алгоритмизации
- •1. Понятие алгоритма
- •1.1. Определение алгоритма
- •1.2. Гост на описание блок-схем
- •1.3. Виды алгоритмов
- •2. Языки программирования
- •2.1. Определение алгоритмического языка
- •2.2. Классификация языков. История развития языков программирования
- •2.3. Выбор языка программирования
- •2.5. Арифметические и логические основы программирования
- •3. Понятие системы программирования
- •3.1. Этапы создания программ
- •3.2. Конструирование программ
- •3.3. Методы, технологии и инструментальные средства производства программных продуктов
- •4.1. Литералы
- •4.2. Встроенные типы данных
- •4.3. Операции
- •Адресные операции
- •Операции преобразования знака
- •Побитовые операции
- •Операция определения размера
- •Операции увеличения и уменьшения значения
- •Операции динамического распределения памяти
- •Операция доступа
- •Аддитивные операции
- •Мультипликативные операции
- •Операции сдвига
- •Поразрядные операции
- •Операции сравнения
- •Логические бинарные операции
- •Операция присваивания
- •Специальные формы операций присваивания
- •Операции выбора компонентов структурированного объекта
- •Операции обращения к компонентам класса
- •Операция управления процессом вычисления значений
- •Операция вызова функции
- •Операция явного преобразования типа
- •Операция индексации
- •4.5. Агрегатные типы данных
- •4.5.1. Массивы
- •4.5.2. Структуры
- •4.5.3. Поля битов
- •4.5.4. Объединения Используются для хранения значений различных типов в одной и той же области памяти, но не одновременно.
- •4.5.5. Перечисления
- •4.5.6. Переименование типов
- •Typedef имя ранее определенного типа имя нового типа1
- •Объявление typedef применяется для создания удобных распознаваемых имен часто встречающихся и для вложенных типов, а также, чтобы сделать программы переносимыми для различных целых типов.
- •4.6. Обработка символьных и строковых переменных
- •4.7. Указатели
- •4.7.1. Инициализация указателей
- •4.7.2. Операции с указателями
- •4.8. Пользовательские процедуры и функции
- •4.8.1. Перегрузка функций
- •4.8.2. Перегрузка операций
- •4.8.3. Шаблоны функций
- •4.8.4. Возврат из функции нескольких значений
- •4.9. Файлы
- •4.10. Директивы препроцессора
- •Библиографический список
4.8. Пользовательские процедуры и функции
4.8.1. Перегрузка функций
Пусть по ходу программы надо часто печатать значения типа int, double, char*. В старых версиях языка программирования Си требовалось дать этим трем функциям различные имена, в языке С++ стало возможным написать «умную» функцию print, существующую как бы в трех видах.
# include <stdio.h>
void print(int i)
{ printf("%d ", i); }
void print(double x)
{ printf("%lf ", x); } // Можно и {printf("%f ", x); }
void print(char* s)
{ printf("%s ", s); }
void main()
{
int j=5;
float pi=3.14159268;
double e=2.7183;
print(j);
print(pi);
print(e);
print("Hello!\n");
}
Компилятор сам выбирает, какую из трех (!) различных функций с именем print (по терминологии С++ «перегруженных» – overloaded) вызвать в каждом случае. Критерием выбора служат количество и тип аргументов, с которым функция вызывается, причем, если не удается найти точного совпадения (float), то компилятор выбирает ту функцию, при вызове которой « наиболее легко» выполнить для аргументов преобразование типа.
Перегруженные функции различаться только по типу возвращаемого значения не могут:
void f (int, int,);
int f(int, int); // ошибка.
Перегрузка функций не должна приводить к конфликту с аргументами, заданными по умолчанию.
Чтобы сообщить компилятору С++, что имена тех или иных функций не должны перегружаться, их следует объявить как extern «с»:
extern «с» int func 1(int); // отдельная функция
extern «с» // несколько функций
{
void func 2 (int);
int func3 ( );
double func4 (double);
;
Модификатор extern «с» можно использовать и при определении функций. Функции, описанные как extern «с»? не могут быть перегруженными.
4.8.2. Перегрузка операций
В С++ можно заставить привычные операции выполнять те иные, чем обычно действия над определенными типами данных. Например, выполнить перезагрузку оператора @ для выполнения некоторых действий. Тогда достаточно определить функцию с именем operator@ и требуемым числом и типами аргументов так, чтобы эта функция выполняла необходимые действия.
Пример. Переопределим («перегрузим») операцию сложения для данных типа string (строки).
# include <stdio.h>
# include <string.h>
const MAX_STR_LEN=80; // В С++ возможно определение констант
struct String // Структурный тип Строка
{
char s[MAX_STR_LEN]; // Массив символов – "Содержимое" Строки
int str_len; // Текущая длина строки
}; // Переопределим ("перегрузим") оператор сложения для данных типа String
String operator+(String s1, String s2)
{
String TmpStr; // для временного хранения
/* Длина строки-результата сложения равна сумме длины складываемых строк.
Позаботимся также о том, чтобы не выйти за границу отведенного массива*/
if ((TmpStr.str_len=s1.str_len+s2.str_len)>=MAX_STR_LEN)
{
TmpStr.s[0]='\x0';
TmpStr.str_len=0;
return TmpStr; // Вернем нулевую строку.
} // Иначе или далее сольем строки
strcpy(TmpStr.s, s1.s); //s1.s-> TmpStr.s
strcat(TmpStr.s, s2.s); // присоединим s2.s к TmpStr.s
return TmpStr; // и возвратим результат
}
void main()
{
String str1, str2, str3;
strcpy(str1.s, "Перегрузка операторов -"); // Заполнение содержимым
str1.str_len=strlen(str1.s); // Определение текущей длины
strcpy(str2.s, "это очень удобно!");
str2.str_len=strlen(str2.s);
printf("Первая строка: длина=%d, содержимое=%s\n",
str1.str_len, str1.s);
printf("Вторая строка: длина=%d, содержимое=%s\n",
str2.str_len, str2.s);
str3=str1+str2; // Используем перегруженный оператор!
/* Компилятор, ориентируясь на типы слагаемых, генерирует код,
эквалентный вызову str3=operator+(str1,str2);*/
printf("Третья строка:\n длина=%d, содержимое=%s\n",
str3.str_len, str3.s);
}
Результаты
Первая строка: длина =23, содержимое = Перегрузка операторов-
Вторая строка: длина =17, содержимое = это очень удобно!
Третья строка:длина=40, содержимое = Перегрузка операторов - это очень удобно!
Для чисел знак «+» выполняет обычное арифметическое сложение.