3668

Процедури і функції — методи класу

Лекция

Информатика, кибернетика и программирование

Процедури і функції — методи класу Історично першим способом структуризації програм в мовах програмування високого рівня було використання процедур і функцій — щодо самостійних фрагментів програм, оформлених особливим чином і забезпечених ...

Украинкский

2012-11-05

64 KB

2 чел.

Процедури і функції — методи класу

Історично першим способом структуризації програм в мовах програмування високого рівня було використання процедур і функцій — щодо самостійних фрагментів програм, оформлених особливим чином і забезпечених ім'ям. Згадка цього імені в програмі називається викликом процедури (функції).

Відмінність функції від процедури полягає в тому, що результатом виконання операторів, утворюючих тіло функції, завжди є значення деякого типу, тому функція може брати участь в утворенні виразів разом із змінними і константами. Умовимося надалі називати процедури і функції загальним словом підпрограми, якщо тільки це дозволяє висловлюваний матеріал.

Структуризація програм необхідна по двох причинах. По-перше, неможливо написати більш менш складну програму як єдине ціле, не розчленовувавши її на окремих відносно самостійні частини — підпрограми. По-друге, підпрограми відкривають можливість повторного використання одного разу створеного коду і сприяють появі бібліотек підпрограм. У мові С# підпрограми не мають самостійного значення — вони можуть бути тільки методами класу.

Опис підпрограм

У С# немає спеціальних зарезервованих слів procedure і function для опису підпрограм. Оскільки вони є методами класу, ці слова надмірні. Синтаксис опису такий:

[модифікатори]   <Тип>  <Ім'я>   ([Формальниє_параметри>]) {<Тіло>}

У квадратних дужках вказані необов'язкові елементи. Модифікатори визначають область видимості підпрограми і детально розглядаються в розділі І..

Зараз поясню лише два модифікатори — private і public. Будь-які члени класу (зокрема методи-підпрограми), оголошені з модифікатором private, доступні тільки в методах даного класу. Модифікатор public робить метод (підпрограму) доступним в будь-якому місці програми. Якщо модифікатор не вказаний, вважається, що даний член класу помічений як закритий (з модифікатором private).

Формальні параметри можуть бути відсутніми, але і в цьому випадку круглі дужки за ім'ям підпрограми обов'язкові.

Тип підпрограми може бути будь-яким типом даних. В цьому випадку підпрограма є функцією, яка повертає результат вказаного типу. У тілі функції обов'язково указується оператор return, який привласнює функції потрібне значення. Як тип можна вказати зарезервоване слово void, яке означає відсутність типу. В цьому випадку підпрограма є процедурою і в ній не можна указувати оператора return.

Ім'я підпрограми повинне бути унікальним в поточній області видимості ідентифікатора.

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

Приклади описів:

int A()  {...}

void В(...) {...}

public string С() { . . . }

Тут А і В — закриті члени класу, які доступні тільки в методах цього ж класу, причому А — цілочисельна функція, а В — процедура. С — відкрита функція рядкового типу, доступна в будь-якій точці програми.

Формальні параметри

Формальні параметри є засобом настройки підпрограми на виконання потрібної роботи. Наприклад, звичайна математична функція sin(х) має формальний параметр х, в тілі функції що трактує як кут, для якого слід обчислити значення синуса.

У С# розрізняють три різновиди (статусу) формальних параметрів: вхідні, вихідні і посилальні. За допомогою вхідних параметрів програма передає дані в тіло підпрограми. При цьому, фактично, в підпрограму передаються не дані, а їх копії, тому зміна вхідних параметрів в підпрограмі ніяк не передається програмі що визиває. Вихідні параметри оголошуються із зарезервованим словом out. Вони призначені для передачі даних з підпрограми в програму що визиває. У тілі підпрограми обов'язково повинен бути присутнім оператор привласнення цим параметрам нового значення — за цим стежить компілятор. Посилальні параметри передаються підпрограмі по посиланню, тобто в тіло підпрограми передається адреса параметра в пам’яті комп'ютера. Такі параметри позначаються зарезервованим словом ref. Вони дозволяють як передати дані в підпрограму, так і отримати з неї нові дані.

При виборі того або іншого різновиду формальних параметрів потрібно керуватися наступними міркуваннями:

  •  Якщо параметр визначений як вхідний, програміст може бути упевнений в тому, що виклик підпрограми не буде пов'язаний з яким-небудь побічним ефектом, оскільки в підпрограму передається не сам параметр, а лише його копія. На місці цього параметра може розташовуватися довільний вираз відповідного типу. Проте програма витрачатиме додаткові ресурси комп'ютера (пам'ять і час), особливо якщо в підпрограму передається великий масив даних.
  •  Якщо параметр помічений як вихідний (out) або посилальний (ref), в підпрограму передається сам параметр (його адреса), а не його копія, що мінімізує витрати пам'яті і часу в точці виклику. Він може (ref) або повинен (out) змінитися в підпрограмі, тому на його місці слід указувати не вираз, а змінну відповідного типу.
  •  У підпрограмі можна оголосити не один, а декілька параметрів. В цьому випадку сусідні параметри розділяються комами, утворюючи список параметрів Останнім (або єдиним) параметром списку може оголошуватися масив будь-якого типу із зарезервованим словом params. В цьому випадку на місці даного параметра при виклику підпрограми може стояти скільки завгодно параметрів такого типу.

Програма з лістингу 19.1 ілюструє використання функції А з довільною кількістю формальних параметрів.

Лістинг 18.1. Функція з довільною кількістю параметрів

using System;

class Program

{

   static int A(params int[] I)

   // Ця функція знаходить суму довільної кількості  цілочисельних параметрів звернення

   {

       int Sum = 0;

       for (int i = 0; i < I.Length; i++)

           Sum += I[i]; ;

       return Sum;

   }

   static void Main()

   {

       Console.WriteLine("{0} {1}", A(1, 2, 3), A(4 , 5, 6, 7, 8, 9));

       Console.ReadLine();

   }

}

Виклик підпрограм

Для виклику підпрограми потрібно вказати її ім'я і список фактичних параметрів (якщо в описі підпрограми є непорожній список формальних параметрів). Список фактичних параметрів повинен відповідати за типом, кількістю, порядком проходження і статусом списку формальних параметрів.

Якщо в списку п формальних параметрів, то фактичних параметрів повинно бути не менше п (відповідність по кількості). Кожному і-му формальному параметру ставиться у відповідність і-й фактичний параметр. Останньому формальному параметру за умови, що він оголошений із зарезервованим словом params, ставляться у відповідність фактичні параметри, що все залишилися (відповідність по порядку).

Якщо формальний параметр оголошений із зарезервованим словом ref або out, то фактичний параметр повинен супроводжуватися таким же зарезервованим словом в точці виклику (відповідність по статусу).

Відповідність за типом означає, що фактичний параметр повинен мати такий же (або сумісний з ним) тип, який має формальний параметр.

Відповідність по статусу, тобто поява зарезервованих слів ref і out в точці виклику підпрограми, особливість мови С#, що відрізняє його від всіх інших мов програмування. Цю особливість слід всіляко вітати, оскільки вона нагадує програмістові про те, що даний фактичний параметр є вихідним і його значення може змінитися (у разі ref) або напевно зміниться (у разі out) після виклику підпрограми. Проте із-за незвичності синтаксису ці слова часто забувають указувати, що приводить до синтаксичних помилок, що супроводжуються повідомленнями типу «Argument N: cannot convert from 'Type' to 'Out Type'» («Параметр N: неможливо перетворити 'Type' в 'Out Type'»).

Функції з побічним ефектом

Функція називається функцією з побічним ефектом, якщо крім результату, що обчислюється функцією і що повертається нею в операторові return, вона має вихідні параметри із зарезервованими словами ref або out.

Деяким програмістам, можливо, такі функції сподобаються, проте хороший стиль програмування не рекомендує їх використання. Річ у тому, що функція може викликатися не тільки в операторові привласнення, але і у виразах. Функція з побічним ефектом може порушити комутативність операцій.

Наприклад, якщо int f (out int а) — функція з побічним ефектом, то вираз а + f (out а) в загальному випадку не рівно виразу f (out а) + а.

Якщо по яких-небудь причинах функція повинна повертати декілька значень, логічніше оформити її у вигляді процедури з відповідним набором вихідних параметрів.

Рекурсія

Рекурсія — це такий спосіб організації обчислювального процесу, при якому підпрограма в ході виконання складових її операторів звертається сама до себе.

Розглянемо класичний приклад — обчислення факторіалу. Програма з лістингу 18.2  читає ціле число N і виводить на екран значення N!, яке обчислюється за допомогою рекурсивної функції Fac().

Лістинг 18.2. Обчислення факторіалу за допомогою рекурсивної функції

using System;

class Factorial 

{

static long Fac(int N)     // Рекурсивна функція

{

   if (N <= 1) // Рішення тривіальне?

       return 1; // -Да. Вихід з рекурсії

   else // -Нет. Рекурсія

       return N * Fac(N - 1);

}

static void Main()

{

   Console.WriteLine("Обчислення факториала\n");

Console.Write("Введіть ціле число: ");

string S = Console.ReadLine();

int N = int.Parse(S);

Console.WriteLine("{0}! = {1:n}", N, Fac(N));

Console.ReadLine();

}

}

При виконанні правильно організованої рекурсивної підпрограми здійснюється багатократний перехід від деякого поточного рівня організації алгоритму до нижнього рівня послідовно до тих пір, поки не буде нарешті отримано тривіальне рішення поставленої задачі. У нашому випадку рішення при N = 1 тривіально (факторіал 1 рівний 1) і використовується для зупинки рекурсії.

Рекурсивні алгоритми зазвичай виглядають витонченішими, ніж нерекурсивні, але вони мають два істотні недоліки: по-перше, при великій глибині вкладення рекурсій може виникнути переповнювання стека, оскільки кожен рекурсивний виклик залишає в стеку параметри виклику; по-друге, при вході в рекурсивну підпрограму і при виході з неї витрачається додатковий час для заштовхування параметрів виклику в стек і для витягання їх із стека. У зв'язку з цим рекомендується, якщо це можливо, використовувати нерекурсивні («плоскі») алгоритми. Наприклад, обчислити факторіал можна і за допомогою такої нерекурсивної функции:

static long Fac(int N)

{

long Res = 1;

for (int i = 1; i <= N; i++) Res = Res * i;

return Res;

}

Проте в деяких випадках обійтися без рекурсії неможливо. Наприклад, мені так і не вдалося придумати «плоский» алгоритм обходу всіх гілок дерева каталогів.

При реалізації рекурсивного алгоритму слід по можливості мінімізувати розмір даних, що передаються в рекурсивному виклику.

Лістинг 18.3. Структурізація програми з допомогою процедур

Приклад 1.

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

//

   class Program

   {//все методы должны быть объявлены в каком либо классе

       //методы, имеющие обозначение static не обязаны быть привязаны к какому либо объекту

       static void Procedure1()

       {

           Console.WriteLine("Hello from Procedure 1");

       }

       static void Procedure2()

       {

           Console.WriteLine("Hello from Procedure 2");

       }

       static int Procedure3(int i)

       {

           return (int)Math.Pow(i,2);

       }

       static string Procedure4()

       {

           return "Hello World (from Procedure 4)";

       }

       static void Main(string[] args)

       {

           Procedure1();

           Procedure2();

           int result1 = Procedure3(7);

           string result2 = Procedure4();

           Console.WriteLine("результат метода Procedure3:"+result1);

           Console.WriteLine("результат метода Procedure4:"+result2);

       }

   }

 

Приклад 2.

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

class A

{

   public void Procedure1()

   {

       Console.WriteLine("Hello from Procedure 1");

   }

   public void Procedure2()

   {

       Console.WriteLine("Hello from Procedure 2");

   }

   public int Procedure3(int i)

   {

       return (int)Math.Pow(i, 2);

   }

   public string Procedure4()

   {

       return "Hello World (from Procedure 4)";

   }

   public static void StaticProcedure()

   {

       Console.WriteLine("Hello from static procedure");

   }

}

   class Program

   {

       static void Main(string[] args)

       {//для использования методов класса А необходимо создать объект даного класса

           A objA = new A();

           objA.Procedure1();

           objA.Procedure2();

           int result1=objA.Procedure3(7);

           string result2 = objA.Procedure4();

           Console.WriteLine("Результат выполнения метода Procedure3:"+result1);

           Console.WriteLine("Результат выполнения метода Procedure4:" + result2);

           //также остаеться возможность использовать статические (static) методы даного класса А

           //для этого необходимо указать какому классу принадлежит статический метод

           //в прошлом примере этого не требовалось, поскольку статический метод находился в томже классе, где и вызывающий его метод Main

           A.StaticProcedure();

           

       }

   }


 

А также другие работы, которые могут Вас заинтересовать

15912. Уголовный процесс Украины 1.03 MB
  МИНИСТЕРСТВО ВНУТРЕННИХ ДЕЛ УКРАИНЫ УНИВЕРСИТЕТ ВНУТРЕННИХ ДЕЛ Ю.П.Янович УГОЛОВНЫЙ ПРОЦЕСС УКРАИНЫ Пособие по подготовка к государственному выпускному экзамену ХАРЬКОВ 1998 КРАТКОЕ ИЗЛОЖЕНИЕ СОДЕРЖАНИЯ ВОПРОСОВ ВЫНОСИМЫХ НА ГОСУДАРСТВЕННЫЙ ЭКЗАМЕ
15913. Реформа уголовно-исполнительной системы современной России 1.15 MB
  АКАДЕМИЯ УПРАВЛЕНИЯ МВД РОССИИ ЯЛУНИН ВЛАДИМИР УВЕНАЛИЕВИЧ РЕФОРМА УГОЛОВНОИСПОЛНИТЕЛЬНОЙ СИСТЕМЫ СОВРЕМЕННОЙ РОССИИ: ПРОБЛЕМЫ ТЕНДЕНЦИИ ПЕРСПЕКТИВЫ Специальность: 12.00.11 Судебная власть; прокурорский надзор; организация правоохранительной деятельн
15914. Правовые аспекты субьективного вменения 272 KB
  Якушин В.А. Шаталова Л.И. Правовые аспекты субъективного вменения Ульяновск 1997 Я 49 Якушин В.А. Шагалова Л.И. Правовые аспекты субъективного вменения. Средневолжский научный центр 1997. 58 с. ISBN 5776900263 В монографии с учетом достижений в области теории г
15915. Ошибка в уголовном праве и ее влияние на пределы субъективного вменения 284 KB
  В.А.Якушин В.В.Назаров Ошибка в уголовном праве и ее влияние на пределы субъективного вменения теоретические аспекты Якушин В.А.Назаров В.В. Я 49 Ошибка в уголовном праве и ее влияние на пределы субъективного вменения теоретические аспекты. Ульяновск:
15916. Вина как основа субъективного вменения 305 KB
  Якушин В.А. Каштанов К.Ф Я 49 Вина как основа субъективного вменения. Средневолжский научный центр 1997. 65 с В монографии рассматриваются различные подходы ученых к пониманию вины анализируется ее содержание и формы показывается их значение для субъективного вменен
15917. Пределы субъективного вменения в уголовном праве 234 KB
  Якушин В.А. Габидуллин М.С. Пределы субъективного вменения в уголовном праве. Ульяновск 1997. От авторов Субъективная сторона преступления относится к числу сложных и важных проблем уголовного права. Некоторые аспекты ее на сегодняшний день исследованы лишь фрагме
15918. Субьективное вменение и его значение в уголовном праве 1.53 MB
  В. А. Якушин Субъективное вменение и его значение в уголовном праве Якушин В.А. Субъективное вменение и его значение в уголовном праве. Тольятти: ТолПИ 1998 стр 296. I8ВN5230164667 В монографии с учетом и на основе достижений в области философии и психологии теори...
15919. Обратная сила уголовного закона 1.08 MB
  АССОЦИАЦИЯ ЮРИДИЧЕСКИЙ ЦЕНТР Теория и практика уголовного права и уголовного процесса А. Е. Якубов ОБРАТНАЯ СИЛА УГОЛОВНОГО ЗАКОНА НЕКОТОРЫЕ ПРОБЛЕМЫ СОВЕРШЕНСТВОВАНИЯ УГОЛОВНОГО КОДЕКСА РОССИЙСКОЙ ФЕДЕРАЦИИ СанктПетербург Юридический центр Пр...
15920. Совокупность преступлений по советскому уголовному праву 543.5 KB
  Яковлев А.М. Совокупность преступлений по советскому уголовному праву. М.: Госюриздат. 1960. [1] ЕДИНОЕ ЕДИНИЧНОЕ ПРЕСТУПЛЕНИЕ [1.1] 1. Конкретизированность однородность и разнородность действий. Совместимость действий [1.2] 2. Конкрет