Սկիզբ » Ուսումնական նյութեր » Ծրագրավորում » Ծրագրավորման լեզուներ » C և C++ » C++։ Մի քանի հարցեր և պատասխաններ։ Մաս 1։

C++։ Մի քանի հարցեր և պատասխաններ։ Մաս 1։

| Ապրիլ 1, 2013 | 1 Մեկնաբանություն |

1.  Որո՞նք են օբյեկտակողմնորոշված ծրագրավորման հիմնական բաղկացուցիչները

Օբյեկտակողմնորոշված ծրագրավորման հիմնական բաղկացուցիչներն են․

1. Ինկափսուլյացիա,

2. Պոլիմորֆիզմ,

3. Ժառանգականություն։

Ինկափսուլյացիան ծրագրավորման լեզվի հատկություն է, որը թույլ է տալիս միավորել և պաշտպանել տվյալներն ու կոդը օբյեկտի միջոցով և թաքցնել օբյեկտի իրականացումը օգտագործողից։ Այս դեպքում օգտագործողի համար կարևոր չէ, թե ինչպես է իրականացված տվյալ օբյեկտը ներսից։ Օգտագործողին տրամադրվում է ինտերֆեյս, որի միջոցով էլ նա փոխազդում է օբյեկտի և դրա բաղադրիչների հետ,

Պոլիմորֆիզմը ծրագրավորման լեզվի հատկություն է, որը թույլ է տալիս միևնույն հայտարարությամբ օբյեկտներին ունենալ տարբեր իրականացումներ։ Ծրագրավորման լեզուն ապահովում է պոլիմորֆիզմ, այն դեպքում, երբ միևնույն հայտարարությամբ դասերը (class) և ֆունկցիաները կարող են ունենալ տարբեր իրականացումներ։ Պոլիմորֆիզմի իմաստը կարելի է բնորոշել հետևյալ արտահայտությամբ «մեկ ինտերֆեյս, տարբեր իրականացումներ»։ Պոլիմորֆիզմը թույլ է տալիս գրել ավելի աբստրակտ կոդ և բարձրացնում է կոդի կրկին օգտագործման արդյունավետության գործակիցը,

Ժառանգականություն ծրագրավորման լեզվի հատկություն է, որը թույլ է տալիս սահմանել և նկարագրել նոր՝ ածանցյալ դաս, հին՝ բազային դասի հիման վրա։ Միևնույն ժամանակ բազային դասից վերառվում են ածանցյալ դասի հատկությունները։ Այլ կերպ ասած ածանցյալ դասը, այս կամ այն չափով իրականացվում է բազային դասի սահմանման հիման վրա։ Դա թույլ է տալիս ցանկացած ժառանգորդ դասի օբյեկտի հետ վարվել այնպես, ինչպես կարելի էր վարվել բազային դասի օբյեկտների հետ։ Ինչպես արդեն կարելի էր հասկանալ, դասը, որից ժառանգում են, հանդիսանում է բազային, իսկ ժառանգորդ դասը՝ ածանցյալ։ Որոշ ծրագրավորման լեզուներում, այնպիսիք, ինչիսիք են C++  -ը և  java -ն կարելի է ստեղծել աբստրակտ դասեր և ժառանգել դրանցից։ C++ -ում աբստրակտ են համարվում այն դասերը, որոնք ունեն գոնե մեկ մաքուր վիրտուալ ֆունկցիա։ Աբստրակտ դասերը ունեն անդամ ֆունկցիաներ և փոփոխականներ, բայց դրանցից չի կարելի ստեղծել օբյեկտներ և օգտագործել դրանք։ Այլ կերպ ասած աբստրակտ դասերը իրենցից ներկայացնում են  ինտերֆեյսներ և նախատեսված են միայն ժառանգման համար։

2. Ինչպե՞ս ստեծել հղումային փոփոխական

Հղումային փոփոխականը իրենից ներկայացնում է այլ փոփոխականի մեկ այլ անուն։ Հղումային փոփոխական կարելի ստեղծել հետևյալ կերպ․

int i = 10;
int& iRef = i;

Այստեղ i փոփոխականին կարելի է դիմել նաև iRef -անունով։ iRef փոփախականին ցանկացած վերագրում կբերի նաև i փոփոխականի արժեքի փոփոխմանը։ Չի կարելի ստեղծել ոչ դասի անդամ հղումային փոփոխական՝ առանց նախնական սկզբնարժեքավորման, օրինակ այս կոդը չի կոմպիլացվի․

int& iRef; //չի կոմպիլացվի

Դասի անդամ հղումային փոփոխականները կարելի է հայտարարել դասում առանց սկզբնարժեքավորման և հետո սկզբնարժեքավորել դասի կոնստրուկտորի սկզբնարժեքավորման ցուցակում։

3. Կարելի է արդյոք ստեղծել հղումային փոփոխական հաստատունի վրա․

Չի կարելի ստեղծել հղումային փոփոխական հաստատունի վրա․ հետևյալ կոդը չի կոմպիլացվի

int& iRef = 5; //չի կոմպիլացվի

Սակայն օգտագործելով const- ը կարելի է դա անել․

const int& iRef = 5; // նորմալ կկոմպիլացվի

4. Կկոմպիլացվի արդյոք հետևյալ կոդը․

int i = 5;
int j = 10;
int& iRef = i;
iRef=&j;

Ոչ չի կոմպիլացվի, քանի որ j փոփոխականի հասցեն իրենից ներկայացնում է ցուցիչ, իսկ iRef -ը հղում է int փոփոխականի վրա, այլ ոչ թե ցուցիչ։

5. Ո՞ր փոփոխականի վրա ցույց կտա iRef փոփոխականը վերագրումից հետո

int i = 5;
int j = 10;
int& iRef = i;
iRef=j;

iRef -ը կշարունակի ցույց տալ i փոփոխականի վրա, ուղղակի վերջին վերագրման արդյունքում կփոխվի i-ի արժեքը և կդառնա 10։

6. Կարելի է արդյոք ունենալ ցուցիչ հղման վրա

Ոչ չի կարելի, հղման վրա ցուցիչ պարունակող կոդը չի կոմպիլացվի

int x;
int& iRef = x;
int&* iRefOther = &iRef; // չի կոմպիլացվի

Չի կոմպիլացվի նաև հղման վրա հղում պարունակող կոդը․

int x;

int& iRef = x;
int&& iRefOther = iRef; // չի կոմպիլացվի

7. Հիշողության ո՞ր տիրույթում տեղ կհատկացվի դասի օբյեկտի համար

class base
{
   public:
          base();
   ...........
   ...........
};

int main()
{
   base b;
   return 0;
}
base b;

կերպով ստեղծվող օբյեկտի համար հիշողություն կհատկացվի stack -ից։

8. Հիշողության ո՞ր տիրույթում տեղ կհատկացվի դասի օբյեկտի համար

class base
{
   public:
          base();
   ...........
   ...........
};

int main()
{
   base* b = new base();
   ..............
   return 0;
}
base* b = new base();

կերպով ստեղծվող օբյեկտի համար հիշողություն կհատկացվի heep -ից։

9. Կկոմպիլացվի արդյոք կոդը, եթե մի կոնստրուկտորի մարմնից կանչենք մյուսը

class base
{
   public:
          base(int n);
          base(std::string s);
   ...........
   ...........
};
................
................

base::base(int n)
{
   ................
   ................
   std::string s(" ..... ");
   base(s);
};

Կոդը հաջող կկոմպիլացվի, ուղղակի դա չի ունենա սպասվող արդյունքը։ Իսկ տեղի կունենա այն, որ կստեղծվի base տիպի ժամանակավոր, անանուն օբյեկտ և այդ օբյեկտի համար բացահայտ ձևով կանչվող կոնստրուկտորում տեղի կունենան ինչ-որ սկզբնարժեքավորումներ, բայց որոնք ոչ մի առնչություն չեն ունենա մեր օբյեկտի հետ։

10. Կարելի է արդյոք հետևյալ կերպով ստեղծել օբյեկտ

class base
{
   public:
          base();
          void set_data(int data);
   ...........
   ...........
};

int main()
{
   base b();
//   b.set_data(5);

   return 0;
}

Զարմանալի է, բայց շատ էլ նորմալ կկոմպիլացվի, բայց մեկնաբանությունը բացելուց հետո (b.set_data(5);) արդեն չի կոմպիլացվի։ Պատճառն այն է, որ երբ գրում ենք base b(); կոմպիլյատորը դա հասկանում է, որպես base տիպի b() ֆունկցիայի հայտարարում և ամեն ինչ նորմալ կոմպիլացվում է, իսկ երբ բացում են b.set_data(5); կոմպիլյատորը դա ընկալում է որպես ֆունկցիայի անվան օգտագործում օբյեկտի փոխարեն և չի կոմպիլացնում կոդը։

11. Եթե դասում սահմանված չէ լռությամբ կոնստրուկտոր, փոխարենը սահմանված են պարամետրերով մի քանի կոնստրուկտորներ, կարո՞ղ ենք ստեղծել օբյեկտ առանց պարամետրերի

Ոչ չենք կարող, քանի որ առանց պարամետրերի օբյեկտ կարող ենք ստեղծել միայն այն դեպքում, երբ ունենք լռությամբ՝ առանց պարամետրերի կոնստրուկտոր։ Իսկ քանի որ ունենք պարամետրերով կոնստրուկտորներ, կոմպիլյատորը մեր փոխարեն չի գեներացի լռությամբ կոնստրուկտոր։

12. Կարելի է արդյոք ստեղծել օբյեկտների զանգված չունենալով լռությամբ կոնստրուկտոր

Ոչ չի կարելի։ Պատճառն է, որ երբ ստեղծում ենք օբյեկտների զանգված, դրանց համար հատկցվում է հիշողության անընդհատ տիրույթ և յուրաքանչյուր օբյեկտի համար առանձին կանչվում է լռությամբ կոնստրուկտորը։ C++ -ում նախտեսված չէ միջոց, որը թույլ կտա օբյեկտների զանգված ստեղծելիս նշել, թե որ կոնստրուկտորն է պետք կանչել։

Հետևաբար՝

base b[3]; //չի կոմպիլացվի
base* b = new base[3]; // նույնպես չի կոմպիլացվի

13. Ի՞նչ կգեներացվի կոմպիլյատորի կողմից, եթե ստեղծենք դատարկ դաս

Կգեներացվի լռությամբ կոնստրուկտոր, պատճենման կոնստրուկտոր, վերագրման օպերատոր և դեստրուկտոր։

14. Կկանչվեն արդյոք պատճենման կոնստրուկտորը և վերագրման օպերատորը բերված կոդում, եթե այո, ապա ինչ հաջորդականությամբ

class base
{
   public:
         base(int n);
   ..........        
   ..........        
   ..........        
   std::string get_string();
};

std::string base::get_string()
{
   return m_string;
}

int main()
{
   base b(5);   
   std::string s = b.get_string();   
   ................................
   ................................
   ................................
   return 0;
}

C++ օբյեկտի հայտարարումը իրենից ներկայացնում է գործողություն, քանի որ հենց այդ ժամանակ է կատարվում օբյեկտի սկզբնարժեքավորումը (կանչվում են համապատասխան կոնստրուկտորները)։

Պատճենման կանստրուկտորը կանչվում է միայն օբյեկտի հայտարարման ժամանակ, օրինակ երբ գրում ենք

base b1(5);
base b2(b1);

կամ

base b1(5);
base b2 = b1;

ապա 2 դեպքում էլ կանչվում  է պատճենման կոնստրուկտորը, իսկ երբ գրում ենք

base b1(5);
base b2;
b2 = b1;

կանչվում է վերագրման օպերատորը, քանի որ օբյեկտի հայտատրարումն ու վերագրումը տարբեր տողերում (միմյանց հաջորդող տարբեր հրամաններով) են տրված։

Իսկ քանի որ string-ը պարզ տիպ չէ այլ օբյեկտային, get_string() ֆունկցիայիում return m_string; -ի ժամանակ կստեղծվի ժամանակավոր օբյեկտ և դրա սկզբնարժեքավորման համար կկանչվի պատճենման կոնստրուկտորը և հաշվի առնելով այն, որ main() -ում string տիպի օբյեկտը հայտարարվել և արժեքավորվել է նույն տողում (այսինքն այս դեպքում նույնպես կանչվել է պատճենման կոնստրուկտորը), ապա գրված կոդի դեպքում 2 անգամն էլ կկանչվեն պատճենման կոնստրուկտորները։

15. Կկանչվեն արդյոք պատճենման կոնստրուկտորը և վերագրման օպերատորը բերված կոդում, եթե այո, ապա ինչ հաջորդականությամբ

class base
{
   public:
         base(int n);
   ..........        
   ..........        
   ..........        
   std::string get_string();
};

std::string base::get_string()
{
   return m_string;
}

int main()
{
   base b(5);   
   std::string s;
   s = b.get_string();   
   ................................
   ................................
   ................................
   return 0;
}

C++ օբյեկտի հայտարարումը իրենից ներկայացնում է գործողություն, քանի որ հենց այդ ժամանակ է կատարվում օբյեկտի սկզբնարժեքավորումը (կանչվում են համապատասխան կոնստրուկտորները)։

Պատճենման կանստրուկտորը կանչվում է միայն օբյեկտի հայտարարման ժամանակ, օրինակ երբ գրում ենք

base b1(5);
base b2(b1);

կամ

base b1(5);
base b2 = b1;

ապա 2 դեպքում էլ կանչվում  է պատճենման կոնստրուկտորը, իսկ երբ գրում ենք

base b1(5);
base b2;
b2 = b1;

կանչվում է վերագրման օպերատորը, քանի որ օբյեկտի հայտատրարումն ու վերագրումը տարբեր տողերում (միմյանց հաջորդող տարբեր հրամաններով) են տրված։

Իսկ քանի որ string-ը պարզ տիպ չէ այլ օբյեկտային, get_string() ֆունկցիայիում return m_string; -ի ժամանակ կստեղծվի ժամանակավոր օբյեկտ և դրա սկզբնարժեքավորման համար կկանչվի պատճենման կոնստրուկտորը և հաշվի առնելով այն, որ main() -ում string տիպի օբյեկտը հայտարարվել  և արժեքավորվել է տարբեր տողերում (այսինքն այս դեպքում նույնպես կանչվել է վերագրման օպերատորը), ապա գրված կոդի դեպքում 2 անգամն էլ կկանչվեն պատճենման կոնստրուկտորները։

16. Ինչպե՞ս կանխել դասերում ոչ բացահայտ ձևափոխությունները

Հաճախ դասերում պարամետրերով կոնստրուկտորները հանդիսանում են ոչ բացահայտ ձևափոխությունների պատճառ, օրինակ մենք կարող ենք ինչ որ դասի տիպի օբյեկտին վերագրել այլ՝ պարզ տիպի փոփոխական կամ դասի տիպի օբյեկտի նկատմամբ կիրառել թվաբանական գործողություններ՝ օգտագոծելով թվաբանական նշանի մյուս հատվածում այլ պարզ տիպ։ Նման ոչ բացահայտ ձևափոխությունները կանխելու նպատակով օգտագործվում է explicit ծառայողական բառը։ Օրինակ՝

#include <iostream>

class base
{
	int m_data;

	public:
		/*explicit*/ base(int d);
};

int main()
{
	base ob = 5;
	return 0;
}

Երբ explicit ծառայողական բառը չկա, մենք հանգիստ կարող ենք օբյեկտ տիպի փոփոխականին վերագրել ոչ օբյեկտային՝ պարզ տիպի փոփոխական (base ob = 5;) : Բայց, երբ explicit ծառայողական բառը կա այս կոդը արդեն չի կոմպիլացվի։

C++։ Մի քանի հարցեր և պատասխաններ։ Մաս 1։, 9.9 out of 10 based on 24 ratings

Նշագրեր: , , , , , , ,

Բաժին: C և C++, Ծրագրավորման լեզուներ

Կիսվել , տարածել , պահպանել

VN:F [1.9.20_1166]
Rating: 9.9/10 (24 votes cast)

Մեկնաբանություններ (1)

Թրեքբեք հղում | Մեկնաբանությունների RSS ժապավեն

  1. Նելլի

    Որո՞նք են C++ լեզվի հղումները:

Մեկնաբանեք

Կհաստատվեն միայն մեսրոպատառ հայերենով գրած մեկնաբանությունները

225