From Wikipedia, the free encyclopedia
C++ (արտասանվում է ինչպես սի փլաս փլաս ˌsiːˌplʌsˈplʌs) ընդհանուր նշանակության ծրագրավորման լեզու, որը համարվում է «միջին-մակարդակի» լեզու, քանի որ թույլատրում է ինչպես ցածր մակարդակի, այնպես էլ բարձր մակարդակի ծրագրավորում։ Այն ստատիկորեն տիպավորվող, բազմապիսի մոտեցումներ թույլատրող (multi-paradigm), սովորաբար կազմակվող (կոմպիլյացվող) լեզու է[2][3]։
Տեսակ | օբյեկտ կողմնորոշված ծրագրավորման լեզու, բազմահարացուցային ծրագրավորման լեզու, ծրագրավորման պրոցեդուրային լեզու, ֆունկցիոնալ ծրագրավորման լեզու, ընդհանուր ծրագրավորման լեզու, ծրագրավորման լեզու, free-form language? և ծրագրավորման կոմպիլյացվող լեզու |
---|---|
Կատարման ձև | բազմապարադիկմային.[1] պրոցեդուրային, ֆունկիցոնալ, օբյեկտ կողմնորոշված, ջեներիկ |
Առաջացել է | 1983 |
Ստեղծող | Բյորն Ստրաուստրուպ |
Նախագծող | Բյորն Ստրաուստրուպ |
Ընդլայնումներ | .cc , .cpp , .cxx , .c , .c++ , .h , .hpp , .hh , .hxx և .h++ |
Տիպիզացիա | ստատիկ, նորմինատիվ |
Համացանցի տվյալների տեսակ | text/x-c և text/plain |
Ընթացիկ տարբերակ | ISO/IEC 14882:2011 |
Ներշնչվել է | Սի (ծրագրավորման լեզու), Simula, Ալգոլ 68, Կլու, ML և Ադա |
Ստանդարտացման մարմին | ISO և International Electrotechnical Commission? |
Կայք | isocpp.org(անգլ.) |
Ելակոդ | github.com/cplusplus/draft |
C++ Վիքիպահեստում |
Բյորն Ստրաուստրուպը, ստեղծեց C++ լեզուն Bell Labs-ում 1979 թ.-ին, որպես C ծրագրավորման լեզվի բարելավում և անվանեց այն «C with Classes»: 1983 թ.-ին այն վերանվանվեց C++ -ի։
C++ -ը ամենատարածված ծրագրավորման լեզուներից է։ Կիրառման ոլորտներից են համակարգային ծրագրավորումը, կիրառական ծրագրերի ստեղծումը, ֆիզիկական սարքավորումների՝ օպերացիոն համակարգի հետ կապի ապահովման ծրագրերի ստեղծումը, բարձր արդյունավետությամբ աշխատող սերվեր և օգտագործող ծրագրերի ստեղծումը, ինչպես նաև, ներդրված ծրագրերի և համակարգչային խաղերի ստեղծումը։
Պատմական փուլերը[4] | Տարի |
---|---|
BCPL լեզու | 1966 |
Բի լեզու (Տոմպսոնի բնօրինակը զարգացումը UNIX-ի տակ) | 1969 |
Սի լեզու | 1972 |
Սին դասերով | 1980 |
C84 | 1984 |
Cfront (E թողարկում) | 1984 |
Cfront (1.0 թողարկում) | 1985 |
Բազմակի /վիրտուալ ժառանգությունը | 1988 |
Ծրագրավորման ընդհանրացված (կաղապարները) | 1991 |
ANSI C++ / ISO-C++ | 1996 |
ISO/IEC 14882:1998 | 1998 |
ISO/IEC 14882:2003 | 2003 |
C++/CLI | 2005 |
TR1 | 2005 |
C++11 | 2011 |
Լեզուն առաջացել է 1980-ական թվականների սկզբին, երբ Bell Labs ընկերության աշխատակից Բյորն Ստրաուստրուպը սեփական կարիքների համար մի շարք կատարելագործումներ մտածեց C ծրագրավորման լեզվի համար[5]։ Երբ 1970-ականների վերջում Ստրաուստրուպը սկսեց աշխատել Bell Labs-ում հաջորդականությունների տեսության առաջադրանքների վրա (հեռախոսների մոդելավորման հավելվածում), նա բացահայտեց, որ այդ ժամանակ գոյություն ունեցող մոդելավորման լեզուների կիրառման փորձերը արդյունավետ չէին, իսկ բարձր արդյունավետություն ունեցող մեքենայական լեզուների կիրառումը չափազանց բարդ է՝ նրանց սահմանափակ արտահայտչականության պատճառով։ Այսպես, Սիմուլա (ծրագրավորման լեզու) լեզուն ունի այնպիսի հնարավորություն, որ մեծ ծրագրային ապահովման մշակման ժամանակ բավականին օգտակար կլինի, սակայն այն շատ դանդաղ է աշխատում։ Իսկ BCPL լեզուն բավականին արագ է աշխատում, սակայն շատ մոտ է ցածր մակարդակի լեզուներին և չի կարող կիրառվել մեծ ծրագրային ապահովում մշակման ժամանակ։
Հիշելով ատենախոսության իր փորձը, Ստրաուստրուպը որոշեց ավելացնել C լեզվի (որի իրավահաջորդը BCPL-ն է) հնարավորությունները, մատչելի Սիմպուլա լեզվով։ C լեզուն, լինելով հիմնարար լեզուն UNIX համակարգի, որի վրա աշխատել են Bell համակարգիչները, արագ են, բազմաֆունկցիոնալ և շարժական։ Ստրաուստրուպը ավելացրել էր հնարավորություն տալիս աշխատել դասերով և օբյեկտներով։ Արդյունքում գործնական խնդիրները մոդելավորման դարձավ մատչելի լուծելու ինչպես ժամանակի տեսանկյունից մշակման (շնորհիվ օգտագործման Սիմպուլա-նման դասերի), այնպես էլ ժամանակի տեսանկյունից հաշվարկներով (շնորհիվ արագ աշխատող C-ի)։ Առաջին հերթին C է եղել ավելացվել դասեր (ինկափսուլացիայով), դասերի ժառանգումը, խիստ ձևերի ստուգում, inline-գործառույթները և default փաստարկները։ Վաղ լեզվի տարբերակը, սկզբնապես անվանվել էր «C with classes» («Սի դասերով»), դարձավ հարսանելի 1980 թվականից։
Մշակելով C դասով, Ստրաուստրուպ գրեց cfront ծրագիրը - տրանսյլատոր, վերամշակման հենակետային կոդը C-ն դասով հենակետային կոդում պարզապես C: Որը թույլ տվեց աշխատել լեզվի հետ և օգտագործել այն պրակտիկայում, կիրառելով նախապես գոյություն ունեցող UNIX-ի ենթակառուցվածքը C-ն մշակելու համար։ Նոր լեզուն, անսպասելի էր հեղինակի համար, ձեռք բերեց մեծ տարածվածություն իր գործընկերների շրջանում և շուտով Ստրաուստրուպը չի կարող անձամբ աջակցել դրան, պատասխանեց մոտ հազար հարցի։
1983 թ. լեզվում ավելացվեց նոր հնարավորություններ, ինչպիսիք են. վիրտուալ ֆունկցիաները, ֆունկցիաների և օպերատորների գերբեռնվածությունը, հղումները, հաստատունները, օգտվողի վերահսկողությունը ազատ հիշողության կառավարման, բարելավվել էր ձևի ստուգումը և նոր ոճ (//
) մեկնբանություններին։ Ստացված լեզուն արդեն դադարեց պարզապես լինել լրացվաց տարբերակ դասական C-ին և վերանվանվեց C-ն դասերով ից «C++»: Առաջին կոմերցիոն թողարկումը եղել է 1985 թվականի հոկտեմբերին։
Սկզբում օֆիցիալ լեզվի ստանդարտացման զարգացումը հիմնականում եղել է Ստրաուստրուպի ուժերով ի պատասխան ծրագրավորման հասարակությանը։ Ստանդարտ լեզվի ֆունկցիաների նկարագրություններ, գրել է Ստրաուստրուպը C++-ի աշխատանքները հրապարակելուց (լեզվի նկարագրությունը, հղումը ուղեցույցը և այլն)։ Միայն 1998 թվականին վավերացվեց C++ լեզվի միջազգային ստանդարտը՝ ISO/IEC 14882:1998 «Standard for the C++ Programming Language»; հետո 2003 թվականին ստանդարտի տեխնիկական ուղղումները կատարելուց - ստեղծվեց ստանդարտի հաջորդ տարբերակը - ISO/IEC 14882:2003[6]:
C++ լեզուն ստեղծելիս Բյորն Ստրաուստրուպն ուզում էր անել հետևյալը[7].
C լեզվի ընտրությունը որպես նոր ծրագրավորման լեզվի բազա պայմանավորված է նրանով, որ C լեզուն.
Չնայած C լեզվի մի շարք թերությունների, Ստրաուստրուպն ընտրեց C լեզուն, քանի որ այդ թերություններն արդեն հայտնի են, իսկ նոր ստեղծված ծրագիրն անկասկած կունենա իր թերությունները, որոնք դեռ պետք է բացահայտել։ Բացի այդ դա թույլ տվեց արագորեն կոմպիլյատոր (cfront) ստանալ, որը պարզապես նոր ավելացված սինտաքսային տարրերը տրանսլյացիա էր անում օրիգինալ C լեզվի։
C++ լեզուն զարգացնելու ժամանակ լեզվում ներառնվեցին միջոցներ, որոնք ծածկում էին C լեզվի կոնստրուկտիվ հնարավորությունները։ Այդ պատճառով էլ բազմաթիվ անգամ առաջարկներ եղավ վերացնել C լեզվի հետ համատեղելիությունը։ Այսպես թե այնպես համատեղելիություն նպատակահարմար եղավ թողնել, իսկ թողնելու պատճառները հետևյալն են.
1983 թ.-ին լեզվին ավելացվեցին նոր հատկություններ՝ վիրտուալ ֆունկցիաներ, ֆունկցիաների և օպերատորների վերբեռնում, հղումներ, հաստատուններ, ազատ հիշողության օգտագործման կառավարում օգտատիրոջ կողմից և մեկնաբանության նոր ոճ (//
)։ Ստացված լեզուն դատարեց C լեզվի վրա լոկ հավելումներով տարբերակ լինելուց և նրան «կլասներով C լեզվից» վերանվանեցին «C++»: Լեզվի առաջին կոմերցիոն թողարկումը լույս տեսավ 1985 թ.-ին։
Լեզվի անունն արյունքում ստացվեց ունար պոստֆիքս «ինկրեմենտից» ++
(արժեքի մեծացում մեկ միավորով)։ C+ անվանումը նրա համար չի օգտագործվել, քանի որ C լեզվի տեսանկյունից այն սխալ է պարունակում։ Բացի դրանից նպատակահարմար չէր լեզուն վերանվանել D, քանի նորաստեղծ լեզուն իրենից ներկայացնում էր C լեզվի ընդլայնված տարբերակը[3]։
1985 թվականին լույս տեսավ «C++ ծրագրավորման լեզու» գրքի առաջին հրատարակությունը, որն այդ լեզվի առաջին նկարագրությունն էր։ Այն կարևոր դեր խաղաց լեզվի հետագա զարգացման վրա, քանի որ լեզվի պաշտոնական ստանդարտ դեռևս գոյություն չուներ։ 1989 թվականին թողարկվում է C++-ի 2.0 տարբերակը։ Նրա նոր հնարավորությունները իրենց մեջ ներառում էին բազմակի ժառանգումը, աբստրակտ դասերը, ստատիկ ֆունկցիա–անդամները, ֆունկցիա–հաստատունները և պաշտպանված անդամները։ 1990 թվականին լույս է տեսնում «C++–ի մեկնաբանված տեղեկատվական ուղեցույց» գիրքը, որը հետագայում ստանդարտի համար որպես հիմք է ծառայել։ Վերջին թարմացումները ներառում էին կաղապարները, բացառությունները, անվանատարածքները, տիպերի վերման նոր եղանակները և բուլյան տիպը։
C++ լեզվի հետ միաժամանակ զարգանում էր նաև նրա ստանդարտ գրադարանը։ C++–ի ստանդարտ գրադարանի առաջին հավելումներն էին մուտքի–ելքի հոսքերը, որոնք ապահովում էին C լեզվի ավանդական printf
և scanf
ֆունկցիաների փոխարինման նոր միջոցներ։ Ավելի ուշ, ստանդարտ գրադարանի ամենանշանակալից զարգացումը դարձավ Կաղապարների ստանդարտ գրադարանի ներառումը։
1998 թվականին հրատարակվեց լեզվի ISO/IEC 14882:1998 ստանդարտը (հայտնի է որպես C++98)[8], որն մշակվել էր C++–ի ստանդարտավորման հանձնաժողովի կողմից (ISO/IEC JTC1/SC22/WG21 working group)։ C++–ի ստանդարտը չի նկարագրում օբյեկտների անվանման եղանակները, բացառությունների մշակման որոշ մանրամասներ և այլ հնարավորություններ, որոնք ավելի շատ կապված են իրականացման մանրամասների հետ, որը տարբեր կոմպիլյատորների կողմից ստեղծված օբյեկտային կոդերը միմյանց միջև դարձնում է անհամատեղելի։ Սակայն դրա համար երրորդ դեմքերի կողմից ստեղծվել են բազմաթիվ ստանդարտներ որոշակի կառուցվածքների և օպերացիոն համակարգերի համար։
2003 թվականին հրապարակվեց լեզվի ISO/IEC 14882:2003 ստանդարտը, որտեղ ուղղված էին լեզվի նախորդ ստանդարտի բացահայտված սխալներն ու թերությունները։
2005 թվականին թողարկվեց Library Technical Report 1 (կարճ անվանումով՝ TR1) հաշվետվությունը։ Չհանդիսանալով պաշտոնական ստանդարտի մի մաս, հաշվետվությունը նկարագրում է ստանդարտ գրադարանի ընդլայնումներ, որոնք, համաձայն հեղինակների սպասելիքների, C++ լեզվի հաջորդ տարբերակներում պետք է ներառվեն։ TR1-ի աջակցման աստիճանը բարելավվում է C++ լեզվի համարյա թե բոլոր աջակցվող կոմպիլյատորներում։
2009 թվականից սկսած աշխատանք էր տարվում նախորդ ստանդարտի թարմացման ուղղությամբ։ Սկզբում նոր ստանդարտի նախնական տարբերակն էր C++99-ը, իսկ մեկ տարի անց C++0x-ը, այսօր՝ C++11-ը, որտեղ ներառված էին լեզվի միջուկի հավելումներ և ստանդարտ գրադարանի ընլայնումներ, այդ թվում՝ TR1-ի մեծ մասը։
C++-ը շարունակում է զարգանալ, որպեսզի բավարարի ժամանակակից պահանջներին։ C++ լեզուն մշակող և ստանդարտավորման հանձնաժողովին լեզվի բարելավմանը նպաստող առաջարկներ ներկայացնող խմբերից մեկը Boost-ն է, որն, այդ թվում, զբաղվում է նաև լեզվի հնարավորությունների կատարելագործմամբ՝ լեզվում ավելացնելով մետածրագրավորման առանձնահատկությունները։
Ոչ մեկ չունի C++ լեզվի նկատմամբ ավելի շատ իրավունքներ, քան մյուսները․ այն ազատ է։ Սակայն լեզվի ստանդարտի փաստաթուղթը անվճար հասանելի չէ (բացառությամբ ստանդարտների սևագրերը)։
C++–ի 2003 թվականի ստանդարտը կազմված է երկու հիմնական մասերից՝ լեզվի միջուկի նկարագրությունից և ստանդարտ գրադարանների նկարագրությունից։
Բացի այդ, գոյություն ունեն մեծ թվով C++–ի գրադարաններ, որոնք չեն մտնում տվյալ ստանդարտի մեջ։ C++–ով գրված ծրագրերում կարելի է օգտագործել C լեզվի շատ գրադարաններ։
Ստանդարտացումն սահմանում է C++ ծրագրավորման լեզուն, սակայն C++ անվանման ետևում կարող են թաքնված լինել նաև լեզվի ոչ լիարժեք, սահմանափակ, մինչ ստանդարտային տարբերակներ։ Սկզբնական շրջանում լեզուն զարգանում էր առանց ձևական շրջանակների, ինքնաբերաբար, իր առջև դրված խնդիրների սահմաններում։ Լեզվի զարգացումն ուղեկցվել է cfront կոմպիլյատորի զարգացմամբ։ Լեզվի նորամուծություններին համընթաց փոփոխվում էր նաև cfront–ի տարբերակի համարը։ Կոմպիլյատորի այդ համարը տարածվում էր նաև լեզվի վրա, սակայն այսօր C++ լեզվի տարբերակների մասին չեն խոսում։
Այս բաժնում նկարագրվում են հնարավորություններ, որոնք անմիջականորեն կապված չեն օբյեկտ կողմնորոշված ծրագրավորման (ՕԿԾ) հետ, բայց որոնցից շատերը կարևոր դեր են խաղում ՕԿԾ–ի կիրառման ժամանակ։
C++–ն աջակցում է մեկնաբանություններ ինչպես C լեզվի ոճով՝
/*
Սա մեկնաբանություն է, որը կարող է կազմված լինել
մի քանի տողերից
*/
այնպես էլ մեկ տողանի մեկնաբանություններ՝
// այս տողի մնացած մասը համարվում է մեկնաբանություն
որտեղ //
–ը նշանակում է մեկնաբանության սկիզբ, իսկ ամենամոտիկ տողանցման նշանը, որը \
նշանով (կամ նրան համարժեք ??/
նշանակմամբ) հայելիացված չէ, համարվում է մեկնաբանության ավարտ։ Ստացվում է, տվյալ տողի սահմաններում //
–ից հետո գրված ամեն ինչ համարվում է մեկնաբանություն։
C++ լեզվում հասանելի են հետևյալ ներկառուցված տիպերը՝
char
, wchar_t
(char16_t
և char32_t
, C++11 ստանդարտում)։signed char
, short int
, int
, long int
(և long long int
, C++11 ստանդարտում)։unsigned char
, unsigned short int
, unsigned int
, unsigned long int
(և unsigned long long int
, C++11 ստանդարտում)։float
, double
, long double
:bool
, որն կարող է ընդունել true
և false
արժեքներից մեկը։Համեմատության գործողություններն վերադարձնում են bool
տիպի արժեքներ։ if
–ից և while
–ից հետո դրվող փակագծերի արտահայտությունները բերվում են bool
տիպի[9]։
Ֆունկցիաները կարող են ընդունել արգումենտներ հղումով։ Օրինակ, void f(int &x) {x=3;}
ֆունկցիան վերագրում է իր արգումենտին 3 արժեքը։ Ֆունկցիաները կարող են նաև արդյունքները վերադարձնել հղումով, և այդ հղումները կարող են ոչ մի կապ չունենալ ֆունկցիայի հետ։ Օրինակ, {double &b=a[3]; b=sin(b);}
կոդը համարժեք է a[3]=sin(a[3]);
կոդին։ Ծրագրավորման ժամանակ հղումներն ինչ–որ չափով նման են ցուցիչներին՝ հետևյալ առանձնահատկություններով․
Գոյություն ունեն նաև այլ տարբերություններ ցուցչի և հղման օգտագործման միջև։ Ըստ գաղափարի, հղումը փոփոխականի կամ ֆունկցիայի մեկ այլ անունն է, միևնույն հասցեի մեկ այլ անվանումը։ Այն գոյություն ունի միայն ծրագրի կոդում և կոմպիլյացիայի ժամանակ փոխարինվում է իր հասցեով։ Իսկ ցուցիչը փոփոխական է, որում պահվում է հասցեն, որին դիմում են։
inline
սպեցիֆիկատորը թույլ է տալիս հայտարարել inline–ֆունկցիաներ։ Ֆունկցիան, որը որոշված է դասի մարմնի ներսում, լռելյայն inline է համարվում։ Ի սկզբանե inline–ֆունկցիաները մտածված էին այնպես, որ նրանք բարելավման համար լավ թեկնածուներ էին, քանի որ այն տեղերում, որտեղ կանչվում էր ֆունկցիան, կոմպիլյատորը պետք է ուղղակի տեղադրեր ֆունկցիայի մարմինը, այլ ոչ թե առանձին կատարեր ֆունկցիան և տեղադրեր արժեքը։ Իրականում կոմպիլյատորը պարտադիր չէ, որ իրականացնի inline–ֆունկցիայի մարմնի տեղադրումը այնտեղ, որտեղից կանչվում է այդ ֆունկցիան, բայց նա կարող է, ելնելով բարելավման տրված աստիճանից, այդպես վարվել ոչ inline–ֆունկցիաների հետ։ inline-ֆունկցիաների ամենամեծ առանձնահատկությունն այն է, որ այն կարող է բազմակի անգամ հայտարարվել մի քանի թարգմանման միավորներում (միևնույն ժամանակ inline-ֆունկցիան պետք է հայտարարված լինի բոլոր այն թարգմանման միավորներում, որտեղ այն օգտագործվում է), իսկ inline չհանդիսացող ֆունկցիաները կարող են հայտարարվել ծրագրում մեկից ավել անգամ։ Օրինակ՝inline double Sqr(double x) {return x*x;}
:
volatile
նկարագրիչը օգտագործվում է փոփոխականների նկարագրման ժամանակ և տեղեկացնում է կոմպիլյատորին, որ տվյալ փոփոխականի արժեքը կարող է փոխվել կոմպիլյատորի կողմից անհայտ եղանակով։ Այն փոփոխականների համար, որոնք հայտարարված են որպես volatile
, կոմպիլյատորը չպետք է կիրառի այնպիսի բարելավման միջոցներ, որոնք փոփոխում են փոփոխականի տեղը հիշողության մեջ (օրինակ, այն ռեգիստր տեղափոխող միջոցներ) կամ ենթադրում են, որ փոփոխականի արժեքը նրա երկու վերագրման գործողությունների միջև չի փոփոխվելու։ Բազմամիջուկ համակարգերում volatile
–ն օգնում է խուսափել հիշողության 2–րդ կարգի խոչընդոտներից։union
) կամ թվարկում (enum
), նրա անունը հանդիսանում է տիպի անուն, օրինակ՝struct Time {
int hh, mm, ss;
};
Time t1, t2;
namespace Foo
{
const int x=5;
typedef int** T;
void f(int y) {return y*x};
double g(T);
...
}
ապա ձևավոր փակագծերից դուրս T–ին, x–ին, f–ին, g–ին դիմելիս պետք է համապատասխանաբար գրել այսպես՝ Foo::T, Foo::x, Foo::f և Foo::g։ Եթե որևէ ֆայլում անհրաժեշտ է անմիջականորեն դիմել այդ անվանատարածքի անդամներին, կարելի է գրել՝
using namespace Foo;
Կամ այսպես՝
using Foo::T;
Անվանատարածքներն անհրաժեշտ են, որպեսզի համընկնող անուններով գլոբալ փոփոխականներ, ֆունկցիաներ և տիպեր ունեցող փաթեթների միջև անհամաձայնություններ չառաջանան։ Որպես մասնավոր դեպք կարելի է նշել անանուն անվանատարածքը՝
namespace
{
...
}
Նրանում հայտարարված բոլոր անունները հասանելի են միայն ընթացիկ թարգմանման միավորում և ուրիշ ոչ մի տեղ։
void f(int x, int y=5, int z=10)
, ֆունկցիայի f(1)
, f(1,5)
և f(1,5,10)
կանչերը համարժեք են միմյանց։int printf(const char* fmt, ...)
:typedef
–ի միջոցով, այնպես էլ այլ դասերի, ինչպես նաև՝ թվարկումների նկարագրմամբ։ Դասից դուրս այդպիսի տիպերին դիմելու համար նրանց անվանը ավելացվում է կառուցվածքի կամ դասի անունը և երկու հատ երկու կետ՝struct S
{
typedef int** T;
T x;
};
S::T y;
void Print(int x);
void Print(double x);
void Print(int x, int y);
struct Date {int day, month, year;};
void operator ++(struct Date& date);
Օպերատորային ֆունկցիաները շատ բաներում նման են սովորական (ոչ օպերատորային) ֆունկցիաներին։ Բացառությամբ new
, new[]
, delete
և delete[]
օպերատորների, չի կարելի վերասահմանել ներկառուցված տիպերի պահվածքը (ասենք, վերասահմանել int տիպի արժեքների բազմապատկման օպերատորը)։ Չի կարելի ստեղծել նոր օպերատորներ, որոնք չկան C++–ում (ասենք, **
)։ Չի կարելի փոխել օպերատորների համար նախատեսված օպերանդների քանակը, ինչպես նաև չի կարելի փոխել օպերատորների գոյություն ունեցող առաջնահերթություններն ու ասոցիատիվությունը (ասենք, a+b*c
արտահայտության մեջ նախ պետք է կատարվի բազմապատկման գործողությունը, և հետո միայն գումարման, ինչ տիպի էլ որ լինեն a–ն, b–ն և c–ն)։ Կարելի է վերասահմանել []
(մեկ պարապետրով) և ()
(ցանկացած քանակությամբ պարամետրերով) գործողություները։
template
)։ Օրինակ, template<class T> T Min(T x, T y) {return x<y?x:y;}
կոդը հայտարարում է Min ֆունկցիան ցանկացած տիպի համար։ Կաղապարները կարող են տալ ոչ միայն ֆունկցիաներ, այլ նաև տիպեր։ Օրինակ, template<class T> struct Array{int len; T* val;};
կոդը հայտարարում է ցանկացած տիպի արժեքների զանգված, որից հետո մենք կարող ենք գրել Array<float> x;
malloc
և free
ֆունկցիաների, ներմուծված են նաև operator new
, operator new[]
, operator delete
և operator delete[]
օպերատորային ֆունկցիաները, ինչպես նաև new
, new[]
, delete
և delete[]
օպերատորները։ Եթե T–ն ցանկացած օբյեկտային տիպ է և չի հանդիսանում զանգվածի տիպ, tt>X–ը՝ ցանկացած օբյեկտային տիպ և A–ն՝ զանգվածի տիպ, որն ունի որոշակի n քանակությամբ տարր, որոնք ունեն X տիպ, ապա
new T
–ն հիշողություն է հատկացնում (operator new
ֆունկցիան կանչելու միջոցով), որն բավարար է Т տիպի մեկ արժեք տեղավորելու համար, հնարավոր է, այդ հիշողության մեջ ինիցիալիզացնում է օբյեկտը և վերադարձնում է Т*
տիպի ցուցիչ (օրինակ, Т* p = new T
)։new X[n]
–ն ու new A
–ն հիշողություն են հատկացնում (operator new[]
ֆունկցիան կանչելու միջոցով), որն բավարար է X տիպի n հատ օբյեկտ տեղավորելու համար, հնարավոր է, ինիցիալիզացնում է յուրաքանչյուր օբյեկտը այդ հիշողության մեջ, և վերադարձնում է X*
տիպի ցուցիչ (օրինակ, X* p = new X[n]
)։delete p
, հեռացնում է օբյեկտը (որը չի հանդիսանում զանգված), որին հղվում է p ցուցիչը, և ազատում է հիշողության այն հատվածը (operator delete
ֆունկցիայի կանչման միջոցով), որն հատկացված է նրա համար new արտահայտության կողմից։delete [] p
, հեռացնում է զանվածի բոլոր օբյեկտները, որին հղվում է p ցուցիչը, և ազատում է հիշողության այն հատվածը (operator delete[]
ֆունկցիայի կանչման միջոցով), որն հատկացված է այդ զանգվածին new արտահայտության կողմից։delete
գործողությունը ստուգում է, արդյո՞ք իր արգումենտը զրոյական ցուցիչ չէ, հակառակ դեպքում նա ոչինչ չի անում։ non-POD դասային տիպի օբյեկտ ինիցիալիզացնելու համար new արտահայտություւնը կանչում է կառուցողին։ Դասային տիպի օբյեկտի հեռացման համար delete արտահայտությունը կանչում է ապակառուցողին (տես՝ ներքևում)։
C++-ը, ի տարբերություն C լեզվի, ունի օբյեկտ կողմնորոշված հնարավորություններ։ Այն ունի դասեր, որոնք ապահովում են օբյեկտ կողմնորոշված ծրագրավորման երեք կարևոր հատկությունները՝ ինկապսուլյացիան, ժառանգությունը և պոլիմորֆիզմը։
C++-ի ստանդարտում դաս (class) ասելով հասկանում են օգտագործողի կողմից ստեղծված տիպ, որն հայտարարված է class
, struct
կամ union
բանալի բառերից մեկի օգնությամբ, կառույց (structure) ասելով հասկանում ենք դաս, որն հայտարարված է struct բանալի բառի օգնությամբ, և միացություն (union) ասելով հասկանում են դաս, որն հայտարարված է union բանալի բառի օգնությամբ։
Դասի մարմնում կարող ենք գրել միայն ֆունկցիայի անունը, կամ նկարագրել այն ամբողջությամբ (տես ներքևում տեղադրված Alloc
ֆունկցիայի օրինակը։ Այս դեպքում այն համարվում է ներկառուցվող (inline
))։
Ոչ ստատիկ ֆունկցիա-անդամները (և միայն նրանք) կարող են ունենալ const
նկարագրիչը՝
class Array
{
...
inline double operator[] (int n) const;
Այսպիսի ֆունկցիաները չեն կարող փոփոխել դասի դաշտերը (բացի այն դաշտերից, որոնք որոշված են որպես mutable
)։ Եթե նրանք փորձեն դա անել, կոմպիլյատորը կարտարծի սխալի մասն հաղորդագրություն։
C++-ում, երբ մի դաս ժառանգվում է մեկ այլ դասի կողմից, ապա վերջինս ժառանգում է իր ծնող-դասի իրականացումը։ Ժառանգորդ-դասը կարող է ավելացնել իր դաշտերն ու ֆունկցիաները, կամ փոխարինել հիմնական դասի ֆունկցիաները։ C++-ում թույլատրվում է բազմակի ժառանգումը։
Ժառանգորդի կառուցողը կանչում է հիմնական դասերի կառուցողներին, այնուհետև ոչ ստատիկ անդամ-տվյալների կառուցողներին, որոնք հանդիսանում են դասի օրինակներ։ Ապակառուցողը նույնը կատարում է հակառակ հերթականությամբ։
Ժառանգումը լինում է հրապարակային, պաշտպանված և փակ (այսինքն փակ տիպի)՝
Հիմնական դասի անդամի տեսակը/ժառանգման ռեժիմը | private-անդամ | protected-անդամ | public-անդամ |
---|---|---|---|
private-ժառանգում | անհասանելի է | private | private |
protected-ժառանգում | անհասանելի է | protected | protected |
public-ժառանգում | անհասանելի է | protected | public |
Կարելի է ասել, որ ժառանգորդը հիմնական դասի ընդլայնված տարբերակն է, այսինքն, եթե հիմնական դասի ժառանգումը բաց է, այն կարող ենք օգտագործել այնտեղ, որտեղ օգտագործվում է հիմնական դասը։ Հակառակը անել հնարավոր չէ։
C++-ի տիպերի համակարգի քերականությունը պոլիմորֆ չէ (ի տարբերություն ML-ի ժառանգորդների, այդ թվում C լեզվի հիբրիդների՝ BitC, Cyclone), սակայն կան պոլիմորֆ վարքն ապահովելու մի քանի եղանակներ։ Ամենից առաջ դա ժառանգման ժամանակ դասերի մեթոդների վերբեռնումն է՝ տվյալների աբստրակցիայի ապահովման օբյեկտ կողմնորոշված ծրագրավորման համար ավանդական դարձած եղականը։ Այնուհետև պարամետրիկ պոլիմորֆիզմի (C++-ի համայնքում սովորաբար անվանվող «ընհանրացված ծրագրավորման») համար կա իրականացման երկու եղանակ։ Առաջին եղանակը ժառանգված է C-ից։ Այն հիմնված է առանց տիպի ցուցչի օգտագործման և տիպի այլ տվյալներից կախված բերման վրա։ Սա C++-ում ավանդաբար համարվում է վտանգավոր եղանակ։ Երկրորդ եղանակը կաղապարների օգտագործումն է, սակայն, ի տարբերություն պարամետրիկ պոլիմորֆիզմի սովորական իրականացումների, C++-ում տեղի է ունենում վերբեռնված մոնոմորֆ ֆունկցիաների ընտանիքի ինքնուրույն գեներացիա, որն հիմնված է պոլիմորֆ որոշչի (կաղապարի)՝ համապատասխանաբար նրա օգտագործման կոնտեքսի վրա, այսինքն ելատեքստային կոդի մակարդակի պարամետրիկ պոլիմորֆիզմը թարգմանվում է մեքենայական մակարդակի իրավիճակայինի (ad hoc), ինչի համար C++-ն ենթարդկվում է քննադատությունների։ C++-ում կա նաև վերբեռնման երրորդ եղանակ՝ օպերատորների վերբեռնումը, որը դասերի ժառանգման հետ համադրված տալիս է էլ ավելի շատ հնարավորություններ կոդի ընթերցումն հեշտացնելու համար ի շնորհիվ, այսպես կոչված, «շարահյուսական շաքարի» ներմուծման։
Տվյալների աբստրակցիան ապահովելու համար անհրաժեշտ է կապել մի քանի դասեր ժառանգման հիերարխիայի մեջ և ֆունկցիաները նշանակել միանման սպեցիֆիկատորներով։ Օրինակ՝
class Figure
{
...
void Draw() const;
...
};
class Square: public Figure
{
...
void Draw() const;
...
};
class Circle: public Figure
{
...
void Draw() const;
...
};
class Window
{
...
void Draw() const;
...
};
class SquareWindow: public Window
{
...
void Draw() const;
...
};
class RoundWindow: public Window
{
...
void Draw() const;
...
};
Այս սահմանումների կոմպիլյացման արդյունքում ձևավորվում են վեց ֆունկցիաների մարմիններ։ Կոդում դրանք օգտագործվում են միանման․ ֆունկցիայի որոշակի օրինակի ընտրությունը կատարվում է կախված այն օբյեկտի օրինակի տիպից, որի համար կանչվում է ֆունկցիան։ Ֆունկցիաների վարքի համաձայնեցվածությունը պետք է ապահովի ծրագրավորողը։
Circle *c = new Circle(0,0,5);
Figure *f = c; // ճիշտ է․ Figure-ը Circle-ի հիմնական դասն է
c->Draw();
f->Draw(); // Ցուցիչները իրար հավասար են, սակայն f-ի և c-ի համար կկանչվեն տարբեր ֆունկցիաներ
SquareWindow *sw = new SquareWindow(0,0,5);
sw->Draw(); // օգտագործվում է նույնկերպ
f = sw; // սխալ է․ SquareWindow-ն չի մտնում Figure-ի ժառանգորդների ցանկում
Ինչպես երևում է, C++-ում պոլիմորֆիզմի այս տեսակի շրջանակը սահմանափակվում է ցուցակով տրված տիպերի նախագծման փուլում։ Այսպիսի պոլիմորֆիզմը լռելյան համարվում է ստատիկ, սակայն virtual
սպեցիֆիկատորի օգտագործման ժամանակ այն վերածվում է դինամիկի՝
class Figure
{
...
virtual void Draw() const;
...
};
class Square: public Figure
{
...
void Draw() const;
...
};
class Circle: public Figure
{
...
void Draw() const;
...
};
Figure* figures[10];
figures[0] = new Square(1, 2, 10);
figures[1] = new Circle(3, 5, 8);
...
for (int i = 0; i < 10; i++)
figures[i]->Draw();
Այս դեպքում զանգվածի յուրաքանչյուր տարրի համար կկանչվի Square::Draw()
-ն կամ Circle::Draw()
-ն, կախված մաևմնի տեսակից։
Մաքուր վիրտուլ ֆունկցիա են անվանում այն վիրտուալ ֆունկցիա-անդամը, որն մարմնի փոխարեն հայտարարված է = 0
սպեցիֆիկատորով՝
class Figure
{
...
virtual void Draw() const = 0;
);
Մաքուր վիրտուալ ֆունկցիան սահմանում չունի և չի կարող ուղղակիորեն կանչվել։ Այսպիսի ֆունկցիայի հայտարարման նպատակն է ստեղծել ընդհանուր հիմնական դասում սիգնատուր-նախատիպ, որն չունի սեփական սահմանում, բայց թույլ է տալիս ստեղծել այդպիսի սահմանումներ ժառանգորդ-դասերում և ցուցիչի միջոցով կանչել դրանք ընդհանուր հիմնական դասին։ Ֆունկցիա-անդամը հայտարարվում է մաքուր վիրտուալ այն ժամանակ, երբ նրա սահմանումը հիմնական դասի համար իմաստ չունի։ Այսպես, վերընշված օրինակում Figure հիմնական դասի համար Draw() ֆունկցիայի սահմանումը իմաստ չունի, քանի որ «մարմիններ» ընդհանրապես չեն ստացվում և դրանք հնարավոր չէ ցուցադրել, սակայն այսպիսի ֆունկցիայի սահմանումը անհրաժեշտ է, որպեսզի կարելի լինի ժառանգորդ-դասերում նրան վերասահմանել և այդ դասերի Draw մեթոդը կանչել Figure-ի ցուցչի միջոցով։ Հետևաբար, միանգամայն տրամաբանական է հայտարարել Figure.Draw()-ն որպես մաքուր վիրտուալ ֆունկցիա-անդամ։
C++-ում մաքուր վիրոտուալ ֆունկցիայի հասկացության հետ սերտորեն կապված է «աբստրակտ դաս» հասկացությունը։ Աբստրակտ դաս են անվանում այն դասը, որն ունի գոնե մեկ չվերասահմանված մաքուր վիրտուալ ֆունկցիա-անդամ։ Այսպիսի դասերի օրինակների ստեղծումը թույլատրված չէ։ Աբստրակտ դասերը կարող են օգտագործվել միայն ժառանգման ճանապարհով նոր դասերի ստեղծման համար։ Եթե աբստրակտ դասի ժառանգորդ-դասում ժառանգված բոլոր մաքուր վիրտուալ ֆունկցիաները վերասահմանված չեն, ապա այդպիսի դասը նույնպես հանդիսանում է աբստրակտ դաս և նրա վրա նույնպես տարածվում են նշված բոլոր սահմանափակումները։
Աբստրակտ դասերը հաճախ օգտագործվում են որպես միջերեսներ։ Ի տարբերություն այլ լեզուների միջերեսների, C++ լեզվի աբստրակտ դասերը կարող են ունենալ ոչ վիրտուալ ֆունկցիաներ և անդամ-տվյալներ։
C++-ում տեղեկատվության կազմակերպման հիմնական միջոց են համարվում դասերը։ Ի տարբերություն C լեզվի կառույցների (struct
), որոնք կարող են կազմված լինել միայն դաշտերից և դերդրվող տիպերից, C++-ի դասը (class
) կարող է կազմված լինել դաշտերից, ներդրված տիպերից և ֆունկցիա-անդամներից (member functions)։ C++-ում ինկապսուլյացիան իրականացվում է դասի անդամների հասանելիության մակարդակի նշման միջոցով։ Դրանք լինում են հրապարակային (բաց, public
), պաշտպանված (protected
) և սեփական (փակ, գաղտնի, private
)։ C++-ում կառույցները դասերից տարբերվում են միայն նրանով, որ դրանցում անդամները և հիմնական դասերը հրապարակային են, իսկ դասերում՝ սեփական։
Հասանելիություն | private | protected | public |
---|---|---|---|
Հենց դասը | այո | այո | այո |
Ընկերներ | այո | այո | այո |
Ժառանգորդներ | ոչ | այո | այո |
Դասից դուրս | ոչ | ոչ | այո |
Հասանելիության ստուգումը կատարվում է կոմպիլյացիայի ժամանակ, դասի ոչ հասանելի անդամին դիմելու փորձը կհանգեցնի կոմպիլյացիայի սխալի։
Դասի օրինակ, որն իրականացնում է միաչափ զանգված՝
class Array
{
public:
Array():
len(0),
val(NULL)
{}
Array(int _len):
len(_len)
{
val = new double[_len];
}
Array(const Array & a);
~Array()
{
Free();
}
inline const double & Elem(int i) const
{
return val[i];
}
inline void ChangeElem(int i, double x)
{
val[i] = x;
}
protected:
void Alloc(int _len)
{
if (len == 0)
Free();
len = _len;
val = new double[len];
}
void Free()
{
delete [] val;
len = 0;
}
int len;
double * val;
};
Այստեղ Array դասն ունի 2 հրապարակային ֆունկցիա-անդամներ, 2 պաշտպանված դաշտեր, 3 հրապարակային կառուցողներ և հրապարակային ապակառուցող։ inline
նկարագրիչը հուշում է կոմպիլյատորին, որ ֆունկցիան կանչելու փոխարեն անհրաժեշտ է այն ներկառուցել կանչելու վայրում, ինչի շնորհիվ հաճախ կարելի է հասնել մեծ արդյունավետության։
Ֆունկցիա-ընկերները այն ֆունկցիաներն են, որոնք չեն հանդիսանում ֆունկցիա-անդամներ, բայց, չնայած դրան, դասի պաշտպանված և փակ անդամները հասանելի են նրա համար։ Այս ֆունկցիաները դասի մարմնում պետք է հայտարարված լինեն friend
բանալի բառով։ Օրինակ՝
class Matrix {
...
friend Matrix Multiply(Matrix m1, Matrix m2);
...
};
Matrix Multiply(Matrix m1, Matrix m2) {
...
}
Այստեղ Multiply ֆունկցիան կարող է դիմել Matrix դասի ցանկացած դաշտի կամ ֆունկցիա-անդամի։
Որպես ընկեր կարող է հայտարարվել ինչպես ամբողջ դասը, այնպես էլ դասի ֆունկցիա-անդամը։ Եթե A դասը հայտարարված է B դասում որպես ընկեր, ապա A դասի բոլոր սեփական (չժառանգված) ֆունկցիա-անդամները կարող են դիմել B դասի ցանկացած անդամի։ Օրինակ՝
class Matrix {
...
friend class Vector::getNum( Matrix & ) ;
...
private:
int i;
};
...
class Vector
{
int GetNum( Matrix & m ){ return m.i;} // դիմում Matrix դասի տվյալների փակ անդամին
};
Դիմման օրինակ՝
void SomeFunction()
{
Matrix m;
Vector v;
int i = Vector::GetNum( m );
}
Չորս կարևոր սահմանափակումներ, որոնք գործում են C++-ում ընկերական «հարաբերությունների» վրա՝
Ընդհանուր առմամբ, այս կանոնը կարելի է ձևակերպել այսպես․ «Ընկերական հարաբերություն գոյություն ունի միայն այն դասերի (դասի կամ ֆունկցիայի) միջև, որոնց համար այն հստակ հայտարարված է կոդում և գործում է միայն այն ուղղությամբ, որով այն հայտարարված է»:
Ըստ C++-ի գործող ստանդարտի, ներդրված դասը շրջապատող դասի փակ անդամների հասանելիության իրավունք չունի և չի կարող հայտարարել նրան որպես իր ընկեր (վերջինս հետևում է ընկեր եզրի՝ որպես դասի ոչ անդամ սահմանումից)։ C++0x ապագա ստանդարտում այս սահմանափակումները կվերացվեն։ Այս հարցում VC++, GNU C++ և Comeau C++ կոմպիլյատորների վերջին տարբերակները նույնիսկ անջատված ընդլայնումներով հետևում են նոր կանոններին, որոնք ձևակերպված են C++0x-ի վերջին սևագրություններում միայն։
Դասերն միշտ ունեն հատուկ ֆունկցիաներ՝ Կոնստրուկտոր և դեստրուկտորներ, որոնք կարող են հայտարարվել բացահայտ կամ անբացահայտ։
Կոնստրուկտորը կանչվում է օբյեկտի (համապատասխան տիպի) ստեղծման ժամանակ՝ այն ինիցիալիզացնելու նպատակով, իսկ Դեստրուկտորը՝ օբյեկտի վերացման համար։ Մասնավորապես, Կոնստրուկտորը կարող է կանչվել՝ դասային տիպի փոխակերպումը կատարելու համար։
Կոնստրուկտորները նշանակվում են որպես դասի անունը կրող ֆունկցիաներ (օրինակ, Array::Array
)։ Դեստրուկտորը նույնպես կրում է դասի անունը, սակայն անունից առաջ դրվում է ~ նշանը (օրինակ, Array::~Array
)։ Կոնստրուկտորների և Դեստրուկտորների համար չի կարելի նշել վերադարձվող արժեքի տիպը։ Դեստրուկտորը չի կարող ընդունել արգումենտներ։ Դասը կարող է ունենալ մի քանի Կոնստրուկտորներ (տարբեր պարամետրերով), այդ թվում՝ կաղապարային, սակայն միայն մեկ՝ ոչ կաղապարային Դեստրուկտոր։
Այն Կոնստրուկտորը, որը չունի պարամետրեր կամ որի պարամետրերը ունեն լռելյան արգումենտներ, անվանում են լռելյան Կոնստրուկտոր։ Եթե ոչ կաղապարային Կոնստրուկտորը, որի առաջին պարամետրը հղում է իր դասին (օրինակ, Array::Array(const Array&)
), իսկ մնացած պարամետրերը (եթե այդպիսիք կան)՝ ոչ, և որը ունի լռելյան արգումենտներ, անվանում են պատճենման Կոնստրուկտոր։ Այն կանչվում է գոյություն ունեցող օբյեկտի պատճեն հանդիսացող նոր օբյեկտի ստեղծման ժամանակ՝
Array a(5); // կանչվում է Array::Array(int)
Array b; // կանչվում է Array::Array()
Array c(a); // կանչվում է Array::Array(const Array&)
Array d=a; // կանչվում է Array::Array(const Array&)
b=c; // կանչվում է = օպերատորը
// եթե այն որոշված չէ (ինչպես այս դեպքում), ապա կանչվում է կոմպիլյատորի կողմից գեներացված վերագրման օպերատորը, որը
// իրականացնում է հիմնական ենթաօբյեկտների պատճենում և ոչ ստատիկ անդամ-տվյալների տերնար պատճենում։
// որպես կանոն, պատճենի Կոնստրուկտորը և վերագրման օպերատորը վերաիմաստավորվում են զույգերով
Եթե դասում չկա Կոնստրուկտորների հստակ հայտարարում, դասն ունի առանց պարամետրերի ոչ հաստակ հայտարարված Կոնստրուկտոր, որն կառուցում է ծնող-դասերի ենթաօբյեկտները և ինիցիալիզացնում է դասի դաշտերը՝ կանչելով դրանց լռելյան Կոնստրուկտորները։ Եթե դասում չկա հստակ հայտարարված պատճենող Կոնստրուկտոր, ապա դասն ունի ոչ հստակ հայտարարված պատճենող Կոնստրուկտոր, որն կատարում է աղբյուր հանդիսացող օբյեկտի բոլոր հայտարարված դաշտերի ուղիղ պատճենում համապատասխանաբար ընդունող օբյեկտի դաշտեր համապատասխան պատճենող Կոնստրուկտորների օգնությամբ։ Եթե դասում չկա հստակ հայտարարված Դեստրուկտոր, ապա դասըն ունի սեփական ոչ հստակ հայտարարված Դեստրուկտորը։
C++-ում Կոնստրուկտորները չեն կարող հայտարարվել վիրտուալ, իսկ Դեստրուկտորները՝ կարող են, և սովորաբար այդպես էլ հայտարարվում են, որպեսզի ապահովվի հղումով կամ ցուցիչով հասանելի օբյեկտի ճիշտ ոչնչացումը՝ անկախ հղման կամ ցուցչի տիպից։
Ֆունկցիա-անդամները կարող են օպերատորներ լինել՝
class Array {
...
inline double& operator[] (int n) { return val[n]; }
Այնուհետև
Array a(10);
...
double b = a[5];
C++-ի ստանդարտ գրադարանը ներառում է որոշակի միջոցների հավաքածու, որոնք պետք է հասանելի լինեն լեզվի ցանկացած իրականացման մեջ, որպեսզի ծրագրավորողներին ապահովեն լեզվի ընձեռած հնարավորությունների հարմարավետ օգտագործումը և ստեղծեն այն հիմքը, որն անհրաժեշտ է ինչպես ամենալայն սպեկտրի կիրառական հավելվածների, այնպես էլ մասնագիտացված գրադարանների մշակման համար։ С++-ի ստանդարտ գրադարանը ներառում է C լեզվի ստանդարտ գրադարանի մի մասը։ C++-ի ստանդարտը նորմատիվ հղում է պարունակում C-ի 1990 թվականի ստանդարտին և ինքնուրույն չի սահմանում ստանդարտ գրադարանի այն ֆունկցիաները, որոնք վերցված են C-ի ստանդարտ գրադարանից։
C++ լեզվի ստանդարտ գրադարանի հնարավորությունների հասանելիությունը ապահովվում է ծրագրում համապատասխան ստանդարտ գլխագիր ֆայլերի միացմամբ (#include
դիրեկտիվի օգնությամբ)։ C++11 ստանդարտում սահմանված ընդամենը 79 այդպիսի ֆայլ։ Ստանդարտ գրադարանի միջոցները հայտարարված են որպես std
անվանատարածք մտնող։ Այն գլխագիր ֆայլերը, որոնց անունները համապատասխանում են «cX» կաղապարին, որտեղ X-ը՝ C լեզվի ստանդարտ գրադարանի գլխագիր ֆայլի անվանումն է՝ առանց ընդլայնման (cstdlib, cstring, cstdio և այլն), պարունակում են սահմանումներ, որոնք համապատասխանում են C լեզվի ստանդարտ գրադարանի տվյալ հատվածին։ Միևնույն ժամանակ ծրագրավորողը կարող է օգտվել այնպիսի գլխագիր ֆայլերից, որոնց անվանումը համապատասխանում է «cX.h» կաղապարին (ավելացված է C-ի գլխագիր ֆայլերի «.h» ստանդարտ ընդլայնումը), որոնց մեջ նույն միջոցները սահմանված են որպես գլոբալ անվանատարածքին վերաբերող։
Ստանդարտ գրադարանի հետևյալ ֆունկցիաների օգտագործման համար որևէ գլխագիր ֆայլեր միացնել հակավոր չէ․
void* operator new(std::size_t) throw(std::bad_alloc);
void* operator new[](std::size_t) throw(std::bad_alloc);
void operator delete(void*) throw();
void operator delete[](void*) throw();
Ստանդարտ գրադարանը ներառում է հետևյալ բաժինները՝
Կոնտեյներները, տողերը, ալգորիթմները, իտերատորները և հիմնական օժանդակ ծրագրերը, բացառությամբ C-ի գրադարանից վերցվածների, միասին անվանում են STL (Stanard Template Library, ստանդարտ կաղապարային գրադարան)։ Ի սկզբանե այս գրադարանը առանձին է եղել և նրա հապավումը այլ ձևով էր ընդլայնվում, սակայն հետագայում այն մտավ C++-ի ստանդարտ գրադարանի մեջ՝ որպես նրա անբաժաների մաս։ Անվան մեջ արտացոլված է այն, որ ընդհանուր տեսքի միջոցների (կոնտեյներների, տողերի, ալգորիթմների) իրականացման համար օգտագործված են ընդհանրացված ծրագրավորման մեխանիզմները (C++-ի կաղապարները՝ template)։ Ստրաուստրուպի աշխատանքներում մանրամասն նկարագրված են այն պատճառները, որոնց համար հենց այդպիսի ընտրություն է կատարվել։ Հիմնական պատճառը ընտրված լուծման մեծ ունիվերսալությունն է (կաղապարային կոնտեյներները, ի տարբերություն օբյեկտայինների, կարող են հեշտությամբ օգտագործվել ոչ օբյեկտային տիպերի համար և չեն պահանջում այդ տարրերի ընդհանուր նախնիի առկայությունը) և նրա տեխնիկական արդյունավետությունը (որպես կանոն, կաղապարային կոնտեյների գործողությունները չեն պահանջում վիրտուալ ֆունկցիաների կանչեր և կարող են հեշտությամբ ներկառուցվել (inline), ինչն արդյունքում տալիս է այնպիսի արդյունավետ կոդ, ինչպիսին կլիներ ձեռքով կոդավորման ժամանակ)։
STL-ը, մինչև C++-ի ստանդարտին միանալը, իրենից ներկայացրել է երկրորդական մշակում, սկզբում HP ընկերության, այնուհետև՝ SGI: Լեզվի ստանդարտը այն «STL» չի անվանում, քանի որ այդ գրադարանը դարձել է լեզվի անբաժանելի մասը, սակայն շատերը մինչև այսօր էլ օգտագործում են այդ անվանումը, որպեսզի այն տարբերեն ստանդարտ գրադարանի մնացած մասին (մուտքի-ելքի հոսքերը (iostream), C-ի ենթաբաժինը և այլն)։
STLport անվանումով նախագիծը[10], որն հիմնված է SGI STL-ի վրա, իրականացնում է STL-ի, IOstream-ի և տողային դասերի մշտական թարմացումը։ Որոշ այլ նախագծեր նույնպես զբաղվում են ստանդարտ գրադարանի մասնավոր կիրառումների մշակմամբ։
C++ լեզվի նոր հնարավորությունները, որոնք բացակայում էին C լեզվում՝
C++-ի նոր հնարավորությունները ներառում են արտահայտությունների տեսքով հայտարարությունները, ֆունկցիաների տեսքով տիպերի փոխարկումները, new
և delete
օպերատորները, bool
տիպը, հղումները, հաստատունության ընհանրացված հասկացությունը, inline-ֆունկցիաները, լռելյան արգումենտները, վերասահմանումները, անվանատարածքները, դասերը (այդ թվում և դասերի հետ կապված բոլոր հնարավորությունները, ինչպիսիք են ժառանգումը, ֆունկցիա-անդամները, վիրտուալ ֆունկցիաները, աբստրակտ ֆունկցիաները և կառուցողները), օպերատորների վերասահմանումները, կաղապարները, ::
օպերատորը, բացառությունների մշակումը, դինամիկ նույնականացումը և այլ հնարավորություններ։ C++ լեզուն շատ դեպքերում նաև ավելի խիստ է վերաբերվում տիպերի ստուգմանը, քան C-ն։
C++-ում նոր մեկնաբանություններ են հայտնվել երկու գծերի տեսքով (//
), որոնք եղել են C-ի նախորդի մոտ՝ BCPL լեզվում։
C++ լեզվի որոշ առանձնահատկություններ ավելի ուշ տեղափոխվել են C լեզու, օրինակ, const
և inline
բանալի բառերը, for
ցիկլերում հայտարարումը և C++-ի ոճով մեկնաբանությունները (//
)։ Ավելի C-ի հետագա իրականացումներում ներկայացված էին նաև այնպիսի հնարավորություններ, որոնք չկան C++-ում, օրինակ va_arg
մակրոսները և զանգված-պարամետրերի հետ բարելավված աշխատանքը։
Չնայած նրան, որ C լեզվով գրված կոդի մեծ մասը կաշխատի նաև C++-ում, վերջինս իր մեջ չի ներառում C լեզուն։ Գոյություն ունի նաև C լեզվի համար աշխատող այնպիսի կոդ, որը չի աշխատում C++-ում։ Սա է C++-ի տարբերությունը Objective C-ից՝ C լեզվի օբյեկտ կողմնորոշված ծրագրավորման ևս մեկ բարելավում, որն հենց ամբողջությամբ ներառում է C լեզուն։
Գոյություն ունեն նաև ուրիշ տարբերություններ։ Օրինակ, C++-ը չի թույլատրում կանչել main()
ֆունկցիան ծրագրի ներսում, այն ժամանակ, երբ C-ում այդ գործողությունը թույլատրվում է։ Բացի այդ, C++-ն որոշ հարցերում ավելի խիստ է․ օրինակ, այն չի թույլատրում դեռևս չհայտարարված ֆունկցիաների օգատգործումը։
Ավելին, կոդը, որը ճիշտ է երկու լեզուների համար էլ, կարող է տալ տարբեր արդյունքներ, կախված, թե որ լեզվի կոմպիլյատորով է այն կոմպիլյացված։ Օրինակ, հարթակների մեծամասնությունում ստորև բերված ծրագիրը տպում է «C», եթե կոմպիլյացվում է C-ի կոմպիլյատորով, և «C++»՝ C++-ի կոմպիլյատորով։ Այսպես տեղի է ունենում այն պատճառով, որ C-ում սիմվոլային հաստատունները (օրինակ, 'a'
-ն) ունեն int
տիպ, իսկ C++-ում՝ char
տիպ, իսկ այդ տիպերի չափսերը սովորաբար տարբերվում են միմյանցից։
#include <stdio.h>
int main()
{
printf("%s\n", (sizeof('a') == sizeof(char)) ? "C++": "C");
return 0;
}
Ստորև ներկայացված են C++ ծրագրավորման լեզվով գրված ծրագրերի կոդեր՝ իրենց բացատրություններով։
Սա մի ծրագրի օրինակ է, որը ոչինչ չի անում։ Այն սկսում է կատարվել և անմիջապես դադարեցնում է աշխատանքը։ Այն կազմված է հիմնական հոսքից՝ main()
ֆունկցիայից, որն հանդիսանում է C++ ծրագրի կատարման սկզբնական կետ։
int main()
{
return 0;
}
C++–ի ստանդարտը պահանջում է, որ main()
ֆունկցիան վերադարձնի int
տիպ։ Այն ծրագիրը, որի main()
ֆունկցիան վերադարձնում է այլ տիպի արժեք, չի համապատասխանում C++–ի ստանդարտին։
Ստանդարտը չի ասում, թե ինչ է իրականում նշանակում main()
ֆունկցիայի վերադարձվող արժեք ասվածը։ Ավանդաբար համարում են, որ այն վերադարձնում է ծրագրի կոդը։ Ստանդարտն երաշխավորում է, որ եթե main()
ֆունկցիան վերադարձնում է 0 արժեք, ապա ծրագրի կատարումն ավարտվել է հաջողությամբ։
C++–ով գրված ծրագրի աշխատանքի սխալով ավարտումը ավանդաբար նշանակում է ոչ զրոյական արժեքի վերադարձ։
Այս ծրագիրը նույնպես ոչինչ չի անում, բայց ավելի հակիրճ է։
int main(){}
C++–ում (ինչպես և C–ում), եթե ծրագրի կատարումը հասնում է main()
ֆունկցիայի ավարտին, ապա այն համարժեք է return 0;
–ին։ Դա ճիշտ է միայն main()
ֆունկցիայի համար։
Սա Hello, world! ծրագրի օրինակ է, որն արտարծում է հաղորդագրություն՝ օգտագործելով ստանդարտ գրադարանը, և ավարտում է աշխատանքը։
// սա միացնում է iostream գլխագիր ֆայլը
#include <iostream>
using namespace std;
int main()
{
cout << "Hello, world!" << endl; // endl–ի փոխարեն կարելի է գրել նաև "...\n"
return 0;
}
Ժամանակակից C++ –ը թույլ է տալիս պարզ եղանակով լուծել ավելի բարդ խնդիրներ։ Այս օրինակը, ամեն ինչից զատ, ցուցադրում է կաղապարների ստանդարտ գրադարանի (STL) կոնտեյներների օգտագործումը։
#include <iostream> // std::cout–ի օգտագործման համար
#include <vector> // std::vector<>–ի համար
#include <map> // std::map<>–ի և std::pair<>–ի համար
#include <algorithm> // std::for_each()–ի համար
#include <string> // std::string–ի համար
using namespace std; // օգտագործում ենք "std" անվանատարածքը
void display_item_count(pair < string const, vector<string> > const& person)
{
// person–ը երկու օբյեկտների զույգ է՝ person.first–ը նրա անունն է,
// person.second–ը՝ նրա առարկաների քանակը (տողերի վեկտոր)
cout << person.first << " is carrying " << person.second.size() << " items" << endl;
}
int main()
{
// Հայտարարում ենք տողային բանալիներով և վեկտորային տողերի տեսքի տվյալներով քարտեզը
map< string, vector<string> > items;
// Ավելացնում ենք այդ քարտեզում մի քանի անձի և տալիս ենք նրանց մի քանի առարկաներ
items["Ani"].push_back("scarf");
items["Davit"].push_back("tickets");
items["Ani"].push_back("puppy");
// Կրկնում ենք բոլոր օբյեկտներն կոնտեյներում
for_each(items.begin(), items.end(), display_item_count);
}
Այս օրինակում պարզության համար օգտագործվում է անվանատարածքի օգտագործման դիրեկտիվ։ Իրական ծրագրում հաճախ խորհուրդ է տրվում օգտագործել հայտարարություններ, որոնք դիրեկտիվներից ավելի կոկիկ են՝
#include <vector>
int main()
{
using std::vector;
vector<int> my_vector;
}
Այստեղ դիրեկտիվը տեղադրված է ֆունկցիայի հատվածում, ինչը նվազեցնում է անունների միջև հնարավոր անհամաձայնությունները (ինչն էլ հենց պատճառ է հանդիսացել ծրագրավորման լեզուներում անվանատարածքների ներմուծման)։ Այնպիսի հայտարարությունների օգտագործումը, որոնք միավորում են տարբեր անվանատարածքներ մեկի մեջ, հակասում է անվանատարածքների օգտագործման հասկացությանը։
boost հանրահայտ գրադարանները լեզվի ստանդարտ միջոցների հետ համադրությամբ թույլ են տալիս շատ հակիրճ և ընկալելի գրել կոդը։ Ստորև բերված օրինակում հաշվվում է կենտ թվերի և իրենց քառակուսիների վեկտորների սկալյար արտադրյալը։ Կոդում արժեքները վեկտորները տրված են ծույլ STL–անման հաջորդականություններով։
#include <iostream>
#include <numeric>
#include <boost/iterator/counting_iterator.hpp>
#include <boost/iterator/transform_iterator.hpp>
int odd(int i)
{
return 2 * i + 1;
}
int square(int i)
{
return i * i;
}
typedef boost::counting_iterator <int> counter;
typedef boost::transform_iterator <int (*)(int), counter> transformer;
transformer odds(int n)
{
return transformer(counter(n), odd);
}
transformer squares(int n)
{
return transformer(counter(n), square);
}
int main()
{
using namespace std;
cout << "Enter vector length: ";
int n; cin >> n;
cout << inner_product( odds(0), odds(n), squares(0), 0 ) << endl;
}
Այս օրինակը ցուցադրում է կոդի գրառման, այսպես կոչված, «հարթ» ոճը։ Այս անվանումը կապված է այն բանի հետ, որ STL ալգորիթմները թույլ են տալիս գրառել կոդն առանց ցիկլերի, հետևաբար տողասկզբի հեռավորության երկարությունը ձևավորված կոդում համարյա թե հաստատուն է։ Այսպիսի մոտեցման կողմնակիցները համարում են, որ C++–ի ստանդարտ գրադարանին ծանոթ ծրագրավորողին բավական է միայն inner_product()
–ի կանչով տողեր, որպեսզի նա հասկանա, ինչ է անում ծրագիրը։ Ըստ այս տեսակետի, inner_product
–ի կանչը նման է առաջադրանքի բառացի նկարագրմանը… «հաշվել կենտ թվերի և իրենց քառակուսիների վեկտորների սկալյար արտադրյալը զրոյից n արժեքների համար»։
Seamless Wikipedia browsing. On steroids.
Every time you click a link to Wikipedia, Wiktionary or Wikiquote in your browser's search results, it will show the modern Wikiwand interface.
Wikiwand extension is a five stars, simple, with minimum permission required to keep your browsing private, safe and transparent.