Ֆունկցիաներ

Մաթեմատիկական մեկնաբանությամբ ֆունկցիան մի գործողություն է, որը մի բազմությունը՝ որոշման տիրույթը, արտապատկերում է մեկ այլ բազմության՝ արժեքների տիրույթին։ C++ լեզվում նույնպես այդպես է․ ֆունկցիան ստանում է արգումենտներ և վերադարձնում է արժեք։ Բայց նաև, ծրագրավորման գործի առանձնահատկություններից ելնելով, C++ լեզուն թույլատրում է սահմանել ֆունկցիաներ, որոնք արգումենտներ չեն ստանում կամ/և արժեքներ չեն վերադարձնում։ Այլ կերպ ասած, C++ լեզվում ֆունկցիան նաև պրոցեդուրա է, որը կարող է թողնել հաշվարկման կողմնակի էֆեկտներ։

Նախորդ գլուխներում main ֆունկցիայի օրինակով արդեն տեսանք, որ C++ լեզվում ֆունկցիայի սահմանումն ունի չորս բաղադրիչ. ա․ վերադարձվող արժեքի տիպ, բ․ անուն, գ․ պարամետրերի ցուցակ, դ․ մարմին։

Ֆիզիկայի դպրոցական դասընթացից հիշենք ազատ անկում կատարող մարմնի անցած ճանապարհի բանաձևը․ (որտեղ ) և սահմանենք դրան համարժեք C++ ֆունկցիան․

double distance( double t )
{
  return (9.81 * t * t) / 2;
}

Այս ֆունկցիայի վերադարձվող արժեքի տիպը double է, անունը distance է, պարամետրերի ցուցակում double տիպի t պարամետրն է, իսկ մարմինը բաղկացած է միակ return հրամանից, որի արգումենտում մարմնի անցած ճանապարհի հաշվման բանաձևն է։

Ֆունկցիայի տիպ է կոչվում վերադարձրած արժեքի տիպի ու պարամետրերի տիպերի ցուցակի համադրությունը։ Մաթեմատիկական արտահայտությամբ, օրինակ, distance ֆունկցիան իրական թվերի բազմությունն արտապատկերում է նույն իրական թվերի բազմությանը՝ ։

Եթե հարկավոր է սահմանել այնպիսի մի ֆունկցիա, որից արժեք չենք ակնկալում, ապա պետք է դրա վերադարձվող արժեքի տիպը նշել որպես void։ Օրինակ, ստորև սահմանված print_number ֆունկցիան ստանում է առանց նշանի ամբողջ թիվ (unsigned int) և արտածում է այդ թվի տասական, ութական ու տասնվեցական ներկայացումները։ Այդ ներկայացումները ստացվում են հոսքերի dec, oct և hex մանիպուլյատորների օգնությամբ, որոնք սահմանված են iostream ֆայլում։

void print_number( unsigned int num )
{
  std::cout << std::dec << num << " "
            << std::oct << num << " "
            << std::hex << num << " "
            << std::endl;
}

Եթե ֆունկցիայի պարամետրերի քանակը մեկից ավելի է, ապա դրանք պարամետրերի ցուցակում թվարկվում են իրարից ստորակետով անջատված։ Օրինակ, avg ֆունկցիան ստանում է երեք իրական թիվ և վերադարձնում է դրանց թվաբանական միջինը։

double avg( double a, double b, double c )
{
  auto sum = a + b + c;
  return sum / 3;
}

Եթե մի որևէ f() ֆունկցիայում օգտագործվելու է մի այլ g() ֆունկցիա, ապա այն պետք է ավելի շուտ հայտարարված կամ սահմանված լինի։ Օրինակ, ծրագրի տեքստում f() և g() ֆունկցիաների փոխադարարձ դասավորությունը կարող է լինել այսպիսին.

int g( double a, char b )
{
    // ինչ-որ հրամաններ
    return 777;
}

void f( int x )
{
    // ինչ-որ հրամաններ
    auto v = g( 3.14, 'p' );
    // ինչ-որ հրամաններ
}

Կամ, f() ֆունկցիային կարող է նախորդել միայն g() ֆունկցիայի հայտարարությունը։ Ահա այսպես.

int g( double, char );

void f( int x )
{
    // ինչ-որ հրամաններ
    auto v = g( 3.14, 'p' );
    // ինչ-որ հրամաններ
}

int g( double a, char b )
{
    // ինչ-որ հրամաններ
    return 777;
}

Առաջին տողում գրված արտահայտությունը կոմպիլյատորին տեղեկացնում է, որ գոյություն ունի g անունով ֆունկցիա՝ double և char տիպի պարամետրերով և int արժեք վերադարձնող, որի սահմանումը գալու է քիչ ավելի ուշ։

C++ լեզուն թույլ է տալիս սահմանել նույն անունով, բայց տարբերվող պարամետրերի ցուցակով ֆունկցիաներ։ Այդ հնարավորությունն անվանում են ֆունկցիայի վերասահմանում։ Օրինակ, սահմանենք sum անունով երկու ֆունկցիա, որոնցից առաջինը վերադարձնում է տրված երկու իրական թվերի գումարը, իսկ երկրորդը՝ երեք թվերի գումարը։

double sum( double a, double b )
{
    return a + b;
}

double sum( double a, double b, double c )
{
    return sum( sum(a, b), c );
}

Վերասահմանվող ֆունկցիաները պետք է տարբերվեն կամ պարամետրերի քանակով, կամ էլ դրանց տիպերով։ Օրինակ, սահմանենք print անունով երկու ֆունկցիա, որոնցից առաջինը տպում է ամբողջ թիվ, իսկ երկրորդը՝ բուլյան արժեք.

void print( int val )
{
    std::cout << "Ես ամբողջ թիվ եմ - " 
              << val << std::endl;
}

void print( bool val )
{
    std::cout << "Ես բուլյան արժեք եմ - " 
              << std::boolalpha << val 
              << std::endl;
}

Եթե նույնն սահմանված ֆունկցիաների և անունները, և պարամետրերի քնակները, և դրանց տիպերը, ապա ֆունկցիայի կանչի ժամանակ հնարավոր չի լինի պարզել, թե տարբերակներից որ մեկն է կանչվում։ Կոմպիլյատորը հեշտությոմբ բացահայտում է այսպիսի դեպքերը և ծրագրավորողին տալիս է համապատասխան հաղորդագրություն։

Պարզ է արդեն, որ ֆունկցիայի վերասահմանումը հարմար է այն դեպքում, երբ անհրաժեշտ է ծրագրում ունենալ նույն անունով, բայց մարմինների տարբեր իրականացումներով ենթածրագրեր։ Բայց հետաքրքիր է, որ շատ հաճախ հանդիպում է նաև հակառակ իրավիճակը․ երբ անհրաժեշտ ենթածրագրի նույն իրականացումն օգտագործել տվյալների տարբեր տիպերի համար։

C++ լեզուն հնարավորություն է տալիս սահմանել պարամետրիզացված տիպերով ենթածրագրեր՝ ֆունկցիաների կաղապարներ (template)։ Կաղապարի օգնությամբ սահմանվում է ոչ թե կոնկրետ ֆունկցիան, այլ նրա ընդհանրացված (generic) ներկայացումը։ Կաղապարի սահմանումը սկսվում է template ծառայողական բառով, որին հետևում են կաղապարի պարամետրերը՝ նշված typename բառով։ Օրինակ,

template<typename E>
E plus( E x, E y )
{
  return x + y;
}

C++ լեզվի ֆունկցիաները կարող են ունենալ նաև լռելության արժեքով պարամետրեր։ Սա նշանակում է, որ ֆունկցիայի սահմանման ժամանակ կարելի է պարամետրերից որոշներին (կամ բոլորին) տալ ինչ-որ արժեքներ, իսկ ֆունկցիայի կանչի ժամանակ, հնարավորության դեպքում, այդ արգումենտները չoգտագործել։ Օրինակ, ենթադրենք սահմանված է հետհևյալ ֆունկցիան.

void hello( std::string name = "աշխարհ" )
{
  std::cout << "Ողջո՜ւյն, " << name << "։" << std::endl;
}

Այս դեպքում, եթե այն կանչված է առանց արգումենտների՝ hello(), ապա արտածվում է «Ողջո՜ւյն, աշխարհ։» տողը, իսկ եթե արգումենտով, օրինակ, hello("Պետրոս"), ապա՝ «Ողջո՜ւյն, Պետրոս։» տողը։


--- Հղումների մասին --- պարամետրերով վերադարձվող արժեքների մասին ---

results matching ""

    No results matching ""