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();

           

       }

   }


 

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

85003. Пожарная безопасность. Определение пожара и пожарной безопасности 27.76 KB
  Систематизировать знания учащихся о пожаре об основных причинах возникновения пожаров в повседневной жизни. Рассказать о возможных последствиях пожаров и об организации защиты населения от пожаров. Дать определение пожара показать основные причины возникновения пожаров привести примеры последствий пожаров имевших место в нашем городе. Довести до учащихся в доступной для них форме организацию защиты населения страны от пожаров.
85004. Безопасное поведение в бытовых ситуациях 27.25 KB
  Разобрать ситуационные задания по обеспечению личной безопасности в бытовых ситуациях; выработать убеждение в необходимости соблюдать правила эксплуатации бытовых приборов и систем в целях обеспечения личной безопасности и безопасности окружающих. Меры безопасности при пользовании в доме водой. Контрольные вопросы Какие меры безопасности необходимо соблюдать при пользовании электроприборами Какие меры безопасности необходимо соблюдать при пользовании бытовым газом Какие меры безопасности следует соблюдать при пользовании в доме водой...
85005. Наводнения. Виды наводнений и их причины. Защита населения от последствий наводнений 37.2 KB
  Наводнения. Опасность которую представляют наводнения для жизнедеятельности человека. Общие профилактические мероприятия по защите населения от наводнения. Правила поведения во время наводнения.
85006. Лесные и торфяные пожары и их характеристика 33.21 KB
  Лесные и торфяные пожары и их характеристика Цель урока. Познакомить обучаемых с опасным природным явлением биологического происхождения лесными пожарами показать основные причины возникновения лесных пожаров особо подчеркнуть что в 80 случаев лесные пожары возникают по вине человека. Изучаемые вопросы Характеристика лесных пожаров и основных причин их возникновения. Классификация лесных пожаров.
85007. Профилактика лесных и торфяных пожаров, защита населения 33.49 KB
  Профилактика лесных и торфяных пожаров защита населения Цель урока. Сформировать у учащихся убеждение в том что лучшей профилактикой возникновения лесных пожаров является соблюдение каждым человеком правил пожарной безопасности в лесу. Изучаемые вопросы Профилактические мероприятия по предотвращению возникновения лесных пожаров. Основной причиной лесных пожаров является безответственное поведение людей которые не проявляют в лесу должной осторожности при пользовании огнем и нарушают правила пожарной безопасности.
85008. Эпидемия 31.55 KB
  Сформировать у учащихся цельное представление об инфекционных заболеваниях и путях распространения инфекции. Изучаемые вопросы Инфекционные болезни и пути распространения инфекции. Дать определение понятию инфекционные болезни привести классификацию инфекционных заболеваний в зависимости от способа передачи инфекции и по источнику возбудителя инфекции. Рассмотреть причины возникновения инфекционных болезней и пути распространения инфекции.
85009. Эпизоотии и эпифитотии, противоэпизоотические и противоэпифитотические мероприятия 31.43 KB
  Дать краткую информацию об инфекционных заболеваниях растений рассмотреть явления эпифитотии панфитотии. Наиболее опасными болезнями растений являются стеблевая ржавчина пшеницы ржи желтая ржавчина пшеницы фитофтороз картофеля. Для защиты растений от инфекционных болезней важно соблюдение правил агротехники на всех этапах сельскохозяйственных работ связанных с растениеводством. Проводят также следующие мероприятия: выведение устойчивых к болезням сортов сельскохозяйственных растений; уничтожение очагов инфекции; химическую обработку...
85010. Общие понятия о здоровье как основной ценности человека 31.7 KB
  Общие понятия о здоровье как основной ценности человека Цель урока. Сформировать у учащихся цельное представление о здоровье человека как об индивидуальной и общественной ценности обратив их внимание на основные показатели которые характеризуют уровень здоровья. Привести их к пониманию что здоровье человека неотделимо от его жизнедеятельности. Изучаемые вопросы Здоровье человека и основные показатели характеризующие его уровень.
85011. Индивидуальное здоровье человека, его физическая, духовная и социальная сущность 32.16 KB
  Индивидуальное здоровье человека его физическая духовная и социальная сущность Цель урока. Сформировать у них цельное представление об основных элементах образа жизни человека оказывающих влияние на формирование его духовного физического и социального благополучия а также убеждение в том что каждый человек несет ответственность за свое здоровье и благополучие. Изучаемые вопросы Основные составляющие индивидуального здоровья человека. Некоторые элементы образа жизни человека обеспечивающие его духовное физическое и социальное...