Функция – это именованная
последовательность описаний и операторов, выполняющая какое-либо законченное
действие. Функция может принимать параметры и возвращать значение.
Любая программа на C++ состоит из
функций, одна из которых должна иметь имя main (с нее начинается выполнение программы). Функция начинает
выполняться в момент вызова. Любая функция должна быть объявлена и определена.
Как и для других величин, объявлений может быть несколько, а определение только
одно. Объявление функции должно находиться в тексте раньше ее вызова для того,
чтобы компилятор мог осуществить проверку правильности вызова.
Объявление функции (прототип, заголовок,
сигнатура) задает ее имя, тип возвращаемого значения и список передаваемых
параметров.
[ класс ] тип имя ([ список_параметров
])[throw ( исключения
)];
int sum(int a, int b); // объявление функции
Определение функции
содержит, кроме объявления, тело функции, представляющее собой
последовательность операторов и описаний в фигурных скобках:
[ класс ] тип имя ([ список_параметров
])[throw ( исключения
)] { тело функции }
int sum(int a, int b) { return (a + b);} // определение функции
Рассмотрим составные части определения.
С помощью необязательного модификатора класс
можно явно задать область видимости функции, используя ключевые слова extern и static:
•
extern –
глобальная видимость во всех модулях программы (по умолчанию);
•
static –
видимость только в пределах модуля, в котором определена функция.
Тип возвращаемого функцией
значения может быть любым, кроме массива и функции (но может быть указателем на
массив или функцию). Если функция не должна возвращать значение, указывается
тип void.
Имя должно быть уникальным,
если используется модификатор extern.
Желательно, чтобы имя несло смысловую нагрузку (отражало действия выполняемые
функцией).
Список параметров определяет
величины, которые требуется передать в функцию при ее вызове. Элементы списка
параметров разделяются запятыми. Для каждого параметра, передаваемого в
функцию, указывается его тип и имя (в объявлении имена можно опускать).
В заголовке функции можно задать список
исключений, которые она может прямо или косвенно порождать. Поскольку
заголовок является интерфейсом функции, указание в нем списка исключений дает
пользователям функции необходимую информацию для ее использования, а также
гарантию, что при возникновении непредвиденного исключения эта ситуация будет
обнаружена.
Типы исключений перечисляются в скобках
через запятую после ключевого слова throw, расположенного за списком параметров функции, например:
void fl() throw (int, const char*){ /* Тело функции */ }
void f2() throw (Oops*){ /* Тело функции */ }
Функция fl должна генерировать исключения только
типов int и const char*. Функция f2 должна генерировать только
исключения типа указателя на класс Oops или производных от него классов.
Если ключевое слово throw не указано, функция может
генерировать любое исключение. Пустой список означает, что функция не должна
порождать исключений:
void f() throw
(){ Тело функции, не порождающей исключений }
Указание списка исключений ни к чему не
обязывает – функция может прямо или косвенно породить исключение, которое она
обещала не использовать. Эта ситуация обнаруживается во время исполнения
программы и приводит к вызову стандартной функции unexpected, которая по умолчанию
вызывает функцию terminate. Функция terminate по умолчанию вызывает функцию abort, которая завершает выполнение программы.
В определении, в объявлении и при
вызове одной и той же функции типы и порядок следования параметров должны
совпадать. На имена параметров ограничений по соответствию не
накладывается, поскольку функцию можно вызывать с различными аргументами, а в
прототипах имена компилятором игнорируются (они служат только для улучшения
читаемости программы). Тип возвращаемого значения и типы параметров совместно
определяют тип функции.
Для вызова функции в простейшем случае
нужно указать ее имя, за которым в круглых скобках через запятую перечисляются
имена передаваемых аргументов. Вызов функции может находиться в любом месте
программы, где по синтаксису допустимо выражение того типа, который формирует функция.
Если тип возвращаемого функцией значения не void, она может входить в состав выражений или, в частном случае,
располагаться в правой части оператора присваивания.
Пример функции, возвращающей сумму двух
целых величин:
int sum(int a, int b){ return (a + b);} // определение функции
…
int a = 2, b = 3, c, d;
с = sum(a, b); // вызов функции
cin >> d;
cout << sum(c, d); // вызов функции
Определение функции должно находится до
функции main(). Все
величины, описанные внутри функции, а также ее параметры, являются локальными.
Областью их действия является функция. При вызове функции, как и при входе в
любой блок, в стеке выделяется память под локальные автоматические переменные.
Кроме того, в стеке сохраняется содержимое регистров процессора на момент,
предшествующий вызову функции, и адрес возврата из функции для того, чтобы при
выходе из нее можно было продолжить выполнение вызывающей функции.
При выходе из функции соответствующий
участок стека освобождается, поэтому значения локальных переменных между
вызовами одной и той же функции не сохраняются. Если этого требуется
избежать, при объявлении локальных переменных используется модификатор static:
#include <iostream.h>
void f(int a)
{
int m = 0;
cout << "n m p\n";
while (a--)
{
static int n = 0;
int p = 0:
cout << n++ << ' ' << m++ << ' ' << p++
<< '\n' ;
}
}
int main(){ f(3); f(2); return 0;}
Статическая переменная n размещается в
сегменте данных и инициализируется один раз при первом выполнении оператора,
содержащего ее определение. Автоматическая переменная m инициализируется при каждом входе в
функцию. Автоматическая переменная р инициализируется при каждом входе в блок
цикла. Программа выведет на экран:
n m р
0 0 0
1 1 0
2 2 0
n m р
3 0 0
4 1 0
|