Добавил:
Преподаватель Колледжа информационных технологий Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Лекции / ФУНКЦИИ

.pdf
Скачиваний:
39
Добавлен:
08.05.2022
Размер:
1.19 Mб
Скачать

ГЛАВА 7. ФУНКЦИИ

 

Оглавление

 

§7.1 Общая форма определения функции ............................................................

1

§7.2 Вызов функции и аргументы .........................................................................

3

§7.3 Возвращаемые значения.................................................................................

6

§7.4 Создание функций с несколькими параметрами .........................................

8

§7.6 Перегрузка функции .....................................................................................

11

§7.7 Передача аргумента по значению................................................................

13

§7.8 Передача аргумента по адресу.....................................................................

14

§7.9 Возврат значений по ссылке, по адресу и по значению............................

18

§7.10 Указатели на функции ................................................................................

23

§7.11 Рекурсия .......................................................................................................

30

§7.12 Делегаты (C#) ..............................................................................................

36

§7.13 Добавление методов в делегат...................................................................

38

§7.1 Общая форма определения функции

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

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

Функция (function) — это подпрограмма, которая может получать параметры на вход и возвращать выходное значение. Чтобы выполнить свою задачу, функция должна быть вызвана. Она является важнейшим элементом процедурного программирования, так как позволяет группировать и обобщать программный код, который может позднее использоваться произвольное число раз.

1

С точки зрения внешней программы функция — это «черный ящик».

Функция определяет собственную (локальную) область видимости, куда входят входные параметры, а, также, те переменные, которые объявляются непосредственно в теле самой функции.

Все функции С++ имеют общую форму, приведенную ниже:

ТИП_ВОЗВРАТА ИМЯ_ФУНКЦИИ(СПИСОК_ПАРАМЕТРОВ)

{

//тело функции

}

Пример объявления функции на С++:

void main()

{

}

При определении функции C# (функции в данном языке программирования называются методами) используется следующая форма:

[модификаторы] ТИП_ВОЗВРАТА ИМЯ_МЕТОДА (СПИСОК_ПАРАМЕТРОВ)

{

//тело метода

}

Пример объявления функции на С#:

static void main()

{

}

Здесь ТИП_ВОЗВРАТА определяет тип данного, возвращаемых функцией. Если функция не возвращает никакого значения, то используется тип void.

Имя функции определяется элементом ИМЯ_ФУНКЦИИ. В качестве имени допускается использовать любой идентификатор, если он еще не занят.

2

СПИСОК_ПАРАМЕТРОВ представляет собой последовательность пар типов и идентификаторов, разделяемых запятыми. Параметры – это переменные, которые получают значения аргументов, передаваемых функции при ее вызове. Аргументы– это значения, которые передаются из caller-а в вызываемую функцию. Если функции не требует параметров, то список параметров будет пуст.

Ключевое слово static является модификатором.

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

§7.2 Вызов функции и аргументы

Применение функции называется вызовом функции (function call).

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

Рассмотрим программу, запрашивающее у пользователя радиус круга, а

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

соответственно, периметр.

Листинг 7.1.

1

#include <iostream>

2

using namespace std;

3

const double Pi = 3.14159;

4

double Area(double InputRadius)

5

{

6

return Pi * InputRadius * InputRadius;

7

}

8

double Circumference(double InputRadius)

9

{

10

return 2 * Pi * InputRadius;

11

}

 

3

12

int main()

13

{

14

cout << "Enter radius: ";

15

double Radius = 0;

16

cin >> Radius;

17

cout << "Area is: " << Area(Radius) << endl;

18

cout << "Circumference is: " << Circumference(Radius)

 

<< endl;

19

return 0;

20

}

 

Результат выполнения программы:

Enter radius: 6.5

Area is: 132.732

Circumference is: 40.8407

Разделение вычисления площади и периметра на отдельные функции

позволяет многократно использовать этот код, поскольку функции можно вызывать неоднократно.

Функции Area() и Circumference() вызываются в функции в строках

17 и 18. Radius – аргумент, передаваемый в функцию Area() и

Circumference(). При вызове выполнение переходит к функции Area(),

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

При вызове функции, все её параметры создаются как локальные переменные, а значение каждого из аргументов копируется в соответствующий параметр (локальную переменную). Этот процесс называется передачей по значению. Например, при вызове функции Area()

значение передаваемого аргумента Radius копировалось в параметр

InputRadius.

Также main() не является единственной функцией, которая может вызывать другие функции. Любая функция может вызывать любую другую функцию.

4

В С++ одни функции не могут быть объявлены внутри других функций

(т.е. быть вложенными). Это приведет к ошибке компиляции.

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

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

Листинг 7.2.

1

int main() {

2

Sum_numbers(1, 2);

3

return 0;

4

}

5

int Sum_numbers(int a, int b) {

6

cout << a + b;

7

}

Так, при вызове функции Sum_numbers() внутри функции main()

компилятор не знает ее полное имя.

Конечно компилятор C++ мог просмотреть весь код и определить полное имя функции, но этого он делать не умеет и нам приходится с этим считаться.

Поэтому мы обязаны проинформировать компилятор о полном имени функции. Для этого мы будем использовать прототип функции.

Прототип функции — это функция, в которой отсутствует блок кода

(тело функции). В прототипе функции находятся:

Полное имя функции.

Тип возвращаемого значения функции.

Вот как правильно должна была выглядеть программа, написанная выше:

 

Листинг 7.3.

 

 

 

1

int Sum_numbers(int a, int b); // прототип функции

 

2

int main() {

 

3

Sum_numbers(1, 2);

 

4

return 0;

 

5

}

 

 

5

 

6

int Sum_numbers(int a, int b) { // сама функция

7

cout << a + b;

8

}

Так, с помощью прототипа мы объясняем компилятору, что полным именем функции является Sum_numbers(int a, int b), и кроме этого мы говорим компилятору о типе возвращаемого значения, у нас им является тип int.

§7.3 Возвращаемые значения

Когда функция main() завершает своё выполнение, она возвращает целочисленное значение обратно в операционную систему, используя оператор return.

Функции, которые мы пишем, также могут возвращать значения. Для этого указывается тип возвращаемого значения. Он указывается при объявлении функции, перед её именем. Обратите внимание, тип возврата не указывает, какое именно значение будет возвращаться. Он указывает только тип этого значения.

Затем, внутри вызываемой функции, мы используем оператор return,

чтобы указать возвращаемое значение. Когда процессор встречает в функции оператор return, он немедленно выполняет возврат значения обратно в caller

и точка выполнения также переходит в caller. Любой код, который находится за return-ом в функции — игнорируется.

Функция может возвращать только одно значение через return обратно в caller. Это может быть либо число (например, 7), либо значение переменной,

либо выражение (у которого есть результат), либо определённое значение из набора возможных значений.

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

6

Рассмотрим простую функцию, которая возвращает целочисленное

значение:

 

 

 

 

 

Листинг 7.4.

 

 

 

 

1

#include <iostream>

 

 

2

using namespace std;

 

 

3

//

int

означает,

что функция

возвращает целочисленное

 

значение обратно в caller

 

 

 

 

 

4

int return7()

 

 

 

5

{

 

 

 

 

 

6

//

Эта

функция

возвращает

целочисленное значение,

 

поэтому мы должны использовать оператор return

 

 

 

7

return 7; // возвращаем число 7 обратно в caller

 

8

}

 

 

 

 

 

9

int main()

 

 

 

10

{

 

 

 

 

 

11

cout << return7() << endl; // выведется 7

 

12

cout << return7() + 3 << endl; // выведется 10

 

13

return7(); // возвращаемое значение 7 игнорируется, так

 

как main() ничего с ним не делает

 

14

return 0;

 

 

 

15

}

 

 

 

 

 

 

Результат выполнения программы:

 

 

7

10

Разберемся детальнее:

Первый вызов функции return7() возвращает 7 обратно в caller,

которое затем передается в cout для вывода

Второй вызов функции return7() опять возвращает 7 обратно в

caller. Выражение 7 + 3 имеет результат 10, который затем выводится на экран.

Третий вызов функции return7() опять возвращает 7 обратно в

caller. Однако main() ничего с ним не делает, поэтому ничего и не происходит

(возвращаемое значение игнорируется).

Обратите внимание, что возвращаемые значения не выводятся на экран,

если их не передать объекту cout. В последнем вызове функции return7()

значение не отправляется в cout, поэтому ничего и не происходит.

7

Одну и ту же функцию можно вызывать несколько раз, даже в разных

программах, что очень полезно:

Листинг 7.5.

1

#include <iostream>

2

using namespace std;

3

int getValueFromUser()

4

{

5

cout << "Enter an integer: ";

6

int x;

7

cin >> x;

8

return x;

9

}

10

int main()

11

{

12

int a = getValueFromUser(); // первый вызов функции

13

int b = getValueFromUser(); // второй вызов функции

14

cout << a << " + " << b << " = " << a + b << endl;

15

return 0;

16

}

Функция getValueFromUser() получает значение от пользователя, а

затем возвращает его обратно в caller.

Результат выполнения программы:

Enter an integer: 10

Enter an integer: 5

10 + 5 = 15

Здесь main() прерывается 2 раза. Обратите внимание, в обоих случаях,

полученное пользовательское значение сохраняется в переменной x, а затем передаётся обратно в main() с помощью return, где присваивается переменной a или b.

§7.4 Создание функций с несколькими параметрами

Предположим, вы пишете программу, которая вычисляет площадь цилиндра по известному радиусу и высоте.

Вы использовали бы для этого следующую формулу:

8

Площадь цилиндра = Площадь верхнего круга + Площадь нижнего круга +

Площадь боковой поверхности = Pi * RadiusA2 + Pi * Radius A2 + 2 * Pi * Radius * Height = 2 * Pi * RadiusA2 + 2 * Pi * Radius * Height

Таким образом, при вычислении площади цилиндра необходимо работать с двумя переменными — радиусом и высотой. Поэтому при объявлении такой функции в списке ее параметров определяется по крайней мере два параметра. В списке параметров их отделяют запятой.

Листинг 7.6.

1 #include <iostream>

2 using namespace std;

3 const double Pi = 3.14159;

4 // Объявление содержит два параметра

5 double SurfaceArea(double Radius, double Height)

6 {

7

double Area = 2 * Pi * Radius * Radius + 2 * Pi * Radius \ * Height;

8 return Area;

9 }

10 int main ()

11 {

12 cout « "Enter the radius of the cylinder: ";

13 double InRadius = 0;

14 cin » InRadius;

15 cout « "Enter the height of the cylinder: ";

16 double InHeight = 0;

17 cin » InHeight;

18 cout « "Surface Area: " « SurfaceArea(InRadius, InHeight) « endl;

19 return 0;

20 }

Результат выполнения программы:

Enter the radius of the cylinder: 3

Enter the height of the cylinder: 6.5

Surface Area: 179.071

Строка 5 содержит объявление функции SurfaceArea() с двумя параметрами: Radius и Height, оба имеют тип double и отделены запятой.

9

Параметры функций похожи на локальные переменные. Они допустимы только в пределах функции. Так, параметры Radius и Height функции

Surface Area() в листинге 7.6 допустимы и пригодны для использования только в пределах самой функции SurfaceArea(), но не вне ее.

§7.5 Параметры функций со значениями по умолчанию

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

Один из способов решения этой проблемы подразумевает создание в функции Area() дополнительного параметра для числа Пи и присвоение ему

значения по умолчанию (default value). Такая адаптация функции Area() из листинга 7.1 выглядела бы так:

double Area(double InputRadius, double Pi = 3.14);

Обратите внимание на второй параметр Pi и присвоенное ему по умолчанию значение 3,14. Этот второй параметр является теперь

необязательным параметром (optional parameter) для вызывающей стороны.

Так, вызывающая функция все еще может вызвать функцию Area(),

используя такой синтаксис:

Area(Radius);

В данном случае второй параметр был проигнорирован, поэтому используется значение по умолчанию 3,14. Но если пользователь захочет задействовать другое значение числа Пи, то сделать это можно, вызвав функцию Area() так:

Area(Radius, Pi); // Pi определяется пользователем

У функции может быть несколько параметров со значениями по умолчанию; но все они должны быть расположены в заключительной части

списка параметров.

10