Фуннкции

Определение функций

Основная форма записи функции имеет следующий вид

Копировать
тип_возврата имя_функции(список_параметров)
{
	тело_функции
}
Тип данных, возвращаемых фиункцией, задаёться с помощью элемента тип_возврата. Под элементом список_параметров подразумеваеться список разделяемых запатыми переменных которые могут принимать любые аргументы, передаваемой функцией.

В версии C89, если тип данных возвращаемый функцией, явно не задан, то подразумеваеться тип int. В языке C++ и версии C99, тип int по умолчанию, не поддерживаеться, хотя в большенстве компиляторов C++ такое предположение остаёться в силе.

Прототипы функций

В языке C++ все функции должны иметь прототипы, а в языке C прототипы формально необязательны, но весьма желательны. Общая форма определения прототипа имеет следующий вид.

Копировать
тип_возврата имя_функции(список_параметров);
Например.
Копировать
float fn(float x);
//или
float fn(float);

В языке C для задания прототипа функции, не имеющей параметров, вместо списка параметров используеться ключефое слово void. В языке C++ пкстой список параметров в прототипе функцим означает, что функция на имеет параметров. Слово void в этом случае необязательно.

Возврат значений (оператор return)

Возврат значений в функсии осуществляеться с помощью оператора return. он имеет две формы записи.

Копировать
return;
return значение;

В языке C99 и C++ форма оператора return, которая не задаёт возвращаемого значения, должна использоваться только в void-функциях.

Перегрузка функций

В языке C++ функции могут перегружаться. Когда говорят, что функция перегружена, это означает, что две или более функций имеют одинаковые имена, однако все версии перегружных функций имеют различное количество или тип параметров. Расмотрим пример следующие три перегруженые функции.

Копировать
void func (int a){
	cout << "a=" << a << endl;
}
void func (int a, int b){
	cout << "a=" << a << endl;
	cout << "b=" << b << endl;
}
void func(int a, double b){
	cout << "a=" << a << endl;
	cout << "b=" << b << endl;
}
//вызываем
func (10);	//вызов func (int)
func (12, 24);	//вызов func (int, int)
func (99, 123.23);	//вызов func (int, double)

В каждом случае для определения того, какая версия функции func() будет вызвана, анализируеться тип и количество аргументов.

Передача аргументов функции по умолчанию

В языке C++ параметру функции можно присвоить значение по умолчанию, которое автоматически будет использовано в том случае, если при вызове функции соответствующий аргумент не будет задан. Например.

Копировать
void func (int a = 0, int b = 10){}
//вызов
func();
func(-1);
func(-1, 99);

Области видимости и время жизни переменных.

В языках C и C++ определенны правила видимости, которые устанавливают такие понятия как область видимости и время жизни объектов. Различают глобальную область видимости и локальную.

Глобыльная область видимости существует вне всех других обласей.Имя объявленное в глобальной области, известно всей программе. Например глобальная переменная доступна для использования всеми функциями программы. Глобальне переменные существуют на протяжении всего жизненого цикла программы.

Локальная область видимости определяеться границами блока. Имя объявленное внутри локальной области,известно только внутри этой области. Локальные переменные создаються при входе в блок и разрушаються при выходе из него. Это означает, что локальные переменные не хранять своих значений междувызовами функций. Чтобы сохранить значения переменных между вызовами, можно использовать модификатор static.

Рекурсия

В языках C и C++ функции могут вызывать сами себя. Этот процес называют рекурсией, а функцию, которая сама себя вызывает — рекурсивной. В качестве примера приведём функцию fact(), вычисляющую факториал целого числа.

Копировать
int fact (int n)
{
	int ans;
	if (n == 1) return 1;
	ans = fact (n-1) * n;
	return ans;
}

Функция main()

Выполнение C/C++ программы начинаеться с выполнения функции main(). (Windows-прграммы вызывают функцию WinMain() );

Функция main() не имеет прототипа. Следовательно, можно использовать различные формы функции main(). Как для языка C, так и для языка C++ допустимя следующие варианты функции main().

Копировать
int main();
int main(int argc, char *argv[])

Как видно из второй формы записи, ф. main() поддерживает по крайней мере два параметра. Они называються argc и argv. Эти аргументы будут хранить количество аргументов командной строки и указатель на них соответственно. Параметр argc имеет целый тип, и его значение всегда будет не меньше числа 1, поскольку как предусмотренно в языках C и C++, первым аргументом являеться всегда имя программы. Параметр argv должен быть объявлён как массив символьных указателей, в которых каждый элемент указывает на аргумент командной строки. Ниже приведён пример программы, в которой демонстрируеться использование этих аргументов.

Копировать
#include <iostream.h>
int main (int argc? char *argv[])
{
	if (argc < 2) cout << "Введите своё имя.\n";
	else cout << "привет " << argv[1];
	return 0;
}

Передача указателей

Несмотря на то что в языках C и С++ по умолчанию используеться передача параметров по значению, можно вручную построить вызов ф. с передачей параметров по ссылке. Для этого нужно эргументу передать указатель. Поскольку в таком случае функции передаёться адрес аргумента, оказываеться возможным изменять значение аргумента вне функции. Например.

Копировать
void swap (int *x, int *y)
{
	int temp;
	temp = *x;
	*x = *y;
	*y = temp;
}
//вызыов
swap (&a, &b);

В языке C++ адрес переменной можно передат функции автоматически. Это реализуеться с помощью параметра-ссылки. При использовании параметра-ссылки функции передаёться адрес аргумента, и функция работает с аргументом, а не с копией. Чтобы создать параметр-ссылку необхадимо перед его именем поставить символ "амперсанда" (&). Внатри ф. этот параметр можно использовать обычным образом, не принибрегая к оператора "звёздочка" (*), например.

Копировать
void swap (int &x, int &y){
	int temp;
	temp = x;
	x = y;
	y = temp;
}
//вызов
swap (a, b);

Спецификаторы функций

В языке C++ определенны три спецификатора функций:

Спецификатор inline представляет собой обращённое к компилятору требование: вместо создания вызова функции раскрыть её код прямо в строке. Если компилятор не можнт вставить функцию в строку он имеет право проигнорировать это требование. Спецификатором inline могут определяться как функции-члены, так и не функции-члены.

В качестве виртуальной функции (с помощью спецификатора virual) ф. определяеться в базовом класе и переопределяеться в производным классом. На примере виртуальных функций можно понять, как язык C++ поддерживает полифилизм.

Спецификатор explicit применяеться только к конструкторам, Конструктор, определённый как explicit, будет задеёствован только в том случае, когда инициализация в точности соответствует тому, что задано конструктором. Никиких преобразований выполняться не будет (т.е. спецификатор explicit создаёт "неконвертирующий конструктор").

Шаблоны функций

Общая форма определения шаблонной функции имеет следующий вид.

Копировать
tetemplate <class тип> тип_возврата имя_функции (список_параметров)
{
	//тело функции
}
Здесь тип означает метку - заполнител для типа данных, с которыми эта функция фактически будет иметь дело. В операторе template можно определить несколько параметров-типов данных, используя форму списка элементов, разделённых запятыми.

Расмотрим пример.

Копировать
template  void swap (X &a, X &b)
{
	X temp;
	temp = a;
	a = b;
	b = temp;
}
//вызов
int a, b;
float x, y;
swap (a, b);
swap (x, y);

Указатели на функцию

На функцию, как и на любой другой объект языка C, Можно создать указатель. Синтаксиз следующий.

Копировать
тип_возврата (*имя_указателя)(описание_переменных);
Данное объявление создаёт указатель на функцию с именем имя_указателя, в которой содержаться переменные описание_переменных и которая возвращает значение типа тип_возврата.

Функцию с помощью указателя можно вызвать следующим образом.

Копировать
имя_указателя = имя_функции;
переменная = имя_указателя (переменные);
Здесь первая строка создаёт ссылку на функцию имя_функции. Вторая строка собсвенно производит вызов функции через указатель имя_указателя, в которую передаються переменные переменные, возврат значения происходит в переменную переменная.

Следующий пример демонстрирует создание указателя и и два способа вызова функции через указатель, а также передачу функции как параметра другим функциям.

Копировать
double y;
double (*p)(doublr x);
p=sin;			//создание указателя на функцию sin()
y = (*p)(2.5);	//вызов
y = p(2.5);		//вызов

//передача функции как параметра
double y;
double f(double (*c)(double x), double y){
	return c(y);	//вызываем переданную функцию в указатель c и возвращаем значение
}
y = f(sin, 2.5);	//передаём функции f функцию sin, а также параметр каторая будет обрабатываться

Создавать массивы указателей на функции так же можно.

Копировать
int f1(void);
int f2(void);
int f3(void);
int (*p)(void) = {f1, f2, f3}

y = (*p[1])();	//вызов функции f2
y = p[2]();		//вызов функции f3


Смотрите также

Шаблоны