Как сделать подпрограмму c

Обновлено: 07.07.2024

В различных примерах программ мы обращали ваше внимание на повторяющийся код, который значительно увеличивал объем этих программ. Для оптимизации программного кода, чтобы сделать его более понятным и удобным для восприятия, используются подпрограммы. Подпрограмма (англ. subroutine) позволяет вынести часть реализации (некоторую вполне самостоятельную подзадачу или алгоритм) за пределы основной программы и обращаться к ней, по мере необходимости, по имени, из любой части программы. Таким образом, можно не только сократить программный код, но и сделать его более структурированным.
Существует две разновидности подпрограмм: процедуры и функции. Но это деление чисто условное. В C++ между функциями и процедурами нет больших синтаксических различий, поэтому они имеют общее наименование – функции. Функция может принимать аргументы (не обязательно) и возвращать некоторое значение, возможно пустое ( void ). Если функция не возвращает никакого значения, то такая функция называется процедурой. В отличие от процедур, функции всегда возвращают результат в точку вызова.
Для того, чтобы использовать функцию в программе её нужно объявить, определить и вызвать по имени.

Объявление функции. Прототип

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

Определение функции состоит из заголовка функции и тела функции, которое заключается в фигурные скобки, т. е. представляет из себя блок. Заголовок функции синтаксически схож с прототипом, за той лишь разницей, что в круглых скобках производится определение локальных объектов, которые также называются формальными параметрами (или просто параметрами). Параметры – это локальные переменные функции, которые инициализируются в момент вызова функции в основной программе.

Если функция не имеет параметров (т. е. данные в функцию не принимаются из-вне), то круглые скобки остаются пустыми.
Тело функции содержит реализацию алгоритма подпрограммы, которая подчиняется общим синтаксическим правилам языка. Например, можно определять переменные фундаментальных и абстрактных типов, осуществлять вызовы библиотечных функций, обращаться к глобальным объектам, которые определены или объявлены вне данной функции, создавать локальные функции и использовать при составлении алгоритма любые операции и инструкции языка. Локальные объекты, которые определены в блоке функции, вне её – не видны.
Составим определение функции line() . Параметры этой функции – x и y , целочисленные переменные, с помощью которых устанавливаются длина линий и их количество. Чтобы в программе не было путаницы с именами, принято (но не запрещено!) чтобы имена параметров и других переменных функции не совпадали с именами переменных в основной программе или именами глобальных объектов.
Определение нашей функции может быть составлено следующим образом:

Вызов функции

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

Процедуры

Тип функции описанной в программе 9.2.1 – это процедура. Процедура производит определенные действия в программе, но не возвращает никакого значения. Вызов процедуры можно включать в программу отдельной инструкцией в основной программе, в ветвях условной инструкции, в теле цикла, а также в других функциях.
В программе 9.1.11, которую мы написали на предыдущем уроке, содержался многократно повторяющийся код рисования треугольника:

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

Наша программа сократилась на 14 строк! Обратите внимание, что аргументами функции могут быть не только переменные, но и константы. Так, в этой программе, значение цвета передается строковым литералом.

Инструкция return

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

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

Чтобы функция смогла возвращать какое-либо значение, полученное в процессе её работы, используется инструкция return . Эта инструкция завершает работу функции и возвращает её значение выражением, которое следует за ключевым словом return . В теле функции должна быть только одна такая инструкция. Допускается использование нескольких инструкций return , но только в том случае, если они находятся в ветвях условной инструкции.
Помимо наличия инструкции return , функцию от процедуры отличает ещё и то, что перед именем в прототипе и в заголовке функции вместо void указан спецификатор типа возвращаемого значения. Тип возвращаемого значения может быть любым, в том числе абстрактным.
Задача 2. Составить программу вычисляющую среднее арифметическое и среднее геометрическое двух введенных чисел a и b . Вычисление среднего арифметического и среднего геометрического оформить в виде функций.

Вынос различных подзадач в функции значительно упрощает чтение и обзор основной программы. Покажем это на следующей задаче.
Задача 4. Составить программу подсчета всех шестизначных счастливых "чисел". Число называется "счастливым", если сумма его первых трех разрядов равна сумме трех его младших разрядов.

Локальные и глобальные переменные. Передача аргументов

Ранее мы упоминали, что блок функции определяет область видимости данных. Что это значит? Приведем пример:

Теги: Функции в си, прототип, описание, определение, вызов. Формальные параметры и фактические параметры. Аргументы функции, передача по значению, передача по указателю. Возврат значения.

Введение

Ч ем дальше мы изучаем си, тем больше становятся программы. Мы собираем все действия в одну функцию main и по несколько раз копируем одни и те же действия, создаём десятки переменных с уникальными именами. Наши программы распухают и становятся всё менее и менее понятными, ветвления становятся всё длиннее и ветвистее.

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

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

Мы уже знакомы с многими функциями и знаем, как их вызывать – это функции библиотек stdio, stdlib, string, conio и пр. Более того, main – это тоже функция. Она отличается от остальных только тем, что является точкой входа при запуске приложения.
Функция в си определяется в глобальном контексте. Синтаксис функции:

Самый простой пример – функция, которая принимает число типа float и возвращает квадрат этого числа

Внутри функции sqr мы создали локальную переменную, которой присвоили значение аргумента. В качестве аргумента функции передали число 9,3. Служебное слово return возвращает значение переменной tmp. Можно переписать функцию следующим образом:

В данном случае сначала будет выполнено умножение, а после этого возврат значения. В том случае, если функция ничего не возвращает, типом возвращаемого значения будет void. Например, функция, которая печатает квадрат числа:

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

Если функция не принимает аргументов, то скобки оставляют пустыми. Можно также написать слово void:

Формальные и фактические параметры

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

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

Обращаю внимание, что приведение типов просиходит неявно и только тогда, когда это возможно. Если функция получает число в качестве аргумента, то нельзя ей передать переменную строку, например "20" и т.д. Вообще, лучше всегда использовать верный тип или явно приводить тип к нужному.
Если функция возвращает значение, то оно не обязательно должно быть сохранено. Например, мы пользуемся функцией getch, которая считывает символ и возвращает его.

Передача аргументов

При передаче аргументов происходит их копирование. Это значит, что любые изменения, которые функция производит над переменными, имеют место быть только внутри функции. Например

Программы выведет
200
100
200
Понятно почему. Внутри функции мы работаем с переменной x, которая является копией переменной d. Мы изменяем локальную копию, но сама переменная d при этом не меняется. После выхода из функции локальная переменная будет уничтожена. Переменная d при этом никак не изменится.
Каким образом тогда можно изменить переменную? Для этого нужно передать адрес этой переменной. Перепишем функцию, чтобы она принимала указатель типа int

Вот теперь программа выводит
200
100
100
Здесь также была создана локальная переменная, но так как передан был адрес, то мы изменили значение переменной d, используя её адрес в оперативной памяти.

В программировании первый способ передачи параметров называют передачей по значению, второй – передачей по указателю. Запомните простое правило: если вы хотите изменить переменную, необходимо передавать функции указатель на эту переменную. Следовательно, чтобы изменить указатель, необходимо передавать указатель на указатель и т.д. Например, напишем функцию, которая будет принимать размер массива типа int и создавать его. С первого взгляда, функция должна выглядеть как-то так:

Но эта функция выведет ERROR. Мы передали адрес переменной. Внутри функции init была создана локальная переменная a, которая хранит адрес массива. После выхода из функции эта локальная переменная была уничтожена. Кроме того, что мы не смогли добиться нужного результата, у нас обнаружилась утечка памяти: была выделена память на куче, но уже не существует переменной, которая бы хранила адрес этого участка.

Для изменения объекта необходимо передавать указатель на него, в данном случае – указатель на указатель.

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

В этом примере утечки памяти не происходит. Мы выделили память с помощью функции malloc, скопировали туда строку, а после этого вернули указатель. Локальные переменные были удалены, но переменная test хранит адрес участка памяти на куче, поэтому можно его удалить с помощью функции free.

Объявление функции и определение функции. Создание собственной библиотеки

В си можно объявить функцию до её определения. Объявление функции, её прототип, состоит из возвращаемого значения, имени функции и типа аргументов. Имена аргументов можно не писать. Например

Это смешанная рекурсия – функция odd возвращает 1, если число нечётное и 0, если чётное.

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

Давайте создадим простую библиотеку. Для этого нужно будет создать два файла – один с расширением .h и поместить туда прототипы функций, а другой с расширением .c и поместить туда определения этих функций. Если вы работаете с IDE, то .h файл необходимо создавать в папке Заголовочные файлы, а файлы кода в папке Файлы исходного кода. Пусть файлы называются File1.h и File1.c
Перепишем предыдущий код. Вот так будет выглядеть заголовочный файл File1.h

Содержимое файла исходного кода File1.c

Наша функция main

Рассмотрим особенности каждого файла. Наш файл, который содержит функцию main, подключает необходимые ему библиотеки а также заголовочный файл File1.h. Теперь компилятору известны прототипы функций, то есть он знает возвращаемый тип, количество и тип аргументов и имена функций.

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

Передача массива в качестве аргумента

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

В этом примере функция может иметь следующий вид

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

Либо, можно писать

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

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

На этом первое знакомство с функциями заканчивается: тема очень большая и разбита на несколько статей.

email

Всё ещё не понятно? – пиши вопросы на ящик

Модификатор доступа — откуда этот метод может быть вызван. Некоторые из них:

Пример функции (метода):

public Boolean StartService(string serviceName) < // код функции >

В примере:
public модификатор доступа,
Boolean тип возвращаемого значения,
StartService идентификатор (имя),
string serviceName параметр (аргумент).

static void SayHello()

Вызов метода / функции

static void Main(string[] args) < int res; Square(5, out res); Console.WriteLine(res); >static void Square(int a, out int res)

В этом примере:
a — ref аргумент (входно-выходной);
res — out аргумент (выходной).

Возврат значения из функции / метода

Три подхода для возврата значений в си шарп:

// 1. без ref static void Main(string[] args) < int a = 1; Plas2(a); Console.WriteLine(a); // результат 1 >static void Plas2(int a)

// 2. с ref static void Main(string[] args) < int a = 1; Plas2(ref a); Console.WriteLine(a); // результат 3 >static void Plas2(ref int a)

Перегрузка методов / функций

Задания и лабораторные си шарп

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

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

Пример выполнения:

[Название проекта: Lesson_5Lab1 , название файла L5Lab1.cs ]

  • Запустите Visual Studio.
  • Создайте консольное приложение, назовите проект Lesson_5Lab1 .
  • В окне Solution Explorer (Обозреватель решений) найдите файл Program.cs и переименуйте его в L5Lab1.cs .
  • В главной функции запросите пользователя ввести два числа:

Метод не возвращает никакого значения основной программе, поэтому мы должны использовать ключевое слово void .

static void Main(string[] args)

Метод возвращает целочисленное значение, именно поэтому мы используем int в сигнатуре ( static int Sum(. ) ).
Обратите внимание, что имена параметров, которые мы указали здесь в сигнатуре метода, могут не совпадать с именами аргументов, которые мы передали. Эти параметры становятся локальными переменными в рамках этого метода.


Перегрузка метода / функции:

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

Выполнить: Вводятся три числа — длины трех сторон треугольника. Создайте функцию Perimeter( ), которая вычисляет периметр треугольника по длинам трех его сторон.

Указание 1: Метод Perimeter() должен принимать в качестве аргументов три целых числа.
Указание 2: Метод не должен возвращать никакого значения, поэтому вы должны использовать ключевое слово void в сигнатуре:

static void Perimeter(. );

Указание 3: Не забудьте преобразовать введенные значения в целые числа. Например:

int a = int.Parse(Console.ReadLine());


Пример выполнения:


[Название проекта: Lesson_5Task1 , название файла L5Task1.cs ]

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

Указание 1: Метод Perimeter() должен принимать в качестве аргументов три целых числа.
Указание 2: Метод должен возвращать значение типа integer, поэтому вы должны использовать ключевое слово int в сигнатуре:

static int Perimeter(. );

Указание 3: Не забудьте преобразовать введенные значения в целые числа. Например:

int a = int.Parse(Console.ReadLine());

Пример выполнения:


[Название проекта: Lesson_5Task2 , название файла L5Task2.cs ]

Выполнить: Создайте метод GetPow(), который принимает два целочисленных аргумента — число и степень. Метод возвращает результат возведения числа в степень.

Указание 1: Необходимо использовать служебное слово static , потому что основная функция static, а мы не можем вызвать нестатический метод из статического метода.

Указание 2: Функция возвращает целочисленное значение, поэтому необходимо использовать int в сигнатуре функции:

static int GetPow(int baseNum, int powNum)

Пример выполнения:

[Название проекта: Lesson_5Lab2 , название файла L5Lab2.cs ]

  • Запустите Visual Studio.
  • Создайте консольное приложение, назовите проект Lesson_5Lab2 .
  • После закрывающей скобки функции Main создайте функцию GetPow :

Функция принимает два целых числа — аргумент baseNum и аргумент powNum . Внутри функции необходимо возвести baseNum в степень powNum .

В первую итерацию цикла всегда будет выполняться 1 * baseNum , результат сохраняется в переменной result . За две итерации имеем baseNum * baseNum . За три – baseNum * baseNum * baseNum и т. д. Мы повторяем это действие каждую итерацию.

Выполнить: Создайте метод Distance который вычисляет расстояние между двумя точками на плоскости. Координаты точек вводятся (переменные x1 , y1 — для первой точки, и x2 , y2 — для второй).

Указание 1: Метод Distance() принимает 4 аргумента (координаты точек).
Указание 2: Метод не должен возвращать значение, поэтому следует использовать ключевой слово void в сигнатуре:

static void Distance(. );

Указание 3: Для подсчета расстояния между двумя точками на плоскости используйте формулу:


квадратный корень: Math.Sqrt(. ); степень числа: Math.Pow(number, power);


Пример выполнения:


[Название проекта: Lesson_5Task3 , название файла L5Task3.cs ]

Выполнить: Необходимо переделать предыдущее задание. Создайте метод Distance который вычисляет расстояние между двумя точками на плоскости. Координаты точек вводятся (переменные x1 , y1 — для первой точки, и x2 , y2 — для второй).

Указание: Метод должен возвращать вещественное значение (double):

static double Distance(. );


Пример выполнения:


[Название проекта: Lesson_5Task4 , название файла L5Task4.cs ]

Выполнить: Создайте метод Minmax() который принимает два целочисленных аргумента по ссылке (ref) и меняет их значения таким образом, что первый становится максимальным, а второй — минимальным (меняет значения аргументов, если требуется). Создайте перегруженный метод Minmax для трех параметров.

Указание 1: Необходимо использовать ключевое слово static в сигнатуре создаваемого метода, т.к. функция Main тоже static, невозможно вызвать не static метод из static метода.

Указание 2: Метод не возвращает значения значит, используется ключевое слово void в сигнатуре).

Пример выполнения:

[Название проекта: Lesson_5Lab3 , название файла L5Lab3.cs ]

  • Создайте консольное приложение, назовите проект Lesson_5Lab3 .
  • В окне Solution Explorer (Обозреватель решений) найдите файл Program.cs и переименуйте его в L5Lab3.cs .
  • В теле функции Main попросите пользователя ввести два числа. Присвойте введенные значения переменным:

Модификатор ref используется для того, чтобы значение аргумента передалось из основной программы в создаваемую функцию и, наоборот, из функции измененное значение должно возвратиться в основную программу. Ref аргументы должны быть инициализированы до их вызова, иначе возникнет ошибка. При вызове модификатор ref также указывается.

Перегруженный метод (функция):

В коде метода найдем сначала минимальное и максимальное из переменных a и b , затем из b и c , и после — из a и b еще раз, так как значения переменных могли уже поменяться к этому моменту.

Выполнить: Вводится двузначное целое число. Создайте метод ChangeDigits() , который принимает введенный аргумент по ссылке и изменяет его значение так, чтобы первая цифра нового числа была второй цифрой введенного числа и, наоборот, вторая цифра нового числа была первой цифрой введенного числа. Например, если ввести 45, то результирующее число будет равно 54.

Указание 1: Метод ChangeDigits() принимает аргумент с модификатором ref.
Указание 2: Метод не возвращает значения:

static void ChangeDigits(. );

Указание 3: Сначала необходимо получить цифры из числа. Затем, поменяв местами цифры, сделать новое число. Пример создания нового числа из двух цифр:


Пример выполнения:


[Название проекта: Lesson_5Task5 , название файла L5Task5.cs ]

Выполнить: Вводятся два двузначных целых числа. Создайте функцию BitwiseSum() , которая вычисляет их побитовую сумму по модулю 10. Например, побитовая сумма чисел 34 и 59 является числом 83 (3 + 5 = 8; 4 + 9 = 13, 13%10 = 3).

Указание 1: Функция BitwiseSum() имеет два аргумента.
Указание 2:Функция возвращает целочисленное значение int :

static int BitwiseSum(. );

Указание 3: Сначала необходимо получить цифры из числа. Затем, поменяв местами цифры, сделать новое число. Пример создания нового числа из двух цифр:


[Название проекта: Lesson_5Task6 , название файла L5Task6.cs ]

Выполнить: Создайте функцию MinmaxSeq() , которая принимает два аргумента по ссылке (ref аргументы) — минимальное и максимальное значение вводимой последовательности чисел. Запросите у пользователя ввести последовательность, которая должна закончиться 0 (если вводится 0, то ввод завершается). Функция должна выполнять поиск максимального и минимального значения последовательности и возвращать результат.

Указание 1: Функция не должна возвращать значениен (поэтому в объявлении функции используется void ). Параметры ref — это параметры ввода-вывода, это говорит о том, что значения этих параметров меняются внутри функции и возвращаются в основную программу с вызовом фнукции.
Указание 2: Необходимо использовать ключевое слово static в объявлении метиода, так как функция Main тоже статическая, а нестатическая фнукция не может быть вызвана внутри статической.

[Название проекта: Lesson_5Lab4 , название файла L5Lab4.cs ]

Пример вывода:

  • Создайте Консольное приложение и назовите его Lesson_5Lab4 .
  • В окне Обозреватель решений найдите файл Program.cs и переименуйте его в L5Lab4.cs .
  • В функции Main объявите две переменные для хранения минимального и максимального значения последовательности. Присвойте им начальные значения: для переменной min — наибольшее возможное целое число, для переменной max — наименьшее возможное целое число:





Выполнить: Создайте функцию PosNegSeq() , которая принимает два аргумента по ссылке — счетчики положительных чисел последовательности и отрицательных чисел. Пользователь вводит последовательность целых чисел, завершая ввод 0 . Функция должна посчитать количество отрицательных и положительных чисел и вернуть значения счетчиков в главную программу.

Указание 1: Функция не должна возвращать значение (поэтому используется ключевое слово void в объявлении функции). Параметр ref — это параметр ввода-вывода, что означает, что значения параметров будут изменены внутри функции и возвращены в основную программу.
Указание 2: Параметры ref должны быть инициализированы до вызова функции. Поэтому сначала вам необхзодимо инициализировать такие параметры значениями. Установите начальные значения для этих параметров, равные 0 :

. int counterPositive = 0; int counterNegative = 0; .

[Название проекта: Lesson_5Task7 , название файла L5Task7.cs ]

Пример вывода:

static void Main(string[] args) < int[] a = new int[] < -1, -2, 3, 4, 5, 6, 7 >; WriteLine("Начальный массив: "); Print(a); int countPos = 0; int countOdd = 0; CountOddPositive(a, ref countPos, ref countOdd); WriteLine($"number of odd elements: , number of positive elements ."); > static void Print(int[] arr) < WriteLine("array:"); foreach (var x in arr) Write(x + " "); WriteLine(); >static void CountOddPositive( int[] arr, ref int countOdd, ref int countPos) < foreach (var x in arr) < if (x % 2 != 0) countOdd++; if (x >0) countPos++; > //return (Odd, Pos); > -->

Приложения для windows forms

To do: Создайте проект для вычисления факториала числа. Вычисление должно быть оформлено в виде пользовательской функции. Запускать функции следует по щелчку на кнопке Вычислить ( btnCalc ). Выводить результата следует в текстовое поле ( txtFactorial ).

[Solution and Project name: Lesson_5Lab5 , file name L5Lab5.cs ]

  1. Создайте новый проект и самостоятельно разработайте интерфейс новой формы.
  2. Необходимо создать функцию пользователя. Щёлкните дважды по кнопке. Во открывшемся окне добавьте код перед кодом для кнопки:

private long Factorial(int n) < //. >

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

С переходом от императивного языка C к объектно-ориентированному языку C++ понятие функции (как подпрограммы) сохранилось, однако каждая функция стала принадлежать какому-либо классу. Отметим что в С++ были добавлены специальные функции – конструкторы и деструкторы.

Разберемся с терминами и понятиями более подробно.

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

Авторы языка определили, что функции-члены — это члены, которые обеспечивают некоторую функциональность для манипулирования данными класса. Они включают методы, свойства, конструкторы, финализаторы (деструкторы в С++), операции и индексаторы.

Для начинающего программиста важно освоить, прежде всего, работу с методами класса, а по сути (в прежнем понимании) – с функциями как подпрограммами. К этому добавим работу с конструкторами классов, а все остальное будет рассмотрено позже.

Шаблон объявления метода

Возврат из метода и возврат значения

Если метод возвращает значение, то для указания точки выхода должен использоваться оператор возврата return вместе с возвращаемым значением. Если метод не возвращает ничего, то в качестве типа возврата указывается void (опустить тип возврата невозможно).

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

В целом, возврат из метода может произойти при двух условиях. Во-первых, когда встречается фигурная скобка, закрывающая тело метода. И во-вторых, когда выполняется оператор return. Имеются две формы оператора return: одна — для методов типа void (возврат из метода), т.е. тех методов, которые не возвращают значения, а другая — для методов, возвращающих конкретные значения.

Использование параметров

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

Параметры объявляются в скобках после имени метода. Синтаксис объявления параметров такой же, как и у переменных. А областью действия параметров является тело метода. За исключением особых случаев передачи аргументов методу, параметры действуют так же, как и любые другие переменные.

Два способа передачи параметров. В общем случае параметры могут передаваться методу либо по значению, либо по ссылке в зависимости от типа данных.

Если переменная, указанная в списке параметров, относится к типу значений (int, double, bool и т.п.), то вызываемый метод получает копию этой переменной, а это значит, что все изменения в ней, выполненные внутри метода будут утеряны.

Если переменная из списка параметров относится к ссылочному типу (например, массив), то параметр передается по ссылке, вызываемый метод получает саму переменную, поэтому любые изменения, которым она подвергнется внутри метода, останутся в силе после его завершения.

Поведение строк также отличается. Дело в том, что строки являются неизменными (изменение значения строки приводит к созданию совершенно новой строки), поэтому строки не демонстрируют поведение, характерное для ссылочных типов. Любые изменения, проведенные в строке внутри метода, не влияют на исходную строку.

Передача структуры (struct) как параметра через ее имя также произойдет через копирование (помните, структура относится к типу значений).

Если же для каких-либо типов данных необходима передача по ссылке (она более эффективна при большом объеме данных, который приходится копировать), то перед указанием типа параметра достаточно указать модификатор ref (reference – ссылка, англ.).

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

ПРИМЕР 1. В статье Первая программа на языке Си шарп мы разбирали программу:

В классе Program объявляется метод Main() (главная функция приложения), при выполнении которого вызываются два метода класса Console: WriteLine() (вывод строки текста) и ReadKey() (чтение символа с клавиатуры).

Ключевое слово static означает, что данный метод принадлежит классу Program.

Модификатор void указывает, что метод не возвращает никаких параметров.

Метод Main() в качестве списка параметров имеет массив строк. Отметим, что список параметров args в Main() пропустить. Метод WriteLine() имеет один параметр – строку, метод ReadKey() параметров не имеет.

ПРИМЕР 2. Объявление метода в примере Вычисление функции sin(x) выглядит так:

Параметром (аргументом) функции объявляется переменная x типа double, метод возвращает результат также типа double (последний оператор метода return s;). Метод является статическим. Для вызова метода достаточно написать оператор y=Sin2(x);

ПРИМЕР 3. Передача параметров по значению, ссылке и через статическую переменную

Объявим в классе Program структуру West с двумя полями, статическую переменную f и метод vp( ):
static void vp(int[] b, West u, string t, double d, ref decimal y)
где b – массив, u – структура, t – строка, d – вещественное число, y – десятичный тип, передается по ссылке (модификатор ref).

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

Напечатаем эти значения до и после вызова метода vp().

48

Результат:

Обратите внимание, что второй элемент массива a[1], десятичное число x (передаваемое через ссылку — ref) и статическая переменная f изменились, а структура u, строка t и вещественное число d не изменились.

Отметим, что статическое поле f, объявленное в классе, доступно методам этого класса без механизма передачи параметров.

Некоторые итоги:

1) переменные, объявленные внутри метода или в списке его параметров, являются локальными переменными;

2) при вызове метода параметры из списка в заголовке метода либо копируются в локальные переменные метода, либо передаются по ссылке;

3) копируются все встроенные типы значений, структуры и (по сути) строки, хотя и они относятся к ссылочным типам;

4) по ссылке передаются массивы и другие объекты. Если их поля будут изменены внутри вызываемого метода, то эти изменения сохранятся при возврате в вызывающий метод;

7) для доступа к данным-членам и функциям-членам других классов необходимо указать имя класса, поставить точку, указать имя члена класса, например: Math.PI — константа, число пи=3,14158… , Math.Tan(x) — тангенс числа x, заданного в радианах;

8) доступ к членам других классов зависит от уровня его приватности (public, но не private или protected).

Завершим раздел рассмотрением двух из трех ключевых принципов ООП — наследования и полиморфизма, считаю принцип инкапсуляции (объединение данных и и методов в класс) уже достаточно ясным.

Читайте также: