7. Функции  I

 
"Нормалната диастолна функция е левокамерно пълнене при нормално
пулмокапилярно налягане (до 12 мм Нg) даващо възможност за
минутен обем достатъчен за нуждите на тялото."
Съвременна медицина, 1991 кн 6.
 
  Използване на функции (функциите като черни кутии).
* Нека е дадена следната проста програма:
#include <iostream>
using namespace std;
int main()
{ double x = 2.5;
  cout << sqrt(x);
  return 0;
}
    Входната стойност или стойността на параметъра x се предава на функцията sqrt. Изпълнението на функцията main се преустановява временно. Управлението се предава на функцията sqrt, която изчислява изхода или стойността на функцията - квадратен корен от входната стойност. Полученият резултат (върнатата от sqrt стойност) се предава обратно на main, която възобновява работата си, използвайки получената стойност (отпечатва я на екрана).
* Входни стойности (параметри) на функции.
- видове:
функция вид параметър
sqrt(x) променлива
sqrt(2.5) константа
sqrt(x+1.02) израз
- брой:
функция брой параметри
sqrt(x) 1
pow(x,y) 2
p.get_x() 0
 
- неявни параметри - за член-функции:
функция неявен параметър тип на неявния параметър
harry.get_salary() harry Employee
t.add_seconds(10) t Time
msg.move(dx,dy) msg Message

- изисквания за параметрите:

функция изисквания за параметрите
fabs(w) параметърът  w е от тип double, константа или променлива
t.second_from(t1) параметърът  t1 е от тип Time, константа или променлива
getline(cin,s) първият параметър трябва да е cin, вторият
параметър трябва да е променлива от тип string

* Изходната стойност (стойността на функцията) е от определен тип:

функция тип на изходната стойност
sqrt(x) double
c.get_center() Point
m.get_text() string
getline(cin,s) не връща стойност


  Писане на функции.
    Да се пресметне стойността на влог с начална сума 1000 лв. след 10 години при месечно начисляване на лихвата. Нека годишната лихва да е p%. Използва се формулата за пресмятане на сложна лихва.
double future_value(double p)
{ double b = 1000*pow(1 + p/(12*100), 12*10);
  return b;
}
Функцията се дефинира като се укаже: тип на резултата (на връщаната стойност), име на функцията, тип на параметъра, име на параметъра, тяло на функцията.
// futeval.cpp
#include <iostream>
#include <cmath>
using namespace std;

double future_value(double p)
{ double b = 1000*pow(1 + p/(12*100), 12*10);
  return b;
}
int main()
{ cout << "Please enter the interest rate in percent: ";
  double rate;
  cin >> rate;
  double balance = future_value(rate);
  cout << "After 10 years, the balance is " << balance << "\n";
  return 0;
}

Please enter the interest rate in percent: 6
After 10 years, the balance is 1819.4

Връщане на стойност.
** Използване на оператор return.
    Друго решение на същата задача - сега функцията future_value има 3 параметъра - началната сума, годишната лихва и брой години на престоя на влога в банката. Оператор return се използва за прекратяване на работата на функцията (при некоректни входни данни).
//futval0.cpp
#include <iostream>
#include <cmath>
using namespace std;

double future_value(double initial_balance, double p, int nyear)
/*
ЦЕЛ:       пресмята стойността на влог със сложна лихва
ПОЛУЧАВА:  initial_balance - начална стойност на влога
           p - годишен лихвен процент
           nyear - броя на годините
ЗАБЕЛЕЖКИ: лихвата се начислява всеки месец
*/
{ if (nyear < 0) return 0;
  if (p < 0) return 0;
   double b = initial_balance*pow(1 + p/(12*100), 12*nyear);
  return b;
}
int main()
{
 cout << "Interest rate in percent: ";
 double rate;
 cin >> rate;
 double bal = future_value(1000, rate, 10);
 cout << "After 10 years, the balance is " << bal << "\n";
 return 0;
}

Interest rate in percent: 8.5
After 10 years, the balance is 2332.65

** Предикат - проверка дали точка лежи в кръг.
// inside.cpp
#include "ccc_win.cpp"

bool is_inside(Point p, Circle c)
/* ЦЕЛ:  проверява дали точка p лежи в кръга c
   ПОЛУЧАВА: p - точка, c - кръг
   ВРЪЩА:  true ако p лежи в c, в противен случай - false
*/
{  double dx = p.get_x() - c.get_center().get_x();
   double dy = p.get_y() - c.get_center().get_y();
   double r = c.get_radius();
   return dx * dx + dy * dy <= r * r;
}
int main()
{  Circle c(Point(1, 1), 2);
   cwin << c;
   Point m = cwin.get_mouse("Please click inside the circle.");
   if (is_inside(m, c))
      cwin << Message(Point(3, 3), "Congratulations!");
   else
      cwin << Message(Point(3, 3), "You missed!");
   return 0;
}



Параметри на функции.
** Формални параметри  - параметри-променливи, задават се при дефиниране на функцията.
double future_value(double initial_balance, double p, int nyear)
** Фактически параметри - представляват изрази за инициализация на параметрите-променливи, указват се при извикване на функцията.
b = future_value(total/2, rate, year1-year2);
    Фактическите параметри съответстват по тип и брой на формалните параметри. В този пример променливите total и rate са от тип double, а year1 и year2 са от тип int .


Деклариране на функции.
    Функциите трябва да бъдат известни, преди да бъдат използвани. Дефинирането на дадена функция преди да бъде използвана не винаги е удобно, особено при по-големи програми, които съдържат много функции. За да използваме (извикаме) една функция достатъчно е са известни типа и името на функцията и типовете на параметрите й. Тези данни се съдържат в декларацията на функцията, която се състои от: тип на функцията (на връщаната стойност), име на функцията, типове и имена на параметри, точка и запетая.
    В езика C++ файла с текста на програмата се подрежда най-често по следния начин:  декларация на функция, използване на функция, дефиниране на функция. Декларациите на стандартните за езика функции са в заглавните файлове.
#include <iostream>
#include <cmath>
using namespace std;

/* декларация на функцията future_value */
double future_value(double initial_balance, double p, int nyear);
int main()
{ ...
/* използване на функцията future_value */
 double bal = future_value(10000, rate, 10);
 ...
}
/* дефиниция на функцията future_value */
double future_value(double initial_balance, double p, int nyear)
{
 ...
}



Странични ефекти и процедури.
** Външно забележимият ефект от функция се нарича страничен ефект - отпечатване на някакво съобщение, прекратяване работата на програмата и др. Функциите по принцип не трябва да имат странични ефекти.
** Когато едно действие трябва да бъде извършено многократно (поне 2 пъти), има смисъл да бъде обособено като функция. Функция, която не връща стойност се нарича процедура.
* Процедура за отпечатване на обект от тип Time.
// printtime.cpp
#include <iostream>
#include <iomanip>
using namespace std;
#include "ccc_time.cpp"

void print_time(Time t)
/* ЦЕЛ:  отпечатва времето във формат hh:mm:ss
   ПОЛУЧАВА: t - времето, което ще се отпечати
*/
{  cout << t.get_hours() << ":";
   if (t.get_minutes() < 10) cout << "0";
   cout << t.get_minutes() << ":";
   if (t.get_seconds() < 10) cout << "0";
   cout << t.get_seconds();
}
int main()
{  Time liftoff(7, 0, 15);
   cout << "Liftoff: "; print_time(liftoff); cout << "\n";
   Time now;
   cout << "Now: "; print_time(now); cout << "\n";
   return 0;
}

Liftoff: 7:00:15
Now: 11:59:02