
- •1. Введение
- •2. Элементы языка
- •2.1. Первые программы
- •2.2. Алфавит языка
- •2.3. Комментарии
- •2.4. Типы данных
- •2.5. Целые типы данных
- •2.6. Плавающие типы данных
- •2.7. Константы-строки, или литералы
- •2.8. Директива препроцессора define
- •2.9. Описания
- •2.10. Модификатор const
- •3. Выражения
- •3.1. Операция и выражение присваивания
- •3.2. Арифметические операции
- •3.3. Операции отношения
- •3.4. Логические операции
- •3.5. Побитовые операции
- •3.6. Сдвиги
- •?????3.8. Тернарная или условная операция
- •3.9. Операция следования
- •3.10. Приоритеты операций и порядок вычисления
- •4.6. Оператор выбора switch
- •4.7. Оператор цикла while
- •4.8. Цикл с постусловием do-while
- •4.9. Оператор for
- •4.10. Оператор безусловного перехода
- •4.11. Оператор break
- •4.12. Оператор continue
- •4.13. Оператор return
- •5. Указатели
- •5.1. Определение указателей
- •5.2. Указатели и массивы
- •5.3. Адресная арифметика
- •5.4. Символьные массивы и строки
- •5.5. Многомерные массивы
- •5.6. Указатели и многомерные массивы
- •6. Операция sizeof
- •7. Операции для работы с динамической памятью
- •7.1. Операция выделения памяти new
- •7.2. Операция освобождения памяти delete
- •8. Функции
- •8.1. Определение и вызов функции
- •8.2. Функции. Передача аргументов
- •8.3. Передача многомерных массивов
- •8.4. Указатели на функции
- •8.5. Ссылки
- •8.6. Ссылки в качестве параметров функций
- •8.7. Аргументы по умолчанию
- •8.8. Переопределение функций
- •8.9. Шаблоны функций
- •9. Объявления и определения
- •10. Область существования имени
- •11. Область видимости
- •Здесь будет напечатано
- •12. Классы памяти
- •13. Объявления объектов и типов
- •14. Имена типов
- •15. Синоним имени типа
- •16. Правила преобразования стандартных типов
- •16.1. Явные преобразования
- •16.2. Неявные преобразования стандартных базовых типов
- •16.3. Преобразование производных стандартных типов
- •17. Перечисления
- •18. Классы
- •18.1. Объявление классов
- •18.2. Конструкторы
- •18.3. Деструкторы
- •18.4. Статические члены класса
- •18.5. Указатель this
- •18.6. Статические функции-члены
- •18.7. Указатели на члены класса
- •18.8. Инициализация данных–членов класса
- •18.9. Конструктор копирования и операция присваивания
- •18.10. Дружественные функции
- •18.11. Конструктор и операция new
- •18.12. Вызов деструктора
- •19. Производные классы
- •19.1. Построение производного класса
- •19.2. Защищенные члены класса
- •19.3. Управление уровнем доступа к членам класса
- •19.4. Последовательность вызова конструктора и деструктора при построении производного класса на основе одного базового
- •19.5. Преобразования типов
- •20. Полиморфизм
- •20.1. Раннее и позднее связывание
- •20.2. Виртуальные функции
- •20.3. Абстрактные классы
- •21. Переопределение стандартных операций
- •21.1. Основные определения и свойства
- •21.2. Операции new и delete при работе с абстрактными типами
- •21.3. Использование new при создании динамического объекта абстрактного типа
- •21.4. Операция delete
- •21.5. Преобразование типов
- •22. Некоторые особенности переопределенных операций
- •22.2. Операция [ ]
- •23. Классы и шаблоны
- •24. Списки
- •24.1. Операции над односвязными списками
- •24.2. Двунаправленные и кольцевые списки
- •24.3. Операции над кольцевыми списками
- •25. Стеки
- •25.1. Реализация стека через массив
- •25.2. Реализация стека через динамическую цепочку звеньев
- •26. Двоичные деревья
- •26.1. Определение и построение
- •26.2.Таблицы
- •27. Список литературы
8.4. Указатели на функции
Указатель на функцию определим следующим образом:
Тип_функции (*имя_указателя) (список параметров);
Например,
int (*fptr) (double);
Здесь определяется fptr как указатель на функцию с одним аргументом типа double, которая возвращает значение int. Имя функции без следующих за ним ( ) – это указатель на функцию, который содержит адрес начала кода этой функции.
Пример:
void f1(void){
cout<<”\n Выполняется f1().”;
}
void f2(void){
cout<<”\n Выполняется f2().”;
}
void main(){
void (*ptr)(void);
ptr = f2;
(*ptr)(); //вызов функции f2();
ptr = f1;
(*ptr)(); //вызов f1();
ptr(); //альтернативная запись!
}
Результат:
Выполняется f2().
Выполняется f1().
Выполняется f1().
Иногда удобно использовать формальные параметры функции, являющиеся указателями на функции.
Проиллюстрируем это при решении следующей задачи.
Вычислить интеграл, используя метод трапеций, от двух разных функций.
// Файл TRAP.CPP
double trap(double a, double b, int n, double (*func)(double)){
double x, h = (b-a)/n, i = ((*func) (a) + (*func) (b))/2;
for (x = a; n >1; n – –) i + = (*func)(( x+=h );
return h*i; }
//Файл INTEGRAL.CPP
#include <iostream.h>
#include <math.h>
#include <stdlib.h>
#include “trap.cpp“
double f1(double x){
return x*x+sin(3+x);}
double f2(double x){
return x/(x*x+1)+exp(-2*x*x);}
void main( ){
double a=1, b=3;
double i = trap(a, b, 50, f1);
cout <<”интеграл от первой функции = ”<<i<<’\n’;
i = trap(a, b, 50, f2);
cout <<”интеграл от второй функции = ”<<i<<’\n’;
}
Отметим, что в теле функции trap можно также писать обращения func(a), func(b) и т.д.
8.5. Ссылки
Тип “ссылка на тип” определяется так: тип&, например:
int& или double&
Ссылочные типы устанавливают псевдонимы объектов. Ссылка обязательно должна быть инициализирована. После инициализации использование ссылки дает тот же результат, что и прямое использование переименованного объекта.
Рассмотрим инициализацию ссылки:
int i=0;
int& iref = i;
Здесь создана новая переменная типа ссылка на int с именем iref. Физически iref – это постоянный указатель на int и, следовательно, значение ссылки после инициализации не может быть изменено. Инициализирующим значением в нашем случае является адрес переменной i, т.е. при инициализации ссылка ведёт себя как указатель.
При использовании ссылка ведёт себя не как указатель, а как переменная, адресом которой она инициализирована:
iref ++; // то же, что и i++;
int *ip=&iref; // то же, что и ip=&i.
Итак, iref стало другим именем, псевдонимом переменной i.
Ссылку можно определить так:
ссылка есть такой постоянный указатель на объект, к которому всегда при его использовании неявно применяется операция разрешения указателя *.
Если тип инициализированной ссылки не совпадает с типом объекта, создаётся новый анонимный объект, для которого ссылка является псевдонимом. Инициализатор преобразуется и его значение используется для установки значения анонимного объекта.
double d=0.0;
int& ir = d; // Создан анонимный объект типа int;
ir = 3.0; // d – не меняется!
Здесь создаётся анонимная переменная типа int, которая инициализируется значением, полученным в результате преобразования значения типа double к типу int. Затем ссылка инициализируется значением адреса этой переменной.
Анонимный объект создаётся также, когда инициализатор не является объектом, например, является константой:
int& ir = 3; // Анонимный объект получил значение 3.
Здесь сначала создается анонимный объект типа int и он инициализируется значением 3. После этого создаётся ссылка ir и инициализируется адресом анонимного объекта. Теперь ir - его псевдоним и оператор
ir = 8;
устанавливает новое значение этого анонимного объекта.