Dasturlash Asoslari: M. A. Bobojonova
Dasturlash Asoslari: M. A. Bobojonova
Bobojonova
DASTURLASH ASOSLARI
(Birinchi qism)
Darslik
M. A. Bobojonova
“KAMOLOT” nashriyoti
Buxoro-2023
UO‘K: 004.424
KBK: 32.973
B69
Taqrizchilar:
F.A.Muradov - Raqamli texnologiyalar va sun`iy intellektni
rivojlantirish ilmiy-tadqiqot instituti katta ilmiy xodimi, texnika fanlari
bo‘yicha falsafa doktori;
T.R.Shafiyev - Buxoro davlat universiteti “Axborot tizimlari va
raqamli texnologiyalar” kafedrasi mudiri, PhD, dotsent.
ISBN: 978-9910-734-38-0
© “KAMOLOT” nashriyoti
© Bobojonova Madina Abduahat qizi
2
АННОТАЦИЯ
ANNOTATION
3
MUNDARIJA:
4
16-MAVZU. SINFLAR VA OBYEKTLAR 193
17-MAVZU. C++ DA MODIFIKATOR BILAN ISHLASH 221
GLOSSARIY 368
XULOSA 372
FOYDALANILGAN ADABIYOTLAR RO‘YXATI 374
5
1-MAVZU. KIRISH. ALGORITM TUSHUNCHASI VA
TASVIRLASH USULLARI
Algoritm tushunchasi va tasvirlash usullari
Dasturlash tillari tarixi
C++ dasturlash tiliga ekskursiya
C++dasturini ishlab chiqarish bosqichlari qanday?
C++tilida birinchi dasturni yozish va kompilyatsiya qilish
6
3-masala: Sonning faktorialini toping.
1-qadam: Boshlash
2-qadam: n, faktorial va i o'zgaruvchilarni e'lon qiling.
3-qadam: o'zgaruvchilarni ishga tushiring
faktorial ← 1
i←1
4-qadam: n qiymatini o‘qish
5-qadam: i = n ga qadar amallarni takrorlang
5.1: faktorial ← faktorial*i
5.2: i ← i+1
6-qadam: faktorialni ko'rsating
7-qadam: To'xtating
7
II. Algoritmni formulalar yordamida ifodalanishi
Algoritmni formuladagi “+”, “”, “·”, “” kabi arifmetik
amallarning hisoblash qoidalariga rioya qilgan holda bajarilishi
formulalar yordamida ifodalanishiga misol bo‘ladi.
𝑎𝑥 2 + 𝑏𝑥 + 𝑐 = 0(𝑎 ≠ 0) ko‘rinishidagi kvadrat tenglamani yechish
algoritmining quyida keltirilgan formula orqali ifodasi bilan tanishsiz:
−𝑏 ± √𝑏 2 − 4𝑎𝑐
𝑥=
2𝑎
III. Algoritmni jadval yordamida ifodalanishi
Algoritmning jadval ko‘rinishda berilishi ham sizga tanish.
Masalan, matematikadagi Pifagorning ko‘paytirish jadvali, lotoreya
yutuqlar jadvali, Mendeleyev kimyoviy elementlar jadvali. Bunday
jadvallardan foydalanish ma’lum bir algoritm qo‘llashni talab etadi.
Biror funksiyaning grafigini chizish uchun ham
funksiyaning argument qiymatlariga mos qiymatlar jadvalini hosil
qilamiz. Bu ham algoritmning jadval ko‘rinishiga misol bo‘ladi.
5-masala: 𝑦 = 𝑥 2 algoritm asosida harakat qilayotgan ijrochi
o‘tadigan nuqtalarni ba’zilari ko‘rsatilgan quyidagi jadval bilan
matematikadan tanishsiz:
x -3 -2 -1
y 9 4 1
8
algoritmning boshlanishini va
tugallanganligini bildiradi
ma’lumotlarni kiritishni bildiradi
9
Dastur fayli doimiy xotirada (qattiq diskda) saqlanadi, bajarilish
vaqtida esa vaqtinchalik (operativ) xotiraga yuklanadi. Kompyuterda
axborotni kiritish klaviatura (kiritish qurilmasi) orqali, chiqarish esa
monitor (chiqarish qurilmasi) orqali amalga oshiriladi.
Kompyuter faqat ikki tipdagi signallar: 0 va 1 (mashina kodlari)
bilan ishlay oladi. 1010101010010101010 ko‘rinishdagi dasturni
yozish inson uchun qiyin masala. Shuning uchun ham insoniyatga
tushunarli bo‘lgan dasturlash tillari bilan birgalikda kompyuterga
tushunarli bo‘lgan yaratildi.
10
1.2-rasm. Dasturlash tillari turlari
XX asrning 50-yillarida, mashina darajasiga eng yaqin bo'lgan past
darajadagi paydo bo'ldi. U protsessor bilan bog'langan,
shuning uchun uni o'rganish protsessor arxitekturasini o'rganishga
o'xshaydi. Bugungi kunda ham assembler tilida yozilgan, xotira
resurslari juda cheklangan dasturlar kichik
qurilmalar(mikrokontrollerlar)ning ajralmas qismi hisoblanadi.
Keyingi bosqich - ning paydo bo‘lishi bo‘lib, shuningdek
ushbu davrda yaratilgan ham hanuzgacha maktablarda
dasturlashni o'rgatishda asosiy til sifatida qo'llaniladi.
Dastlab operatsion tizim assembler tilida yozilgan bo‘lib, uni
o‘zgartirish va o‘rganish ancha qiyin bo‘lgan, keyinchalik
tizimli dasturlash uchun ni ishlab chiqdi va B.Kernigan bilan
birgalikda tizimini shu tilda qayta yozdi.
So‘ngra UNIX operatsion tizimi keng tarqaldi (hozirda uning
GNU / Linux versiyalari ko'proq ma'lum) va unda ishlaydigan
dasturchilar soni ham keskin ko‘paydi.
Keyingi bosqich (80-yillar) yirik sanoat dasturlarini yaratishni
soddalashtirishi kerak bo'lgan ning
(OOP) paydo bo‘lishi bilan tavsiflanadi. C tilining
imkoniyatlaridan qoniqmadi, shuning uchun u OOP qo'shish orqali bu
tilni kengaytiradi. Yangi til C++ deb nomlandi.
C++ TILI TARIXI
Ilgari dasturchilar uzun 1 va 0 lar qatoridan iborat bo‘lgan
kompyuter buyruqlari bilan ishlashgan. Tez orada Assembler tili ixtiro
qilingandan so‘ng, ular mashina buyruqlarini odam uchun tushunarli
bo'lgan ko'rinishda namoyish etishlari mumkin edi.
11
Vaqt o'tishi bilan va kabi yuqori darajadagi tillar
paydo bo'ldi. Ushbu tillar yordamida so'zlar va gaplarning mantiqiy
loyihalashlaridan foydalangan holda dasturlash mumkin bo'ldi,
masalan, Let I = 100. Ushbu buyruqlar tomonidan mashina
tiliga tarjima qilingan. dasturni o'qiyotganda, uning
buyruqlarini (yoki kodini) mashina tili buyruqlariga ketma-ket o‘giradi.
dastur kodini to'liqligicha obyekt fayliga tarjima qiladi.
Ushbu bosqich deb ataladi.
Tarjimon tillarining yana biri bo‘lgan bilan ishlash
nisbatan osonroq, chunki dastur buyruqlari yozilgan ketma-ketlikda
bajariladi, bu esa dasturning bajarilishini nazorat qilishni
osonlashtiradi. Biroq, kompilyatsiya qilingan dasturlar tezroq ishlaydi,
chunki dastur buyruqlarini mashina tiliga tarjima qilish kompilyatsiya
bosqichini o‘zida amalga oshiriladi.
Ba'zi tillarda (masalan, Visual Basic) interpretator vazifasini
dinamik kutubxona bajaradi. Java tilining interpretatori virtual mashina
(Virtual mashina yoki VM). Brauzer odatda virtual mashina sifatida
ishlatiladi (masalan, Internet Explorer yoki Netscape).
Ko'p yillar davomida dasturning asosiy afzalligi uning qisqaligi va
bajarilish tezligi deb hisoblangan. Dasturchilar dasturni iloji boricha
qisqartirishga harakat qilishdi, chunki xotira juda qimmat edi. Ammo
kompyuterlar tobora portativ (ko'chma) bo‘lganligi sababli, arzonroq
(xotira ayniqsa sezilarli darajada arzon) va tezligi oshdi, bu esa o‘z
navbatida, rivojlanishga olib keldi. Bugungi kunda dasturchining ish
vaqtining narxi ancha yuqori. Endilikda professional ravishda yozilgan
va oson ishlaydigan dasturlarga talab o‘sib bormoqda.
DASTURLAR
so'zi ikki ma'noda ishlatiladi: dasturchi tomonidan yozilgan
alohida buyruq bloklari (yoki dastur kodini) va tayyor bir dasturiy
mahsulot. Shunday qilib, dasturni dasturchi tomonidan yozilgan
buyruqlar to'plami yoki kompyuterda bajariladigan dasturiy mahsulot
sifatida aniqlash mumkin.
Tarjimon dasturlari ikkiga bo‘linadi. Birinchi holda,
interpretatorlar dastur kodini mashina buyruqlariga tarjima qilishadi va
kompyuter ularni darhol bajaradi. Interpretatorlar bilan ishlash osonroq
bo‘lsada, aksariyat dasturlar kompilyatorlar yordamida yaratiladi,
12
chunki kompilyatsiya qilingan kod ancha tezroq. C++ tili ham
kompilyatsiya qilinadigan dasturlash tiliga misol bo‘la oladi.
Vaqt o'tishi bilan dasturchilar oldida turgan muammolar o'zgardi.
Shu bilan birga, ko'pincha dasturlarni yozganlar ham, ulardan
foydalanganlar ham kompyuter bilimlari sohasidagi mutaxassislar
edilar. Bugungi kunda esa ko'p o'zgarishlar bo‘ldi.
Ajablanarlisi shundaki, foydalanuvchilarning yangi avlodiga
dasturlar bilan ishlashni osonlashtirish uchun ushbu dasturlarning
murakkabligi sezilarli darajada oshdi. Zamonaviy dasturlarda
foydalanuvchilarga qulay bo‘lgan interfeyslar qo'llaniladi, ular ko'plab
oynalar, menyular, dialog oynalari va ko‘plab vizual grafik vositalar
bilan jihozlangan. Inson va kompyuter o'rtasidagi o'zaro
munosabatlarning ushbu yangi darajasini qo'llab-quvvatlash uchun
yozilgan dasturlar bundan o'n yil oldin yozilganlarga qaraganda ancha
murakkab.
Kompyuterlar uchun butunjahon internet axborot tarmog'ining
rivojlanishi bilan bozorga kirishning yangi davri boshlandi. Hozirda har
qachongidan ham ko'proq kompyuter foydalanuvchilari bor.
Dasturlash talablarining o'zgarishi bilan tillar ham, dastur yozish
texnologiyasi ham o'zgardi.
C++TILINING SOHALARI
Obyektga yo'naltirilgan tahlil, loyihalash va dasturlash g'oyasi
paydo bo'lganda, Byarn Stroustrup (Bjarne Stroustrup) C tilini (tijorat
dasturiy mahsulotlarini ishlab chiqarish uchun eng mashhur) uni
obyektga yo'naltirilgan dasturlash uchun zarur bo'lgan vositalar bilan
boyitish orqali kengaytirdi.
C++ tili haqli ravishda C davomi deb nomlangan bo‘lsada va C
tilidagi har qanday ishlaydigan dastur C++ kompilyatori tomonidan
qo'llab-quvvatlanadi, C dan C++ ga o'tishda juda katta o‘zgarish amalga
oshirildi. C++ tili C tili bilan bog'liq, shuning uchun dasturchilar C dan
C++dan foydalanishga osongina o'tishlari mumkin edi. Biroq, ko'plab
dasturchilar C++ tilidan to'liq foydalanish uchun avvalgi bilimlaridan
voz kechib, yangi bilimlarlarga, ya'ni dasturlash muammolarini
tushunish va hal qilishning yangi usulini o'rganishga ega bo‘lishlari
kerakligini aniqladilar.
Ko'pchilikda savol tug'iladi: "C++ C tilining davomi bo'lganligi
sababli, avval C ni o'zlashtirishim kerakmi?" Stroustrup va boshqa
13
ko'plab dasturchilar, C++ dan foydalanadiganlar, bu kerak emas va buni
qilmaslik yaxshiroq deb hisoblashadi.
C++ VA JAVA
C++ hozirda tijorat dasturiy mahsulotlarini ishlab chiqarish uchun
ishlatiladigan asosiy til hisoblanadi. So'nggi yillarda Java kabi
dasturlash tili tufayli bu hukmronlik biroz o‘zgardi. Qanday bo'lmasin,
bu ikki til shu qadar o'xshashki, ulardan birini o'rganish orqali siz
boshqasini 90% o'zlashtirasiz.
ANSI STANDARTI
(American National Standards
Institute - ANSI) rahbarligida faoliyat yuritadigan standartlar qo'mitasi
C++tili uchun xalqaro standartni yaratdi.
C++ standarti hozirgi kunda - International Standard
Organization (xalqaro standartlash tashkiloti) deb nomlanadi. Bundan
tashqari, C++ tili standarti haqida gapirganda, ba'zida ular NCITS
(National Committee for Information Technology Standards - axborot
texnologiyalari standartlari bo'yicha Milliy qo'mita) yoki X3 (NCITS
qo'mitasining eski nomi) yoki ANSI/ISO degan ma'noni anglatadi.
Ushbu kitobda biz mashhur atama bo‘lgan ANSI standartiga amal
qilamiz.
ANSI standarti C++ tilining apparat jihatdan mustaqil bo‘lishini
ta'minlashga urinishdir (ya'ni kompyuterdan kompyuterga uzatiladi).
Bu shuni anglatadiki, dastur Microsoft kompilyatori uchun ANSI
standartiga muvofiq yozilgan, boshqa ishlab chiqaruvchining
kompilyatori yordamida xatosiz kompilyatsiya qilinadi. Bundan
tashqari, ushbu kitobda keltirilgan dasturlar ANSI-ga mos bo'lganligi
sababli, ular Mac, Windows yoki Alpha platformalarida ishlaydigan
kompyuterlarda xatosiz kompilyatsiya qilinishi kerak.
Ko'pgina C++ tilini o'rganuvchilar uchun ANSI standarti ideal
bo'lib qolmoqda. Shunga qaramay, dasturiy mahsulotning an'anaviy
ANSI standartlariga muvofiqligi professional dasturchilar uchun
muhimdir.
C++ tili dasturchidan dasturni yozishdan oldin uni loyihalashdan
iborat tayyorgarlik bosqichini o'tkazishni talab qiladi.
Professional dasturchilar deyarli har kuni real hayotda duch
keladigan murakkab muammolar rostan ham dastlabki loyihasini talab
14
qiladi va u qanchalik professionallik bilan amalga oshirilsa, dastur
ularni minimal vaqt va pul bilan hal qilishi mumkin.
Har qanday dasturni loyihalashga tayyorgarlik ko'rishda
beriladigan birinchi savol quyidagicha: "men qanday muammoni hal
qilmoqchiman?" Har bir dastur aniq belgilangan maqsadga ega bo‘lishi
kerak.
Har bir o'zini hurmat qiladigan dasturchi ikkinchi savolni
quyidagicha qo'yadi: "ushbu muammoni allaqachon mavjud bo'lgan
dasturiy mahsulotlar yordamida hal qilish mumkinmi?" Ko'pincha,
bunday yechim mutlaqo yangi dastur yaratishdan ko'ra yaxshiroq
bo‘lishi mumkin. Bunday yechimni taklif qiladigan dasturchi hech
qachon ish yetishmasligidan aziyat chekmaydi: muammolarga iqtisodiy
yechimlarni topish qobiliyati kelajakda uning mashhurligini
ta'minlaydi.
Muammoni tushunib, bu mutlaqo yangi dastur yozishni talab qiladi
degan xulosaga kelib, siz loyihalash bosqichiga tayyor bo'lasiz. Har
qanday tijorat dasturini yaratish muammoni sinchkovlik bilan tahlil
qilishni va uning samarali yechimini loyihalashni talab qiladi.
Sizning kompilyatoringiz o'zining o'rnatilgan matn muharririga
ega yoki siz fayllarni formatlash atributlarisiz matn formatida
saqlaydigan har qanday kod kiritish muharriridan foydalanishingiz
mumkin. Bunday muharrirlarga Windows Notepad, DOS Edit, Brief,
Epsilon, EMACS buyruqlari misol bo'la oladi. WordPerfect, Word va
boshqalar fayllarni matn formatida saqlashga imkon beradi.
Matn muharrirlari yordamida yaratilgan fayllar deb
ataladi. Ular odatda kengaytmaga .cpp, .cp yoki .c ega. ushbu kitobda
dastur kodlarini o'z ichiga olgan fayllar kengaytmaga .cpp ega.
ESLATMA: Ko'pgina C++ kompilyatorlari uchun dasturning asl
matnini o'z ichiga olgan fayl qaysi kengaytmaga ega bo‘lishi muhim
emas, garchi ko'pchilik .cpp kengaytmani sukut holatda ishlatadi.
DASTUR KODINI KOMPILYATSIYA QILISH
Sizning faylingizdagi dasturning asl matni uni ko'rib chiqadigan
har bir kishi uchun tushunarli bo'lmasada (ayniqsa C++ tilini
bilmaganlar uchun), u inson tomonidan idrok etilishi mumkin bo'lgan
ko‘rinishda taqdim etilgan. Dastur matni fayli - bu hali dastur emas va
uni bajarish yoki ishga tushirish mumkin emas, ya’ni dasturga
aylantirish uchun kompilyator ishlatiladi.
15
Dastur kodini kompilyatsiya qilish tugagandan so'ng, obyekt fayli
yaratiladi. Ushbu fayl odatda .obj kengaytmaga ega. Ammo bu hali
bajarilmagan dastur. Obyekt faylini bajariladigan faylga aylantirilib
ishga tushirilishi mumkin.
-bu kompilyator bilan birga keladigan, alohida sotib
olinadigan yoki dasturchining o'zi tomonidan yaratilgan va tuzilgan
tarkibiy fayllar to'plami. Barcha C++ kompilyatorlari dasturga
kiritilishi mumkin bo'lgan funksiyalar (yoki protseduralar) va sinflar
kutubxonasi bilan birga keladi. Shunday qilib, bajariladigan faylni
yaratish uchun siz quyida keltirilgan amallarni bajarishingiz kerak.
1. .cpp kengaytmaga ega bo'lgan dastur faylini yarating.
2. Dastur kodini kompilyatsiya qiling va .obj kengaytmali obyekt
faylini oling.
3. .obj faylini kerakli kutubxonalar bilan birgalikda dastur faylini
ishlatish uchun kompilyatsiya qiling.
Dasturdagi har qanday xato tuzatilishi kerak va buning uchun
dastur matnini tahrirlash, uni qayta kompilyatsiya qilish va yana
ishlatish kerak.
C++ TILIDAGI BIRINCHI DASTUR HELLO.CPP
An'anaga ko'ra, dasturlash kitoblarida dasturlarning birinchi
misollari “Hello World!” so'zlarini yoki mavzu bo'yicha ba'zi
o'zgarishlarni ko'rsatish bilan boshlanadi. Bu kitobda biz an'analarga
amal qildik. Barcha qoidalarga amal qilgan holda C++ dasturlash tilida
birinchi dasturni kiriting. Yozishni tugatgandan so'ng, faylni saqlang,
kompilyatsiya qiling va bajaring. Dastur “Hello World!” so'zlarini
konsolga chiqarishi kerak. Ushbu dasturning barcha kodlari keyingi
darslarda batafsil ko'rib chiqiladi.
ESLATMA: Quyidagi listing chap tomonida qatorning tartib
sonlari yozilgan bo‘lib, ularni muharrir oynasiga kiritish shart emas.
Masalan, Listing 1.1 da birinchi qatorida siz quyidagilardan boshlab
kiritishingiz kerak:
#include <iostream>
Listing 1.1. Hello.cpp dasturi
1 #include <iostream>
2 using namespace std;
3 int main(){
4 cout << "Hello World!\n";
5 return 0;
6}
16
Siz kiritgan dastur matni bu yerda keltirilgan listingga mos
kelishiga ishonch hosil qiling. Tinish belgilariga e'tibor bering. 4-
qatordagi “ << ” belgisi chiqarish operatoridir. 4- va 5-qator nuqta-
vergul (;) bilan tugaydi. Dastur kodi satrini tugatish uchun ushbu belgini
qo‘yish kerak.
Kompilyatsiya jarayonidagi xatolar turli sabablarga ko'ra yuzaga
kelishi mumkin. Yaxshi kompilyatorlar nafaqat xatolik haqida xabar
berishadi, balki ular aniqlangan xatoning aniq manzilini ham
ko'rsatadilar.
17
2-MAVZU: C++ DASTURLASH TILINING TUZILISHI
Dev C++ dasturlash muhiti
C++ dasturlash tilida dastur sintaksisi
Cout obyekti haqida qisqacha ma'lumot
Izohlar
18
2.3-rasm. Dev C++ dasturining ishchi oynasi
2.4-rasm. Dev C++ dasturida yangi fayl ochish
19
2.5-rasm. Dev C++ dasturida kompilyatsiya va dasturni bajarish
jarayoni
Compile & Run yoki F11 klavishlarini bosish orqali kompilyatsiya
va dasturni bajarish amalga oshiriladi.
22
Listing 2.2. Cout obyektidan foydalanish
1 #include <iostream>
2 using namespace std;
3 int main(){
4 cout << "Hello there.\n";
5 cout << "Here is 5: " << 5 << " n";
6 cout << "The manipulator endl writes a new line to the screen.";
7 cout <<endl;
8 cout << "Here is a very big number:\ t" << 70000 << endl;
9 cout << "Here is the sum of 8 and 5:\ t" << 8+5 << endl;
10 cout << "Here's a fraction:\ t\ t" << (float) 5/8 << endl;
11 cout << "And a very very big number:\ t";
12 cout << (double) 7000 + 7000 << endl;
13 cout << "Don't forget to replace Jesse Liberty with your name…\n";
14 cout << "Jesse Liberty is a C++ programmer!\n";
15 return 0;
16 }
23
joy matn satrining bir qismidir. Keyin 5 qiymati chiqarish operatori
yordamida cout obyektiga uzatiladi va undan so‘ng yangi qatorga o‘tish
belgisi kelgan (bu belgi har doim ikki yoki bitta tirnoqlar ichida
yoziladi). Ushbu ifodani bajarayotganda ekranda ushbu qator paydo
bo'ladi.
Here is 5: 5
7-qatorda ekranda axborot xabari ko'rsatiladi, shundan so'ng 8-
qatorda endl operatori ishlatiladi. Ushbu operator ham yangi qatorga
o‘tish operatori hisoblanadi.
ESLATMA: Endl operatori (satr oxiri) degan ma'noni
anglatadi.
9-qatorda yana bir formatlash belgisi ishlatilgan - \t, bu belgi
ma`lumotlari o‘rtasida bir tabulyatsiya o‘lchamida bo‘sh joy qo‘yish
uchun ishlatiladi (9-12-qatorlar). 9-qator Long int tipidagi qiymatlarni
chop etadi. 10-qatorda cout obyekti matematik amal natijalarini
chiqarishi mumkinligi ko'rsatilgan. Cout obyektiga qiymat emas, balki
butun matematik ifoda 8+5 uzatiladi, ammo 13 soni ekranda
ko'rsatiladi.
11-qatorda cout obyekti boshqa matematik amalning natijasini
chiqaradi-5/8. Identifikator (float) cout obyektiga natijani kasr son
sifatida ko'rsatish kerakligini bildiradi.
13-qatorda 7000 + 7000 ifodasi cout obyektiga uzatiladi va
identifikator (double) natijaning chiqarishini eksponent ko'rinishda
o'rnatadi.
15-qatorga ismingizni kiritishingiz mumkin.
IZOHLAR
Dastur yozayotganda nima maqsadda yozayotganingiz har doim
aniq bo'ladi. Ammo, agar siz bir oydan keyin ushbu dasturga
qaytishingiz kerak bo'lsa, unda ajablanarli tomoni shundaki, siz nima
haqida yozganingizni deyarli eslay olmaysiz va tafsilotlar haqida
gapirishning hojati yo'q.
Dastur maqsadini esda saqlash va boshqalarga dasturingizni
tushunishga yordam berish uchun izohlardan foydalanish maqsadga
muvofiq.
-bu kompilyator tomonidan e'tiborsiz qoldirilgan, ammo
dasturda alohida satr yoki butun blokning maqsadini to'g'ridan-to'g'ri
tavsiflashga imkon beradigan matn.
24
IZOH TURLARI
C++ tilida ikki xil izoh ishlatiladi:
Ikkita slash (//)
slash va yulduzcha (/*) kombinatsiyasilari.
Ikkita slash (C++ uslubidagi izoh deb nomlanadi) yordamida
olingan izohlar bo‘lib, kompilyatorga izohdan keyingi
hamma narsani e'tiborsiz qoldirishni buyuradi. Slash va yulduzcha bilan
yozilgan izohga (C uslubidagi izoh deb nomlanadi)
deyiladi va kompilyatorga izoh belgilari boshlanishidan to izohni
tugatish belgisi paydo bo'lguncha hamma narsani e'tiborsiz qoldirishni
aytadi. Har bir ochiladigan / * belgilar juftligi */yopilish juftligiga mos
kelishi kerak.
C uslubidagi izohlar C++ tilida ham qo'llaniladi. C++ da
dasturlashda izohga olish uchun asosan ikkita slash belgilaridan
foydalaniladi va C uslubidagi izohlar faqat dasturning katta bloklarini
vaqtincha o'chirish uchun ishlatiladi.
IZOHLARDAN FOYDALANISH
Listing 2.3 da izohlardan foydalanish ko‘rsatilgan, ular dasturning
bajarilishi va uning natijalariga ta'sir qilmaydi.
Listing 2.3. hello.cpp dasturi misolida izohlar
1 #include <iostream>
2 int main()
3{
4 /* bu izoh,
5 bu qadar davom etadi
6 izohning oxiri yulduzcha va Slash belgisi bilan tugaydi */
7 cout << "Hello world!\n";
8 // ushbu izoh satr oxirida tugaydi
9 cout << "That comment ended! \n";
10 // ikki marta slashdan keyin hech nima bo'lmasligi mumkin,
11 /* bu belgilar orasi */
12 return 0;
13 }
Natija:
Hello world!
That comment ended!
Tahlil: 4-6-qatorlardagi izohlar, 8, 10 va 11-qatorlardagi izohlar
kabi, kompilyator tomonidan umuman e'tiborga olinmaydi. 8-qatordagi
izoh ushbu satr oxirida tugaydi, ammo 4 va 11-qatorlarda boshlangan
izohlarni to‘ldirish uchun izohning tugash belgisi (*/) talab qilinadi.
25
Nazorat savollari va topshiriqlar
1. Kompilyator va preprotsessor o'rtasidagi farq nima?
2. Main () funksiyasining o'ziga xos xususiyati nimada?
3. Qanday izohlarni bilasiz va ular bir-biridan qanday farq qiladi?
4. Izohlar bir qatorda joylashtirilishi mumkinmi?
5. Izohlar bir nechta satrlarni egallashi mumkinmi?
6. “ I love C++” xabarini ko'rsatadigan dasturni yozing.
7. Kompilyatsiya qilish va bajarish mumkin bo'lgan eng kichik
dasturni yozing.
8. Xatolar: ushbu dasturni kiriting va uni kompilyatsiya qiling. Nima
xatolik berdi?
1 #include <iostream>
2 using namespace std;
3 int main(){
4 cout << Is there a bug here?";
5 return 0;
6}
26
3-MAVZU: O’ZGARUVCHILAR VA IFODALAR
27
Har bir katak bir bayt hajmga ega. Agar butun tipdagi
o'zgaruvchiga to'rt bayt kerak bo'lsa, unda buning uchun to'rtta katak
ajratiladi, ya'ni aynan o'zgaruvchining tipi bo'yicha (masalan, int)
kompilyator ushbu o'zgaruvchiga qancha xotira (qancha katakcha)
ajratilishi kerakligini baholaydi.
Bir xil tipdagi o'zgaruvchilar uchun turli rusumdagi
kompyuterlarda turli xil xotira hajmi ajratilishi mumkin, shu bilan birga
bitta kompyuter ichida bir xil tipdagi ikkita o'zgaruvchi har doim
o‘zgarmas hajmga ega bo'ladi.
Char tipidagi o'zgaruvchi (belgilarni saqlash uchun ishlatiladi)
ko'pincha bir bayt hajmiga ega.
Ko'pgina kompyuterlarda short int(qisqa butun) tipi uchun odatda
ikkita bayt, long int (uzun butun) tipi uchun to'rt bayt, int tipi uchun
(qisqa yoki uzun kalit so'zsiz) ikki yoki to'rt bayt ajratilishi mumkin.
Butun qiymatning kattaligi kompyuter tizimi (32 yoki 64 bitli) va
ishlatilgan kompilyator tomonidan belgilanadi. Ushbu kitob 4 baytli
butun sonlardan foydalanishga qaratilgan, ammo sizda boshqa variant
bo‘lishi mumkin.
3.1 listingida keltirilgan dastur sizning kompyuteringizda ushbu
tiplarning aniq hajmini aniqlashga yordam beradi. faqat bir bayt
xotirani egallaydigan bitta harf, son yoki belgini anglatadi.
Listing 3.1. Turli xil tiplarning o'lchamlarini aniqlash
1 #include <iostream>
2 using namespace std;
3 int main()
4 {cout << "The size of an int is:\t\t" << sizeof(int) << " bytes.\n";
5 cout << " The size of a short int is:\t\t" << sizeof(short) << " bytes.\n";
6 cout << " The size of a long int is:\t\t" << sizeof(long) << " bytes.\n";
7 cout << " The size of a char is:\t\t" << sizeof(char) << " bytes.\n";
8 cout << " The size of a float is:\t\t" << sizeof(float) << " bytes.\n";
9 cout << " The size of a double is:\t\t" << sizeof(double) << " bytes.\n";
10 cout << " The size of a bool is:\t\t" << sizeof(bool) << " bytes.\n";
11 }
12 return 0;
13 }
Natija:
The size of an int is: 4 bytes.
The size of a short int is: 2 bytes.
The size of a long int is: 4 bytes.
The size of a char is:1 bytes.
The size of a float is:4 bytes.
The size of a double is:4 bytes.
28
The size of a bool is:1 bytes.
ESLATMA: Kompyuteringizda har xil tipdagi o'zgaruvchilarning
o'lchamlari boshqacha bo‘lishi mumkin.
Listing 3.1 operatorlarining aksariyati sizga tanish. 4-10 qatorlarda
sizeof() funksiyasidan foydalanish siz uchun yangi bo‘lishi mumkin.
Sizeof () funksiyasining natijasi kompilyator va kompyuterga bog'liq
bo'lib, uning maqsadi parametr sifatida uzatiladigan obyektlarning
o'lchamlarini aniqlashdir. Masalan, sizeof() funksiyasining 4-qatorida
int kalit so'zi uzatiladi. Funksiya ma'lum bir kompyuterda int tipidagi
o'zgaruvchining baytlarida hajmni qaytaradi. Bizning misolimizda int
va long int tiplari uchun to'rt bayt qiymati qaytariladi.
29
C++ dasturlarida ishlatiladigan o'zgaruvchilarning asosiy tiplari
3.1-jadvalda keltirilgan. Shuningdek, u ko'rsatilgan tipdagi
o'zgaruvchilarning odatiy o'lchamlarini va ushbu o'zgaruvchilarda
saqlanishi mumkin bo'lgan chegara qiymatlarini ko'rsatadi. Siz 3.1-
Listingda keltirilgan dasturning natijalarini 3.1- jadval bilan
taqqoslashingiz mumkin.
Turi Hajmi, bayt Qiymati
bool 1 true yoki false
unsigned short int 2 0…..65535
short int 2 -32768…..32767
unsigned long int 4 0….4294967295
long int 4 -2147483648….2147483647
int(16ta son) 2 -32768…..32767
int(32ta son) 4 -2147483648….2147483647
unsigned int(16ta son) 2 0…..65535
unsigned int(32ta son) 4 0….4294967295
char 1 256ta belgilar qiymati
float 4 1,2e38………3,4e38
double 8 2,2e308……..1,8e308
3.1- jadval. O'zgaruvchilar tiplari
O'ZGARUVCHINI NOMLASH
O'zgaruvchini yaratish yoki nomlash uchun siz uning tipini
o‘zlashtirishingiz kerak, undan keyin (bir yoki bir nechta bo‘sh
joylardan keyin) o‘zgaruvchi nomi nuqta-vergul bilan tugashi kerak.
O'zgaruvchining nomi uchun deyarli har qanday harf birikmasidan
foydalanish mumkin, ammo unda bo'sh joy bo'lmasligi kerak, masalan:
x, J23qrsnf va myAge. O'zgaruvchilarni baholashga imkon beradigan
ismlar yaxshi deb hisoblanadi, chunki yaxshi tanlangan o‘zgaruvchi
nomi umuman dasturning ishlashini tushunishni osonlashtirishi
30
mumkin. Quyidagi ifoda myAge nomli butun son o'zgaruvchisini
aniqlaydi: int myAge;
ESLATMA: O'zgaruvchini e'lon qilganda, unga xotira ajratiladi
(zaxiralanadi).
Professional dasturchilar j23qrsnf kabi o'qib bo'lmaydigan
o'zgaruvchi nomlardan foydalanishmaydi, bir harfli o'zgaruvchilar
(masalan, x yoki i) faqat takrorlash hisoblagichlari kabi vaqtinchalik
o'zgaruvchilar uchun ishlatiladi. MyAge yoki howMany kabi iloji
boricha ma'lumotli nomlardan foydalanishga harakat qiling. Bunday
ismlar, hatto vaqt o'tgach ham, ma'lum bir dastur satrlarini
yozganingizda nimani nazarda tutganingizni eslab qolishingizga
yordam beradi.
Keyingi dasturni ko‘rib chiqing. Dasturning dastlabki besh
qatoriga asoslanib, quyida e'lon qilingan o'zgaruvchilar nima uchun
ekanligini taxmin qilishga harakat qiling.
1-misol:
int main()
{
unsigned short x;
unsigned short y;
unsigned short z;
Z = * Y;
return 0;
}
2-misol:
int main ()
{
unsigned short Width;
unsigned short Length;
unsigned short Area;
Area = Width • Length;
return 0;
}
Shubhasiz, ikkinchi misolda o'zgaruvchilarni o‘zlashtirish haqida
tasavvur qilish osonroq, chunki siz u yoki bu o'zgaruvchining nima
uchun mo'ljallanganligi haqida bosh qotirishingiz shart emas.
HARFLARNING KATTA-KICHIKLIGIGA SEZGIRLIK
C++ tili harflarga sezgir. Boshqacha qilib aytganda, katta va kichik
harflar har xil harflar deb hisoblanadi. Age, Age va AGE nomli
o'zgaruvchilar uch xil o'zgaruvchi sifatida qaraladi.
Ko'pgina dasturchilar o’zgaruvchi nomlarni faqat kichik harflar
bilan yozishni afzal ko'rishadi. Agar nom uchun ikkita so'z kerak bo'lsa
31
(masalan, mening mashinam), unda eng mashhur konvensiyalar my_car
yoki myCar variantlaridan foydalanadi.
ESLATMA: Ko'pgina professional dasturchilar Venger
o'zgaruvchini nomlash uslubini qo'llaydilar. G'oya shundan iboratki,
har bir o'zgaruvchida uning tipini ko'rsatadigan prefiks bo‘lishi kerak.
Shunday qilib, butun tipdagi o'zgaruvchilarining nomlari (int tipi)
kichik harf bilan boshlanishi kerak. Tegishli prefikslar konstantalar,
global o'zgaruvchilar, ko'rsatkichlar va boshqa obyektlar bilan
belgilanishi kerak. Biroq, bu C++ dasturiga qaraganda C tilida
dasturlashda muhimroq, chunki bu nostandart tiplarni yoki
foydalanuvchi tomonidan belgilangan tiplarni yaratishni qo'llab-
quvvatlaydi.
KALIT SO’ZLAR
Ba’zi so'zlar dastlab C++ tilida saqlangan va shuning uchun ularni
o‘zgaruvchi nomlari sifatida ishlatib bo'lmaydi. Bunday so'zlar
deb ataladi va kompilyator tomonidan dasturni boshqarish uchun
ishlatiladi. Bularga if, while, for va main kabilar kiradi.
Tavsiya etiladi!
O’zgaruvchini aniqlashda nomdan oldin o'zgaruvchining
tipini ko'rsating.
O'zgaruvchilar uchun ma'lumot beruvchi nomlardan
foydalaning.
C++ tilida katta va kichik harflar farq qilishini unutmang.
Kompyuteringizdagi har bir o'zgaruvchining xotira tipi
qancha baytni egallashini va ushbu tipdagi o'zgaruvchilarda qanday
qiymatlarni saqlash mumkinligini aniqlang.
Tavsiya etilmaydi!
Ishorasiz o'zgaruvchilarga manfiy sonlarni bermang.
Kalit so'zlarni o’zgaruvchi nomlar sifatida ishlatmang.
BITTA TIPLI BIR NECHTA O'ZGARUVCHILARINI
YARATISH
C++ tilida dastur satrida bir vaqtning o'zida bir xil tipdagi bir
nechta o'zgaruvchilarni yaratish imkoniyati mavjud. Buning uchun
vergul bilan ajratilgan o‘zgaruvchi nomlar Listingi keltirilgan tipni
ko'rsating. Masalan:
unsigned int myAge, myWeight; // unsigned int tipidagi o'zgaruvchilar
long int area, width, length; // Long int tipidagi o'zgaruvchi
32
Ushbu misolda ikkala o'zgaruvchi, myAge va myWeight, ishorasiz
butun sonlar deb e'lon qilinadi. Ikkinchi qatorda area, width va length
nomli uchta o'zgaruvchi e'lon qilinadi. Ushbu o'zgaruvchilarning
barchasiga bir xil tipdagi (long) berilgan, shuning uchun
o'zgaruvchilarni aniqlashning bir qatorida har xil tiplarni aralashtirish
mumkin emas.
O'ZGARUVCHILARGA QIYMATLARNI
O‘ZLASHTIRISH
Shu maqsadda o‘zlashtirish operatori (=) ishlatiladi. Shunday qilib,
width o'zgaruvchisiga 5 sonini berish uchun quyidagilarni yozing:
Unsigned short Width;
Width = 5;
ESLATMA: Long tipi - long int tipining qisqartirilgan nomi, short
- short int tipining qisqartirilgan nomi.
Misol sifatida width o'zgaruvchisini quyidagicha ishga tushirish
mumkin:
unsigned short Width = 5; //initsializatsiya
o‘zlashtirishga o'xshaydi, ayniqsa butun
o'zgaruvchilari ishga tushirilganda. Quyida, konstantalarni ko'rib
chiqayotganda, ba'zi qiymatlarni ishga tushirish kerakligini bilib olasiz,
chunki ularga nisbatan o‘zlashtirish amalini bajarish mumkin emas.
Bir vaqtning o'zida bir nechta o'zgaruvchini aniqlash mumkin
bo'lganidek, ularni yaratishda bir vaqtning o'zida bir nechta
o'zgaruvchini initsializatsiya qilish mumkin. Masalan:
// long turdagi ikkita o'zgaruvchi va ularni ishga tushirish
long width = 5, length = 7;
Ushbu misolda Long int tipidagi kenglik o'zgaruvchisi 5 qiymati
va shu tipdagi uzunlik o'zgaruvchisi 7 qiymati bilan initsializatsiya
qilinadi. Bitta satrda bir nechta o'zgaruvchini aniqlashda ulardan faqat
bir nechtasini ham initsializatsiya qilish mumkin:
int myAge = 39, yourAge, hisAge = 40;
Ushbu misolda int tipidagi uchta o'zgaruvchi yaratiladi va faqat
birinchi va uchinchi o'zgaruvchilar initsializatsiya qilinadi.
Listing 3.2 da kompilyatsiya qilishga to'liq tayyor dastur
keltirilgan. U to'rtburchakning maydonini hisoblab chiqadi, shundan
so'ng natija ekranda ko'rsatiladi.
33
Listing 3.2. O'zgaruvchilardan foydalanish
1 #include <iostream>
2 using namespace std;
3 int main()
4{
5 unsigned short int Width = 5, Length;
6 Length = 10;
7 // ishorasiz qisqa turdagi maydon o'zgaruvchisi
8 // ko'paytirish natijasi
9 unsigned short int Area = (Width * Length);
10 cout << "Width:" << Width << "\n";
11 cout << "Length: " << Length << endl;
12 cout << "Area: " << Area << endl;
13 return 0;
14 }
Natija:
Width:5
Length: 10
Area: 50
Tahlil:
2-qatorda cout chiqarish obyektining ishlashini ta'minlaydigan
iostream kutubxonasini o'z ichiga olgan preprotsessor e’loni mavjud.
Aslida, dastur o'z ishini 4-qatorda boshlaydi.
6-qatorda width o'zgaruvchisi ishorasiz short int kabi qiymatni
saqlash uchun aniqlanadi va bu o'zgaruvchini 5 soni bilan
initsializatsiya amalga oshiriladi. 7-qatorda Length o'zgaruvchisiga 10
qiymat beriladi.
11-qatorda ishorasiz short int tipidagi maydon o'zgaruvchisi
aniqlanadi, u kenglik va uzunlik o'zgaruvchilarining qiymatlarini
ko'paytirish natijasida olingan qiymat bilan boshlanadi. 11-13
qatorlarda dasturning barcha o'zgaruvchilarining qiymatlari ekranda
ko'rsatiladi. E'tibor bering, yangi qator uchun maxsus endl ifodasi
ishlatiladi.
TYPEDEF KALIT SO'ZI
Ba'zan unsigned short int kabi kalit so'zlarni qayta-qayta yozish
zerikarli bo'lishi mumkin. C++ tilida kalit so'zidan foydalanib,
ushbu ifoda uchun taxallus (psevdonim) yaratish imkoniyati mavjud,
bu tipni aniqlashni anglatadi.
Taxallusni yaratishda uni yangi tipni yaratishdan farqlash kerak.
Ma'lumotlar tipi taxallusini yaratish uchun avval typedef kalit so'zi,
so'ngra mavjud tipi yoziladi, undan keyin yangi nom va nuqta-vergul
belgisi yoziladi. Masalan, qatorni bajarayotganda
34
typedef unsigned short int USHORT;
USHORT yangi nomi yaratilmoqda, uni unsigned short int tipidagi
o'zgaruvchini aniqlash kerak bo'lgan joyda ishlatish mumkin. 3.3
Listingi unsigned short int so'zlari o'rniga USHORT taxallusidan
foydalangan holda 3.2 Listingini o'zgartiradi.
Listing 3.3. Typedef yordamida tipni aniqlashga misol
1 #include <iostream>
2 using namespace std;
3 typedef unsigned short int USHORT;
4 int main()
5{
6 USHORT Width = 5:
7 USHORT Length;
8 Length = 10:
9 USHORT Area = Width • Length;
10 cout << "Width:" << Width << "\n":
11 cout << "Longth: " << Length << end1;
12 cout << "Area: " << Area << endl;
13 return 0;
14 }
Natija:
Width:5
Length: 10
Area: 50
Tahlil:
4-qatorda typedef kalit so'zidan foydalangan holda USHORT
identifikatori ishorasiz short int tipidagi taxallus sifatida aniqlanadi.
Shunday qilib, ushbu dastur 3.2 Listingida keltirilgan avvalgisiga
o'xshaydi va ikkala dasturning natijalari bir-biriga mos keladi.
QANDAY HOLLARDA SHORT VA INT TIPLARIDAN
FOYDALANISH KERAK?
Ayrim dasturchilar uchun o'zgaruvchini long tipi va short tipi
yordamida qachon e'lon qilish to'g'risida qaror qabul qilish ko'pincha
qiyin. Qoida juda oddiy: agar sizning qiymatingiz mo'ljallangan tip
uchun juda katta bo‘lishi uchun eng kichik imkoniyat bo'lsa, long
tipidan foydalaning.
3.1-jadvalda keltirilganidek, unsigned short int turidagi
o'zgaruvchilar odatda ikki baytga teng va 65535 dan oshmaydigan
qiymatni saqlashi mumkin. Signed short int sonlar o'z diapazonini
musbat va manfiy sonlar o'rtasida taqsimlaydi, shuning uchun ularning
maksimal qiymati unsigned short int ning yarmiga teng.
35
Unsigned long int tipidagi o'zgaruvchilar juda katta sonni (4 294
967 295) saqlashi mumkin. Agar siz undan ham ko'proq sonlar bilan
ishlashingiz kerak bo'lsa, siz float yoki double tiplaridan foydalanishga
o'tishingiz kerak bo'ladi. Float va double tipidagi o'zgaruvchilar juda
katta sonlarni saqlashi mumkin, ammo aksariyat kompyuterlarda faqat
dastlabki 7 yoki 19 sonlar muhim bo'lib qoladi, ya'ni belgilangan sonlar
sonidan keyin son yaxlitlanadi. Short tipidagi o'zgaruvchilaridan
foydalanilganda esa xotira tejaladi.
ISHORASIZ BUTUN SONLAR QIYMATLARINING
TO‘LISHI
Agar Unsigned long int lardan foydalanganda ularning maksimal
chegarasidan oshib ketsangiz nima bo'ladi?
Unsigned int son maksimal qiymatiga yetganda, keyingi o'sish
bilan u nolga qaytariladi. 3.4- Listingida short tipdagi o'zgaruvchiga
qiymat to‘lishi ko‘rsatilgan.
Listing 3.4. Unsigned int qiymatlarining birga ortishiga misol.
1 #include <iostream>
2 using namespace std;
3 int main()
4{
5 unsigned short int smallNumber;
6 smallNumber = 65535;
7 cout << "small number:" << smallNumber << endl;
8 smallNumber++;
9 cout << "small number:" << smallNumber << endl;
10 smallNumber++;
11 cout << "small number:" << smallNumber << endl;
12 return 0;
13 }
Natija :
small number: 65535
small number:0
small number:1
Tahlil:
4-qatorda unsigned short int tipidagi smallNumber o'zgaruvchisi
e'lon qilinadi, bu kompyuterda 0 dan 65535 gacha bo'lgan qiymatni
saqlashga qodir bo'lgan ikki baytli o‘zgaruvchidir. 5-qatorda
smallNumber o'zgaruvchisiga maksimal qiymat beriladi, u 6-qatorda
ekranda ko'rsatiladi. 7-qatorda smallnumber o'zgaruvchisi 1 ga
ko'payadi. O'sish (++) orqali, ya`ni inkrement operatori yordamida
amalga oshiriladi. Shu bilan birga, unsigned short int o'zgaruvchisi
36
65535 dan katta sonni saqlay olmaydi, shuning uchun uning qiymati 0
ga qaytariladi, bu 8-qatorda ko'rsatiladi.
9-qatorda smallNumber o'zgaruvchisi yana bittaga ko'payadi,
shundan so'ng uning yangi qiymati ekranda ko'rsatiladi.
Ishorali butun sonlar ishorasiz butunlardan farq qiladi. Maksimal
musbat qiymatdan oshib ketganda, o'zgaruvchi minimal manfiy
qiymatni oladi. 3.5 Listingi short int tipidagi o'zgaruvchida saqlangan
maksimal musbat songa birlik qo'shilganda nima sodir bo‘lishini
ko'rsatadi.
Listing 3.5. Signed int qiymatlarining to‘lishi.
1 #include <iostream>
2 using namespace std;
3 int main(){
4 short int smallNumber;
5 smallNumber = 32767;
6 cout << "small number:" << smallNumber << endl;
7 smallNumber++;
8 cout << "small number:" << smallNumber << endl;
9 smallNumber++;
10 cout << "small number:" << smallNumber << endl;
11 return 0;
12 }
Natija:
small number: 32767
small number:-32768
small number:-32767
Tahlil:
4-qatorda smallNumber o'zgaruvchisi short int tipi bilan e'lon
qilinadi. Ushbu dastur avvalgisi bilan bir xil amallarni bajaradi, ammo
butunlay boshqa natijalar ekranda ko'rsatiladi.
Ushbu misol shuni ko'rsatadiki, ishorali maksimal musbat butun
ko'paygan taqdirda, nol qiymat (unsigned int bo'lgani kabi) emas, balki
minimal manfiy son olinadi.
O‘ZGARMASLAR
O'zgaruvchilar kabi, ham ma'lumotlarni saqlash uchun
mo'ljallangan xotira kataklaridir. Ammo, o'zgaruvchilardan farqli
o'laroq, konstantalar o'zgarmaydi (ismning o'zi aytganidek-o‘zgarmas).
C++ tilida ikki xil o‘zgarmas mavjud: literal va belgili.
-bu dasturning o'zida to'g'ridan-to'g'ri kiritilgan
qiymat. Masalan,
int myAge = 39;
37
ifodada myAge int tipidagi o'zgaruvchidir, bir soni 39 literal
o‘zgarmasdir. O‘zgarmas 39 ga hech qanday qiymat berolmaysiz.
-bu nom bilan ifodalangan o‘zgarmas. Biroq,
o'zgaruvchidan farqli o'laroq, boshlang'ich konstantaning qiymatini
o'zgartirish mumkin emas.
Agar sizning dasturingizda talabalar deb nomlangan bitta butun
o'zgaruvchisi bo'lsa, siz maktabda qancha sinf borligini va har bir sinfda
qancha o'quvchi borligini bilish sharti bilan maktab o'quvchilarining
umumiy sonini hisoblashingiz mumkin (aytaylik, har bir sinf 15
o'quvchidan iborat):
talabalar = sinflar * 15;
ESLATMA: “*” belgisi ko'paytirishni anglatadi.
Ushbu misolda 15 soni literal o‘zgarmasdir. Ammo agar ushbu
so'zma-so'z o‘zgarmas belgi bilan almashtirilsa, kelajakda sizning
dasturingizni o'qish va o'zgartirish osonroq bo'ladi:
students = classes * studentsPerClass;
Agar siz keyinchalik har bir sinfdagi o'quvchilar sonini
o'zgartirishingiz kerak bo'lsa, buni studentsPerClass o‘zgarmasi
aniqlangan dastur qatorida bir marta qilishingiz mumkin.
#DEFINE E`LONI BILAN O‘ZGARMASLARNI
ANIQLASH
An'anaviy tarzda o‘zgarmasni aniqlash uchun quyidagi ifodani
kiriting:
#define studentsPerClass 15;
Shuni esda tutingki, studentsPerClass o‘zgarmasi o'ziga xos tipga
ega emas (int, char va boshqalar). #Define e’loni oddiy matnni
almashtirishni amalga oshiradi. Har safar preprotsessor
studentsPerClass so'ziga duch kelganda, uni 15 bilan almashtiradi.
CONST KALIT SO'ZI BILAN O‘ZGARMASLARNI
ANIQLASH
#Define e’loni o'z vazifalarini bajarayotgan bo‘lsada, C++ da
konstantalarni aniqlashning yangi, qulayroq usuli mavjud:
const unsigned short int studentsPerClass = 15;
Ushbu misolda studentsPerClass deb nomlangan ishorali
o‘zgarmas e'lon qilinadi, ammo bu safar ushbu o‘zgarmas uchun
unsigned short int tipi aniqlanadi. Ushbu o‘zgarmas va oldingi (#define
38
e’loni bilan e'lon qilingan) o'rtasidagi eng muhim farq shundaki, u tipga
ega va kompilyatorda uning ishlatilishi maqsadga muvofiq.
ESLATMA: Dastur davomida konstantalarni o'zgartirish mumkin
emas. Agar o'zgartirish kerak bo'lsa, masalan, studentsPerClass
konstantalari, siz dasturdagi tegishli o'zgartirish kiritishingiz va uni
qayta kompilyatsiya qilishingiz kerak.
Tavsiya etiladi!
O'zgaruvchilarning qiymatlari ruxsat etilgan chegaradan
oshmasligiga ishonch hosil qiling.
O'zgaruvchilarga ularning maqsadlarini aks ettiruvchi
mazmunli nomlar bering.
Kompyuter xotirasini yanada samarali boshqarish uchun
short va long tiplardan foydalaning.
Tavsiya etilmaydi!
Kalit so'zlarni o’zgaruvchi nomlar sifatida ishlatmang.
ENUM O‘ZGARMASLARI
yangi ma'lumotlar tipini yaratishga imkon beradi va keyin
qiymatlari o‘zgarmas qiymatlar to'plami bilan cheklangan ushbu
tipdagi o'zgaruvchilarni aniqlaydi. Masalan, siz rangni ro‘yxat sifatida
e'lon qilishingiz va buning uchun beshta qiymatni o‘zlashtirishingiz
mumkin: qizil, ko'k, yashil, oq va qora.
Enum kalit so'zidan keyin tip nomi, figurali qavsni ochish, vergul
bilan ajratilgan o‘zgarmas qiymatlar ro‘yxati, figurali qavsni yopish va
nuqta-vergul bilan yoziladi.
Masalan: enum COLOR { qizil, kok, yashil, oq, qora };
Ushbu ifoda ikkita vazifani bajaradi.
1.Yangi tipdagi COLOR nomli ro‘yxat yaratiladi.
2. Belgilar konstantalari aniqlanadi: 0 qiymati bilan qizil; 1 qiymati
bilan ko'k; 2 qiymati bilan yashil va boshqalar.
Har bir enum konstantasi ma'lum bir butun son qiymatiga to'g'ri
keladi. Birinchi indeks 0 qiymati bilan boshlanadi va har bir keyingi
qiymat avvalgisidan kattaroq bo'ladi. Biroq, har qanday o‘zgarmasni
ixtiyoriy qiymat bilan boshlash mumkin, bu holda aniq boshlanmagan
konstantalar ortib borayotgan ketma-ketlikni davom ettiradi va ularning
oldidagi qiymatni mos yozuvlar sifatida oladi. Agar
enum Color { RED=100, BLUE, GREEN=500, WHITE, BLACK=700
};
39
bo‘lsa, qizil o‘zgarmas 100 qiymati ega bo'ladi; moviy - 101 o‘zgarmas;
yashil - 500 o‘zgarmas; oq - 501 o‘zgarmas; qora - 700 o‘zgarmas.
Endi rang tipidagi o'zgaruvchilarni aniqlash mumkin, ammo
ularning har biriga sanab o'tilgan qiymatlardan faqat bittasi berilishi
mumkin (bu holda qizil, ko'k, yashil, oq yoki qora yoki 100, 101, 500,
501 yoki 700). Rang o'zgaruvchisiga har qanday rang qiymati berilishi
mumkin. Enum o'zgaruvchilari aslida unsigned int tipiga ega ekanligini
va berilgan enum konstantalari butun sonli o'zgaruvchilarga
o‘zlashtiringanligini tushunish muhimdir. Biroq, ba'zida ranglar,
haftaning kunlari yoki boshqa shunga o'xshash qiymatlar to'plami bilan
ishlashda ushbu qiymatlarni ism bilan nomlash yaxshi fikrdir. Listing
3.7 enum foydalanadigan dasturni taqdim etadi.
Listing 3.7. Enumdan foydalanish
1 #include <iostream>
2 using namespace std;
3 int main(){
4 enum Days { Sunday, Monday, Tuesday,
5 Wednesday, Thursday, Friday, Saturday };
6 int choice;
7 cout << "Enter a day (0-6): "
8 cin << choice;
9 if (choice = Sunday || choice == Saturday)
10 cout << "\nYou're already off on weekends!\n";
11 else
12 cout << "\n0kay, I'l1 put in the vacation day.\n";
13 return 0;
14 }
Natija:
Enter a day (0-6): 6
You' re already off on weekends!
Tahlil:
4-qatorda yettita o‘zgarmas qiymatga ega kunlar Listingi
aniqlanadi. Ularning barchasi noldan boshlab sonlarning ortib
borayotgan ketma-ketligini hosil qiladi. Shunday qilib, seshanba
qiymati 2 ga teng.
Foydalanuvchiga 0 dan 6 gacha bo'lgan qiymatni kiritish taklif
etiladi. U Sunday so'zini kirita olmaydi, chunki dastur belgilarni enum
qiymatiga o‘girishni ta'minlamaydi. Ammo siz foydalanuvchi kiritgan
qiymatni 9-qatorda ko'rsatilgandek o‘zgarmas listing qiymatlari bilan
40
taqqoslash orqali tekshirishingiz mumkin. Enumdan foydalanish
dasturni tahlil qilishni osonlashtiradi.
41
4. Quyidagi o’zgaruvchi nomlardan qaysi biri yaxshi, yomon yoki
umuman yaroqsiz deb hisoblanishi mumkin?
a) Age
b)!ex
b) R79J
D) TotalIncome
e) _Invalid
42
4-MAVZU: C++ TILINING AMALLARI. INKREMENT,
DECREMENT, SIZEOF, MANTIQIY, RAZRYADLI, TAQQOSLASH.
AMALLARNING USTUNLIKLARI VA BAJARILISH YO‘NALISHLARI
Operatorlar
Bloklar
Ifodalar
Berilgan mantiqiy shartni bajarish natijasi asosida dasturni
tarmoqlashni amalga oshirish
C++dasturchisi nuqtai nazaridan TRUE va FALSE nima?
43
mumkin. Bo'sh joy belgilari ekranda va chop etishda ko'rinmaydi, faqat
matn elementlari orasidagi turli xil bo‘sh joylargina ko'rinadi.
BLOKLAR VA MURAKKAB IFODALAR
Ba'zan dasturni tushunishni osonlashtirish uchun mantiqiy o'zaro
bog'liq ifodalarni deb nomlangan komplekslarga birlashtirish
qulay. Blok ochiladigan figurali qavs ({) bilan boshlanadi va yopuvchi
figurali qavs (}) bilan tugaydi.
{
temp = a;
a = b;
b = temp;
}
Tavsiya etiladi!
Har ochiladigan figurali qavs ishlatilganda yopiladigan
figurali qavsni ham qo‘yishni unutmang.
Dasturdagi ifodalarni nuqta-vergul belgisi bilan tugating.
Tavsiya etilmaydi!
Dasturingizni boshqa yo'l bilan emas, balki aniqroq qilish
uchun bo'sh joy belgilaridan oqilona foydalaning.
AMALLAR
unda ishtirok etadigan operandlar soni bo'yicha unar,
binar va ternar amallarga bo'linadi. Amal bajarilganda, qiymat
qaytariladi. Shunday qilib, 3+2 amali 5 qiymatini qaytaradi. Barcha
amallar bir vaqtning o'zida ifodalardir.
Quyidagi uchta misolni keltiraylik:
3. 2; / / 3.2 qiymatini qaytaradi
PI; / / 3.14 qiymatini qaytaradigan haqiqiy o‘zgarmas
Secondsperminute; / / 60 ni qaytaradigan butun o‘zgarmassi
Aytaylik, PI 3.14 ga teng o‘zgarmas, Secondsperminute 60 ga teng
o‘zgarmas, uchta ifoda ham amallar bo'lishi mumkin.
//Ifoda
x = a + b;
a va b o'zgaruvchilarining qiymatlarini qo'shibgina qolmay, balki
natijani x o'zgaruvchiga o‘zlashtiradi. Amallar har doim o‘zlashtirish
operatorining o'ng tomonida joylashgan:
y = x = a + b;
44
Amallar ketma-ketligi quyidagicha:
a va b ni qo'shing .
a + b natijasini x o'zgaruvchiga o‘zlashtiring.
Agar a, b va x o'zgaruvchisi butun bo'lsa, hamda a qiymati 2 ga va
b qiymati 5 ga teng bo'lsa, u holda x o'zgaruvchisiga 7 qiymat beriladi.
Ba'zi amallarni bajarish misoli Listing 4.1 da keltirilgan.
Listing 4.1. Murakkab amallar bajarilishi
1 #include <iostream>
2 using namespace std;
3 int main(){
4 int a=0, b=0, x=0, y=35;
5 cout << " a: "<<a <<" b: "<<b;
6 cout << " x: " << x << " y:" << y <<"\n";
7 a = 9;
8 b = 7;
9 y = x = a+b;
10 cout << " a: "<<a <<" b: "<<b;
11 cout << " x: " << x << " y: " << y <<"\n";
12 return 0;
13 }
Natija:
a: 0 b: 0 x: 0 y: 35
a: 9 b: 7 x: 16 y: 16
Tahlil:
4-qatorda to'rtta o'zgaruvchi e'lon qilinadi va ishga tushiriladi.
Ularning qiymatlari 5 va 6-qatorlarda ko'rsatiladi. 7-qatorda a
o'zgaruvchiga 9 qiymati beriladi. 8-qatorda b o'zgaruvchisiga 7 qiymati
beriladi. 9-qatorda a va b o'zgaruvchilarining qiymatlari qo‘shiladi va
natija x o'zgaruvchiga beriladi, x = a+b amalining natijasi, o'z
navbatida, y o'zgaruvchiga uzatiladi.
- o'zgaruvchilar va qiymatlar ustida amallarni bajarish
uchun ishlatiladigan simvol yoki simvollar to‘plamidir. Operatorlar
operandlar qiymatiga ta`sir ko‘rsatadi. C++ da operandlar alohida
harflar yoki sonli ifodalar bo‘lishi mumkin. C++ tilida asosiy to‘rt
turdagi operatorlar mavjud:
1. O‘zlashtirish (tayinlash) operatorlari;
2. Matematik operatorlar;
3. Taqqoslash operatorlari;
4. Mantiqiy operatorlar.
45
O‘ZLASHTIRISH (TAYINLASH) OPERATORI
O‘zlashtirish operatori ( = ) tenglik belgisining chap tomonida
joylashgan operand qiymatini uning o'ng tomonida hisoblangan qiymat
bilan almashtirishga imkon beradi. Shunday qilib, ifoda
x = a + b;
operandga x qiymatini belgilaydi, bu a va b o'zgaruvchilar
qiymatlarini qo'shish natijasidir.
O‘zlashtirish operatorining chap tomonida bo‘lishi mumkin
bo'lgan operand manzil operandi yoki l-qiymat (ingliz tilidan l-left,
chap operand) deyiladi. O‘zlashtirish operatorining o'ng tomonida
bo‘lishi mumkin bo'lgan operand operatsion operand yoki r-qiymat
(ingliz tilidan r-o'ng, o'ng operand) deyiladi.
O‘zgarmaslar faqat r-qiymatlari bo‘lishi mumkin, chunki dastur
davomida o‘zgarmas qiymatlarni o'zgartirish mumkin emas. Shunday
qilib, siz quyidagicha yozishingiz mumkin:
x = 35; // to'g'ri
Lekin bu xato:
35 = x; // xato!
Aytib o‘tilganidek, l-qiymat-bu o‘zlashtirish ifodasining chap
tomonida turishi mumkin bo'lgan operand va r - qiymat-bu ifodaning
o'ng tomonida turishi mumkin bo'lgan operand. E'tibor bering, barcha
1-qiymatlar r-qiymat bo‘lishi mumkin, ammo barcha r-qiymatlar 1-
qiymat bo'lmasligi mumkin. 1-qiymat bo‘lishi mumkin bo'lmagan r-
qiymatga misol literal o‘zgarmasdir. Shunday qilib, siz x=5; deb
yozishingiz mumkin, lekin 5=x; deb yozolmaysiz: (x l-qiymat
yoki r-qiymat bo‘lishi mumkin, lekin 5 faqat r-qiymat bo‘lishi
mumkin).
O‘zlashtirish operatorlari 4.1-jadvalda berilgan.
Operator Misol Izoh
= a = b; a = b;
+= a += b; a = a + b;
-= a -= b; a = a - b;
*= a *= b; a = a * b;
/= a /= b; a = a / b;
%= a %= b; a = a % b;
4.1-jadval. O‘zlashtirish operatorlari
46
MATEMATIK OPERATORLAR
C++ asosan 5 ta matematik operatordan foydalanadi: qo'shish ( +
), ayirish ( - ), ko'paytirish ( + ), butun bo'lish ( / ) va qoldiqli bo‘lish
(%).
Qo'shish va ayirish amallarini tushunish oson: ular ikkita
operandning yig'indisi yoki ayirmasini bildiradi. Shuni ta'kidlash
kerakki, ishorasiz butun sonlarni ayirishda ayirma manfiy son bo'lsa,
noto‘g`ri natijaga olib kelishi mumkin. Shunga o‘xshash Listing 4.2
bilan tanishib chiqing.
Listing 4.2. Butun sonni to‘lib qolishiga misol
1 #include <iostream>
2 using namespace std;
3 int main()
4{
5 unsigned int difference;
6 unsigned int bigNumber = 100;
7 unsigned int smallNumber = 50;
8 difference = bigNumber - smallNumber;
9 cout << "Difference is: " << difference;
10 difference = smallNumber - bigNumber;
11 cout << "\nNow difference is: " << difference <<endl;
12 return 0;
13 }
Natija:
Difference is: 50
Now difference is: 4294967246
Tahlil: Ayirish operatori 10-qatorda ishlatiladi va natija 11-
qatorda ko'rsatiladi, bu holda to‘g`ri natija chiqadi. 12-qatorda ayirish
operatori yana chaqiriladi, ammo bu safar kichik musbat sondan katta
musbat son chiqariladi. Natija manfiy bo‘lishi kerak, ammo u musbat
son sifatida hisoblanganligi (va chiqarilganligi) sababli, o'tgan darsda
aytib o'tilganidek, xotiraning to‘lib qolishi sodir bo'ladi.
BUTUN BO'LISH VA QOLDIQLI (MODULLI) BO'LISH
Butun bo'lish odatdagidan biroz farq qiladi. 21 sonini 4 soniga
(21/4) bo‘lishda, javobda 5 butun soni va qoldiq 1 chiqadi.
Qoldiqni olish uchun siz 21 sonini 4 ga qoldiqli bo‘lishingiz kerak
(21% 4), natijada biz 1 qoldig`ini olamiz.
Shunday qilib, 1% 10 ifodasining natijasi 1 ga teng; 2% 10 2 ga
teng va hokazo; va 10% 10 0 ga teng. 11% 10 bo'linishining natijasi
yana 1 ga teng; 12% 10 yana 2 ga teng va hokazo.
47
1-misol:
5 ni 3 ga bo'lganda, javob 1 ga teng.
Bir butun sonni boshqasiga bo‘lganda, natija sifatida siz ham butun
sonni olasiz. Shuning uchun 5/3=1 ga teng.
Kasrli natijani olish uchun haqiqiy sonlardan foydalanish kerak.
5.0 / 3.0 ifodasi kasrli javob beradi: 1.66667.
Turli tipni qo'shish uchun ikkita usul mavjud. Siz eski uslubdan
yoki yangi takomillashtirilgan static_cast operatoridan
foydalanishingiz mumkin. Ikkala variant ham 4.3 Listingida
ko'rsatilgan.
Listing 4.3. O'zgaruvchini float tipiga keltirish
1 #include <iostream>
2 using namespace std;
3 void intDiv(int x, int y)
4{
5 int z = x / y;
6 cout << "z: " << z << endl;
7}
8 void floatDiv(int x, int y)
9{
10 float a = (float)x; // eski uslub
11 float b = static_cast<float>(y); // zamonaviy uslub
12 float c = a / b;
13 cout << "c: " << c << endl;
14 }
15 int main()
16 {
17 int x = 5, y = 3;
18 intDiv(x,y);
19 floatDiv(x, y);
20 return 0;
21 }
Natija:
z: 1
c: 1.66667
Tahlil:
17-qatorda ikkita butun o'zgaruvchi e'lon qilinadi. 18-qatorda ular
parametrlar sifatida intDiv funksiyalari, 19 - qatorda floatDiv
funksiyalari berilgan. Ikkinchi funksiya 9-qator bilan boshlanadi. 10 va
11-qatorlarda butun qiymatlar haqiqiy turga keltiriladi va float tipidagi
o'zgaruvchilarga beriladi. Bo'linish natijasi 12-qatorda float turidagi
uchinchi o'zgaruvchiga o‘zlashtiriladi va 13-qatorda ko'rsatiladi.
48
Agar sizda myAge o'zgaruvchisi bo'lsa va uning qiymatini ikkiga
orttirmoqchi bo'lsangiz, quyidagilarni yozishingiz mumkin:
int myAge = 5;
int temp;
temp = myAge + 2; / / 5 + 2 natijani temp ga qo'ying
myAge = temp; / / yosh qiymatini yana myAgega o‘giradi
Biroq, bu usul haddan tashqari uzun. C++ tilida siz o‘zlashtirish
operatorining ikkala tomoniga bir xil o'zgaruvchini qo'yishingiz
mumkin, masalan, oldingi blok faqat bitta ifodaga qisqartiriladi:
myAge = myAge + 2;
Algebrada bu ifoda ma'nosiz deb hisoblanadi, ammo C++ tilida u
quyidagicha o'qiladi: myAge o'zgaruvchisining qiymatiga ikkini
qo'shing va natijani myAge o'zgaruvchisiga o‘zlashtiring.
Oldingi yozuvning yanada sodda versiyasi mavjud, ammo uni
o'qish qiyinroq:
myAge += 2;
(+=) ushbu o‘zlashtirish operatori r-qiymatni 1-qiymatga qo'shadi,
so'ngra natijani yana l-qiymatiga yozadi. Agar ifoda bajarilishidan oldin
myAge o'zgaruvchisi 4 qiymatga ega bo'lsa, u bajarilgandan so'ng
myAge o'zgaruvchisining qiymati 6 ga teng bo'ladi.
Yig`indi bilan o‘zlashtirish operatoridan tashqari, ayirish ( - = ),
bo'lish ( / = ), ko'paytirish (*=) va qoldiqli (modulli) bo'lish (%=)
bo'lgan o‘zlashtirish operatori ham mavjud.
INKREMENT VA DEKREMENT
Ko'pincha dasturlarda o'zgaruvchilarga birlik qo'shiladi (yoki
ayiriladi). C++ tilida qiymatni 1 ga oshirish , 1 ga kamaytirish
esa deb ataladi. Ushbu harakatlar uchun maxsus operatorlar
taqdim etiladi.
( ++ ) o'zgaruvchining qiymatini 1 ga oshiradi
va (--) uni 1 ga kamaytiradi. Shunday qilib, agar
sizda C o'zgaruvchisi bo'lsa va uni bittaga oshirmoqchi bo'lsangiz,
quyidagi ifodani ishlating:
C++; // C qiymatini birga oshirish
Xuddi shu ifodani quyidagicha yozish mumkin:
C = C + 1;
bu, o'z navbatida, ushbu ifodaga tengdir.
C + = 1;
49
Inkrement operatori ham, dekrement operatori ham ikkita variantda
ishlaydi: . Prefiks o'zgaruvchining nomidan oldin
(++myAge) va postfiks undan keyin (myAge++) yoziladi.
Oddiy ifodada foydalanish unchalik katta ahamiyatga ega emas,
ammo murakkab holda, bitta o'zgaruvchining ortishini amalga
oshirishda, so'ngra natijani boshqa o'zgaruvchiga o‘zlashtirishda bu
juda muhimdir.
Prefiks operatorining semantikasi quyidagicha: bir qiymatni
qo'shish va keyin uni o'qish. Postfiks operatorining semantikasi
boshqacha: qiymatni o'qish va keyin qiymatni 1 ga oshirish.
Agar x qiymati 5 ga teng bo'lgan butun o'zgaruvchisi bo'lsa:
int a = ++x;
ushbu operatorlar bajarilganda, kompilyator x o'zgaruvchiga 1 ni
qo'shadi (u 6 ga teng bo‘ladi) va keyin bu qiymatni a o'zgaruvchiga
o‘zlashtiradi. Shunday qilib, a va x o'zgaruvchining qiymati 6 ga teng.
Agar quyidagicha yozilsa:
int b = x++;
ular kompilyatorga o'zgaruvchining joriy qiymatini o‘zlashtirishni va
keyin o'zgaruvchiga qaytib, uni qo'shish kerakligi aytadi.
Bunday holda, b o'zgaruvchisining qiymati 6 ga tengligi
ko‘rsatiladi, ammo o'zgaruvchining qiymati allaqachon 7 ga teng.
Listing 4.4. ikkala turdagi inkrement va dekrement operatorlaridan
foydalanish ko‘rsatib o‘tilgan.
Listing 4.4. Prefiks va postfiks operatorlari
1 #include <iostream>
2 using namespace std;
3 int main(){
4 int myAge = 39;
5 int yourAge = 39;
6 cout << "I am: " << myAge << " years old.\n";
7 cout << "You are: " << yourAge << " years old\n";
8 myAge++; // postfiks inkrementi
9 ++ yourAge; / / prefiks ortishi
10 cout << "One year passes… n";
11 cout << "I am: " << myAge << " years old.\n":
12 cout << "You are: " << yourAge << " years old\n";
13 cout << "Another year passes\n";
14 cout << "I am: " << myAge++ << " years old.\n";
15 cout << "You are: " << ++yourAge << " years old\n";
16 cout << "Let's print it again.\n";
17 cout << "I am: " << myAge << " years old,\n";
18 cout << "You are: " << yourAge << " years old\n";
50
19 return 0;
20 }
Natija:
I am 39 years old
You are 39 years old
One year passes
I am 40 years old
You are 40 years old
Another year passes
I am 40 years old
You are 41 years old
Let's print it again
I am 41 years old
You are 41 years old
Tahlil:
7 va 8-qatorlarda ikkita butun o'zgaruvchi e'lon qilinadi va ularning
har biri 39 qiymati bilan boshlanadi. Ushbu o'zgaruvchilarning
qiymatlari 9 va 10-qatorlarda ko'rsatiladi.
11-qatorda myAge o'zgaruvchisi postfiks inkrement operatori
bilan, 12-qatorda esa prefiks inkrement operatori yordamida yourAge
o'zgaruvchisi qo'shiladi. Ushbu amallarning natijalari 14 va 15-
qatorlarda keltirilgan; ko'rib turganingizdek, ular bir xil (bizning
tajribamizning ikkala ishtirokchisi ham 40 yoshda).
17-qatorda myAge o'zgaruvchisi (postfiks inkrement operatori
yordamida) qo'shiladi, shu bilan birga ekranda chiqariladi. Bu yerda
operatorning postfiks formasi ishlatilganligi sababli, o'sish chiqarish
amalidan keyin amalga oshiriladi, shuning uchun 40 qiymati yana
chiqarildi. Keyin (postfiks varianti bilan taqqoslash uchun) 18-qatorda
prefiks inkrement operatori yordamida yourAge o'zgaruvchisi
qo'shiladi. Ushbu amal ekranga chiqarishdan oldin amalga oshiriladi,
shuning uchun ko'rsatilgan qiymat 41 ga teng.
Nihoyat, 20 va 21-qatorlarda xuddi shu qiymatlar yana ko'rsatiladi.
O'sish endi bajarilmaganligi sababli, myAge o'zgaruvchisining qiymati
endi 41 ga teng.
OPERATORLARNING USTUVOR YO'NALISHLARI
Savol tug`ilishi tabiiy. Qaysi amal (qo'shish yoki ko'paytirish)
birinchi bo'lib murakkab ifodada amalga oshiriladi?
Masalan:
x= 5 + 3 * 8;
51
Agar qo'shish birinchi bo'lib amalga oshirilsa, unda javob 8 * 8
yoki 64 ga teng. Agar ko'paytirish birinchi bo'lib amalga oshirilsa, unda
javob 5 + 24 yoki 29 ga teng.
Har bir operator ustuvor qiymatga ega. Ko'paytirish yig`indiga
qaraganda yuqori ustuvorlikka ega, shuning uchun bu ifodaning
qiymati 29 ga teng.
Agar ikkita matematik operator bir xil ustuvorlikka ega bo'lsa, ular
chapdan o'ngga qarab bajariladi. Shunday qilib, ifodada
x = 5 + 3 + 8 * 9 + 6 * 4;
birinchidan, ko'paytirish hisoblab chiqiladi va chapdan o'ngga:
8*9 = 72 va 6*4 = 24. Endi xuddi shu ifoda osonroq ko'rinadi:
x = 5 + 3 + 72 + 24;
Keyin yig`indi, chapdan o'ngga bajariladi: 5 + 3 = 8; 8 + 72 = 80; 80 +
24 = 104.
Biroq, barcha operatorlar ushbu tartibiga rioya qilmaydi. Masalan,
o‘zlashtirish operatorlari o'ngdan chapga hisoblanadi! Ifodani ko'rib
chiqing:
TotalSeconds = NumMinutesToThink + NumMinutesToType *60;
Aytaylik, ushbu ifodada siz NumMinutesToType
o'zgaruvchisining qiymatini 60 soniga ko'paytirmoqchi emassiz va
keyin natijani NumMinutesToThink o'zgaruvchisining qiymati bilan
qo'shishni xohlamaysiz. Daqiqalarning umumiy sonini olish uchun
avval ikkita o'zgaruvchining qiymatlarini qo'shishingiz, so'ngra bu
sonni 60 ga ko'paytirib va shu bilan soniyalarning umumiy sonini
olishingiz kerak.
Bunday holda, operatorlarning ustuvorligi bilan belgilangan
amallarni bajarish tartibini o'zgartirish uchun siz qavslardan
foydalanishingiz kerak. Qavsga olingan elementlar boshqa matematik
operatorlarga qaraganda yuqori ustuvorlikka ega. Shuning uchun, ifoda
ushbu ko‘rinishda yozilishi kerak:
TotalSeconds = (NumMinutesToThink + NumMinutesToType) * 60;
Murakkab ifodalarni yaratishda qavs qo'yish kerak bo‘lishi
mumkin. Masalan, soniyalarning umumiy sonini, so'ngra ko'rib
chiqarishga kiritilgan odamlarning umumiy sonini hisoblashingiz va
shundan keyingina bu sonlarni ko'paytirishingiz kerak:
52
TotalPersonSeconds = ( ( (NumMinutesToThink +
NumMinutesToType) * 60) * (PeopleInTheOffice +
People0nVacation) );
53
C++ tilining oldingi versiyalarida mantiqiy ifodalarning natijalari
butun sonlar bilan ifodalangan, ammo yangi ANSI standartida faqat
ikkita mumkin bo'lgan qiymatga ega bo'lgan yangi-bool tipi joriy
qilingan: true yoki false.
ESLATMA: Ko'pgina kompilyatorlar ilgari bool tipiga
yo'naltirilgan bo'lib, u long int tipi bilan ichki ko'rinishda taqdim etilgan
va shuning uchun hajmi to'rt baytga teng edi. Endi ANSI-ga mos
keladigan kompilyatorlar ko'pincha bir baytli bool tipini taqdim
etadilar.
TAQQOSLASH OPERATORLARI
ikkita qiymatning tengligi yoki
tengsizligini aniqlash uchun ishlatiladi. Taqqoslash ifodalari har doim
true (true) yoki false (false) qiymatlarini qaytaradi.
ESLATMA: Yangi ANSI standarti yangi bool tipini taqdim etadi
va barcha shart operatorlari endi bool - true va false tipidagi qiymatni
qaytaradi.
Agar bitta myAge butun o'zgaruvchisi 39 qiymatini, ikkinchisi
sizning butun son o'zgaruvchingiz 40 qiymatini o'z ichiga olsa, u holda
( = = ) tenglik operatoridan foydalanib, ushbu o'zgaruvchilar teng yoki
yo'qligini bilib olishingiz mumkin:
myAge= = yourAge;
Ushbu ifoda 0 yoki false (false) ni qaytaradi, chunki taqqoslangan
o'zgaruvchilar teng emas. Ifoda myAge > yourAge;
shuningdek, 0 (yoki false) ni qaytaradi.
ESLATMA: C++ tilida dasturlashni boshlagan ko'pchilik
o‘zlashtirish operatorini (=) tenglik operatori (==) bilan almashtiradilar.
Noto'g'ri operatordan tasodifiy foydalanish aniqlash katta xatoga olib
kelishi mumkin.
Umuman olganda, C++ tilida oltita taqqoslash operatori ishlatiladi:
teng ( = = ), kichik ( < ), katta ( > ), kichik yoki teng ( < = ), katta yoki
teng (>=) va teng emas (!=). 4.1-jadvalda nafaqat barcha taqqoslash
operatorlari ro‘yxati keltirilgan, balki ulardan foydalanish misollari
ham keltirilgan.
Tavsiya etiladi!
Esda tutingki, taqqoslash operatorlari true yoki false qiymatini
qaytaradi.
54
Tavsiya etilmaydi!
O‘zlashtirish operatorini (=) tenglik operatori (==) bilan
almashtirmang.
55
5-MAVZU. C++ KIRITISH VA CHIQARISH
OPERATORLARI VA MANTIQIY(BOOLEAN) BILAN
ISHLASH
Kiritish operatorlari
Chiqarish operatorlari
Satrlar
CHIQARISH-KIRITISH OPERATORLAR BILAN
TANISHISH
C++ dasturlash tili ma'lumotlarning ekranda yoki faylda qanday
ko'rsatilishini yoki dastur tomonidan qanday o'qilishini aniq
belgilamaydi. Shunga qaramay, bu xususiyatlar dasturchi ishining
muhim qismidir, shuning uchun C++ standart kutubxonasi
kutubxonasini o'z ichiga oladi, bu kiritish- chiqarish (input-output) ni
soddalashtiradi.
ESLATMA: -bu qo'shimcha funksiyalar uchun
dasturga ulanishi mumkin bo'lgan .obj fayllari to'plami.
Iostream sinflari dastur tomonidan ekranda ko'rsatilgan
ma'lumotlarni bitma-bit ma'lumotlar operatori sifatida ko'rib chiqadi.
Oqimlardan foydalanishning asosiy maqsadlaridan biri bu
ma'lumotlarni disk yoki kompyuter displeyi bilan sinxronlashtirishdir.
Dasturning o'zi faqat ushbu jarayonlarni amalga oshiradigan operatorlar
bilan ishlaydi. Sxematik ravishda, bu g'oya 5.1-rasmda tasvirlangan.
57
DOS va UNIX operatsion tizimlarida maxsus kirish (<) va chiqarish (>)
yo'naltirish operatorlari qo'llaniladi.
DOS operatsion tizimida chiqarish (>) va kiritish (<) uchun
cheklangan yo'naltirish buyruqlari to'plami mavjud. UNIX tizimining
yo'naltirish buyruqlari xilma-xildir, ammo asosiy g'oya bir xil bo'lib
qoladi: ma'lumotlar ekranda ko'rsatiladi, faylga yoziladi yoki boshqa
dasturga uzatiladi. Dasturga kirish fayllardan yoki klaviaturadan
amalga oshiriladi.
Umuman olganda, yo'naltirish iostream kutubxonalariga emas,
balki operatsion tizimning funksiyalariga ko'proq tegishli. C++ tili
to'rtta standart qurilmaga kirish va kiritish-chiqarish qurilmalarini
yo'naltirish uchun kerakli buyruqlar to'plamini taqdim etadi.
58
E'tibor bering, parametr havola sifatida uzatilganligi sababli, kirish
operatori asl o'zgaruvchini o'zgartirishi mumkin. Cin dan foydalanish
Listing 5.1 da ko'rsatilgan.
Listing 5.1. Har xil tipdagi ma'lumotlarni kiritish uchun cin
operatoridan foydalanish
1 #include<iostream>
2 using namespace std;
3 int main()
4 { int myInt;
5 long myLong;
6 double myDouble;
7 float myFloat;
8 unsigned int myUnsigned;
9 cout<<"int:"; cin>>myInt;
10 cout<<"Long:"; cin>>myLong;
11 cout<<"Double:"; cin>>myDouble;
12 cout<<"Float:"; cin>>myFloat;
13 cout<<"Unsigned:"; cin>>myUnsigned;
14 cout<<"\n\nInt:\t"<<myInt<<endl;
15 cout<<"Long:\t"<<myLong<<endl;
16 cout<<"Double:\t"<<myDouble<<endl;
17 cout<<"Float:\t"<<myFloat<<endl;
18 cout<<"Unsigned:\t"<<myUnsigned<<endl;
19 return 0; }
Natija:
int:2
Long:7000
Double:987654321
Float:3.33
Unsigned:25
int:2
Long:7000
Double:9.8765e+08
Float:3
Unsigned:25
Cin obyekti, shuningdek, belgilar qatoriga ko'rsatgichni (char)
argument sifatida qabul qilishi mumkin, bu sizga belgilar buferini
yaratishga va uni cin bilan to‘ldirishga imkon beradi. Masalan, siz
quyidagilarni yozishingiz mumkin:
char YourName[50];
cout << "Enter your name;
cin >> Your Name;
59
Agar siz Jesse nomini kiritsangiz, YourName o'zgaruvchisi J, e, s,
s, e va \0 belgilar bilan to‘ldiriladi. Oxirgi belgi nol belgisi bo'ladi,
chunki cin uni avtomatik ravishda kiritadi.
SATRLARNI KIRITISHDA YUZAGA KELADIGAN
MUAMMOLAR
Cin obyekti bilan ilgari tavsiflangan barcha amallarni
muvaffaqiyatli bajarganingizdan so'ng, satrga to'liq ismni kiritishga
harakat qilsangiz, bu amalga oshirishda xatolik beradi. Gap shundaki,
cin bo‘sh joyni sukut bo'yicha berilgan satr ajratuvchi sifatida ko'rib
chiqadi. Satrda bo'sh joy aniqlangandan so'ng, satrni kiritish oxirgi nol
belgini qo'shish bilan yakunlanadi. Ushbu muammo listing 5.2 da
ko'rsatilgan.
Listing 5.2. Cin yordamida bir nechta so'zlarni kiritish
1 #include<iostream>
2 using namespace std;
3 int main()
4 { char YourName[50];
5 cout<<"Your first name:";
6 cin>>YourName;
7 cout<<"Here it is:"<<YourName<<endl;
8 cout<<"Your entire name:";
9 cin>>YourName;
10 cout<<"Here it is:"<<YourName;
11 return 0;}
Natija:
Your first name:Madina
Here it is: Madina
Your entire name: Madina Bobojonova
Here it is: Madina Bobojonova
Listing 5.3. Qiymatlar qatorini kiritish
1 #include <iostream>
2 unsigned int myUnsigned;
3 char using namespace std;
4 int main()
5 {int myInt;
6 long myLong;
7 double myDouble;
8 float myFloat;
9 myWord[50];
10 cout << "int:"; cin >> myInt;
11 cout << "Long:"; cin >> myLong;
12 cout << "Double: ";cin >> myDouble;
13 cout << "Float: ";cin >> myFloat;
14 cout << "Word: ";cin >> myWord;
15 cout << "Unsigned: ";cin >> myUnsigned;
60
16 cout <<"\n\nInt:\t" << myInt << endl;
17 cout << "Long:\t" << myLong << endl;
18 cout << "Double:\t" << myDouble << endl;
19 cout << "Float:\t" << myFloat << endl;
20 cout << "Word:\t" << myWord << endl;
21 cout << "Unsigned:\t" << myUnsigned << endl;
22 cout << "\n\nInt, Long, Double, Float, Word, Unsigned: ";
23 cin >> myInt >> myLong >> myDouble;
24 cin >> myFloat >> myWord >> myUnsigned;
25 cout << "\n\nInt:\t" << myInt << endl;
26 cout << "Long:\t" << myLong << endl;
27 cout << "Double:\t" << myDouble << endl;
28 cout << "Float:\t" << myFloat << endl;
29 cout << "Word:\t" << myWord << endl;
30 cout << "Unsigned:\t" << myUnsigned << endl;
31 return 0;}
Natija:
int:2
Long:30303
Double:393939397834
Float:3.33
Word: Hello
Unsigned:85
int:2
Long:30303
Double:393939397834
Float:3.33
Word: Hello
Unsigned:85
Int, Long, Double, Float, Word, Unsigned: 3 304938 393847473
6.66 bye -2
int:3
Long: 304938
Double:3.93939397e+08
Float:6.66
Word: bye
Unsigned:4294967294
cin istream obyekti bo'lganligi sababli, bitta kiritish amalining
natijasi quyida ko'rsatilganidek, keyingi kiritish amalining boshlanishi
bo‘lishi mumkin:
Int VarOne, varTwo, varThree;
cout << "Enter three numbers: ";
cin >> VarOne >> varTwo >> varThree;
cin >> VarOne >> varTwo >> varThree; qatorida birinchi kirish
cin >> VarOne tomonidan amalga oshiriladi, natijada istream obyekti
qaytib keladi va varTwo o'zgaruvchisiga ikkinchi qiymatni
o‘zlashtirishga imkon beradi. Bu quyidagi yozuvga teng:
61
((cin >> VarOne) >> varTwo) >> varThree;
Belgiga havolani qabul qiladigan operator >> standart kirish
moslamasidan bitta belgini o'qish uchun ishlatilishi mumkin. Buning
uchun get () a'zo funksiyasidan foydalaniladi. Bunday holda siz
parametrlarsiz get() dan foydalanishingiz yoki parametr sifatida belgi
havolasini qabul qiladigan xuddi shu funksiyaning variantidan
foydalanishingiz mumkin.
62
PARAMETRLI GET () FUNKSIYASIDAN FOYDALANISH
Get() funksiyasida belgi o'zgaruvchisini ko'rsatadigan parametr
o'rnatilganda, ushbu o'zgaruvchiga keyingi kirish operatori belgisi
beriladi. Bu iostream obyektini qaytaradi, bu sizga Listing 5.5 da
ko'rsatilgandek ketma-ket qiymatlarni kiritish imkonini beradi.
Listing 5.5. Parametrlar bilan get () funksiyasidan foydalanish
1 #include <iostream>
2 using namespace std;
3 int main()
4 { char a,b,c;
5 cout<<"Enter three letter:";
6 cin.get(a).get(b).get(c);
7 cout<<"a:"<<a<<"\nb:"<<b<<"\nc:"<<c<<endl;
8 return 0;}
Natija:
Enter three letter: one
a:o
b:n
c:n
Tavsiya etiladi!
Qatordagi bo‘sh joylar bilan ajratilgan qiymatlarni kiritish
kerak bo'lganda > > kiritish operatoridan foydalaning.
Agar siz satrning barcha belgilarini, shu gapdan bo‘sh
joylarni ketma-ket kiritishingiz kerak bo'lsa, belgi parametri bilan get()
funksiyasidan foydalaning.
STANDART SATRLARNI KIRITISH
Belgilar qatorini to‘ldirish uchun siz kirish operatoridan (>>) va
get() va funksiyalaridan foydalanishingiz mumkin.
get() funksiyasining yana bir varianti uchta parametrni oladi.
Birinchi parametr bu belgilar qatoriga ko'rsatgich, ikkinchisi avtomatik
ravishda qo'shilgan terminal nol belgisini hisobga olgan holda satrdagi
maksimal belgilar sonini bildiradi va uchinchisi satr ajratuvchi
belgilarni belgilaydi.
Agar ikkinchi parametr 20 ga teng bo'lsa, get() funksiyasi 19 ta
belgini kiritadi va birinchi parametr ko'rsatgan satrning kiritilishini
to'xtatadi, shundan so'ng u oxirgi nol belgisini qo'shadi. Uchinchi
parametr sukut bo'yicha yangi qatorga o‘tish sifatida o'rnatiladi ('\n').
Agar ushbu belgi satrning oxirgi ruxsat etilgan belgisi kiritilishidan
63
oldin uchrashsa, funksiya bu joyga terminal nol belgisini kiritadi va
keyingi kirish funksiyasi sifatida o'qiladi.
Listing 5.6. get () funksiyasidan foydalanish
1 #include <iostream>
2 using namespace std;
3 int main()
4 {char stringOne[256];
5 char stringTwo[256];
6 cout<< "Enter string one:";
7 cin.get(stringOne,256);
8 cout<<"stringOne:"<<stringOne<<endl;
9 cout<<"Enter string two:";
10 cin>>stringTwo;
11 cout<<"stringTwo:"<<stringTwo<<endl;
12 return 0;}
Natija:
Enter string one: 2
stringOne:2
Enter string two: 3
stringTwo:3
Listing 5.7. Getline () funksiyasidan foydalanish
1 #include <iostream>
2 using namespace std;
3 int main(){
4 char stringOne[256];
5 char stringTwo[256];
6 char stringThree[256];
7 cout<< "Enter string one:";
8 cin.get(stringOne,256);
9 cout<<"stringOne:"<<stringOne<<endl;
10 cout<<"Enter string two:";
11 cin>>stringTwo;
12 cout<<"stringTwo:"<<stringTwo<<endl;
13 cout<<"Enter string three:";
14 cin.get(stringThree,256);
15 cout<<"stringThree:"<<stringThree<<endl;
16 return 0; }
Natija:
Enter string one: 2
stringOne:2
Enter string two: 3
stringTwo:3
Enter string three: stringThree:
COUT YORDAMIDA MA'LUMOTLARNI CHIQARISH
Siz ilgari ni chiqarish operatori (<<) bilan birga sonlar
va boshqa ma'lumotlarni ko'rsatish uchun ishlatgansiz. Ushbu obyekt
64
shuningdek ma'lumotlarni formatlash, ustunlarni tekislash va sonli
qiymatlarni o'nlik va o'n oltilik formatda chiqarish imkonini beradi.
Siz to'g'ridan-to'g'ri flush o‘zgaruvchisining qiymatini chiqarishni
quyidagi operator orqali chaqirishingiz mumkin:
cout << flush;
Ushbu usul, agar undagi barcha ma'lumotlar ekranda
ko'rsatilmagan bo'lsa, chiqarish buferini aniq tozalashga imkon beradi.
COUT OBYEKTINING FUNKSIYA A'ZOLARI
Cin get() va getline () obyekt usullariga qanday murojaat
qilganimizga o'xshab, cout obyekti bilan put() va write ()
funksiyalaridan foydalanish mumkin.
Put () funksiyasi standart chiqarish qurilmasiga bitta belgini
chiqaradi. Ushbu funksiya ostream ga havolani qaytarganligi sababli,
cout ostream obyekti hisoblanadi, ma'lumotlarni kiritishda bo'lgani kabi
bir qator qiymatlarni chiqarish uchun put() funksiyasiga ketma-ket
murojaat qilish mumkin.
65
Listing 5.9. Chiqarish maydonining kengligini sozlash
1 #include<iostream>
2 #include<math.h>
3 using namespace std;
4 int main()
5{
6 cout<<"start>";
7 cout.width(25);
8 cout<<123<<"<end\n";
9 cout<<"start>";
10 cout.width(25);
11 cout<<123<<"<next>";
12 cout<<456<<"<end\n";
13 cout<<"start>";
14 cout.width(4);
15 cout<<123456<<"<end\n";
16 return 0;
17 }
Odatda, cout obyekti yuqoridagi misolda ko'rsatilgandek width ()
funksiyasi tomonidan berilgan bo'sh maydon pozitsiyalarini bo‘sh
joylar bilan to‘ldiradi. Biroq, ba'zida bo'sh joylarni boshqa belgilar
bilan to‘ldirish kerak bo'ladi, masalan, yulduzcha (*).
Listing 5.10. Fill () funksiyasidan foydalanish
1 #include<iostream>
2 #include<math.h>
3 using namespace std;
4 int main()
5{
6 cout<<"start>";
7 cout.width(25);
8 cout<<123<<"<end\n";
9 cout<<"start>";
10 cout.width(25);
11 cout.fill('*');
12 cout<<123<<"<end\n";
13 return 0;
14 }
66
Listing 5.11. Printf () funksiyasi
1 {
2 printf("%s","hello world\n");
3 char*phrase="hello again!\n";
4 printf("%s",phrase);
5 int x=5;
6 printf("%d\n",x);
7 char*phrasetwo="here's some values:";
8 char*phrasethree="and also these:";
9 int y=7,z=35;
10 long longvar=98456;
11 float floatvar=8.8f;
12 printf("%s %d %s %ld %f\n",phrasetwo,y,z,phrasethree,longvar,floatvar);
13 char*phrasefour="formatted";
14 printf("%s %5d %10d %10.5f\n",phrasefour,y,z,floatvar);
15 return 0;
16 }
69
6-MAVZU. C++ TILIDA SHART OPERATORLAR
If operatori
Else operatori
Mantiqiy operatorlar
Odatda, dastur ketma-ket bajariladi. shartni tekshirishga
imkon beradi (masalan, ikkita o'zgaruvchining tengligi) va taqqoslash
natijasiga bog'liq bo'lgan boshqa kanalga yo'naltirish orqali dasturning
bajarilishini o'zgartiradi.
If operatorining eng oddiy ko‘rinishi quyidagicha:
If(shart)
ifoda;
Qavs ichidagi shart har qanday ifoda bo‘lishi mumkin, lekin odatda
munosabatlar operatorlarini o'z ichiga oladi. Agar bu ifoda noto'g'ri
bo'lsa, keyingi operator o'tkazib yuboriladi. Agar u rost qiymatini
qaytarsa, u holda operator bajariladi. Quyidagi misolni ko'rib chiqing:
if (bigNumber > smallNumber)
bigNumber = smallNumber;
Bu yerda bigNumber va smallNumber o'zgaruvchilarining
qiymatlari taqqoslanadi. Agar bigNumber o'zgaruvchisining qiymati
kattaroq bo'lsa, unda ushbu dastur parchasining ikkinchi qatorida uning
qiymati smallNumber o'zgaruvchisining qiymatiga teng bo'ladi.
Qavsga olingan ifodalar bloki bitta ifodaga teng bo'lganligi sababli,
bu xususiyat if operatori bilan satr ortida juda keng bo‘lishi mumkin
bo'lgan butun bloklardan foydalanishga imkon beradi:
if(shart)
{
ifoda1;
ifoda2;
ifoda3
}
Ifoda blokini qo'llashning oddiy misoli:
if (bigNumber > smallNumber)
{
bigNumber = smallNumber;
cout << "bigNumber: " << bigNumber << "\n";
cout << "smallNumber: " << smallNumber << "\n";
}
Bu safar, agar bigNumber o'zgaruvchisining qiymati smallNumber
o'zgaruvchisining qiymatidan katta bo'lsa, unda katta o'zgaruvchi
nafaqat kichik o'zgaruvchining qiymatiga teng o'rnatiladi, balki ekranda
satrlar ham ko'rsatiladi. Listing 6.1 munosabatlar operatorlaridan
70
foydalanishga asoslangan dastur tarmoqlanishining yana bir misolini
ko'rsatadi.
Listing 6.1. Shart operatorlari misoli
1 #include <iostream>
2 using namespace std;
3 int main(){
4 int RedSoxScore, YankeesScore;
5 cout << "Enter the score for the Red Sox: ";
6 cin >> RedSoxScore;
7 cout << "\nEnter the score for the Yankees: "
8 cin >> YankeesScore;
9 cout << " n";
10 if (RedSoxScore > YankeesScore)
11 cout << "Go Sox!\n";
12 if (RedSoxScore < YankeesScore)
13 {
14 cout << "Go Yankees!\n";
15 cout << "Happy days in New York!\n";
16 }
17 if (RedSoxScore == YankeesScore)
18 {
19 cout << "A tie? Naah, can't be.\n";
20 cout << "Give me the real score for the Yanks: ";
21 cin >> YankeesScore;
22 if (RedSoxScore > YankeesScore)
23 cout << "Knew it! Go Sox!";
24 if (YankeesScore > RedSoxScore)
25 cout << "Knew it! Go Yanks!";
26 if (YankeesScore == RedSoxScore)
27 cout << "Wow, it really was a tie!";
28 }
29 cout << "\nThanks for telling me.\n";
30 return 0;
31 }
Natija:
Enter the score for the Red Sox: 10
Enter the score for the Yankees: 10
A tie? Naah, can't be
Give me the real score for the Yanks: 8
Knew it! Go Sox!
Thanks for telling me…
Tahlil:
Ushbu dasturda foydalanuvchidan ikkita beysbol jamoasi uchun
ball hisobini kiritish so'raladi. Kiritilgan ballar butun sonli
o'zgaruvchilarda saqlanadi. Ushbu o'zgaruvchilarning qiymatlari if
operatori tomonidan 15, 18 va 24-qatorlarda taqqoslanadi.
71
ESLATMA:Ko'pgina boshlang'ich dasturchilar if ifodasi bilan
ifodalanganidan keyin beparvolik bilan nuqta-vergul qo'yadilar. Bu esa
xatolikka olib keladi.
if(SomeValue < 10);
SomeValue = 10;
73
Natija:
Please enter a big number: 10
Please enter a smaller number: 12
Oops. The second is bigger!
Tahlil:
11-qatorda if ifodasida ko'rsatilgan shart tekshiriladi. Agar bu shart
to'g'ri bo'lsa, 12-qator bajariladi. Agar ushbu shart noto'g'ri bo'lsa,
dastur 14-qatordan ishlashni davom ettiradi. Agar 13-qatorda else kalit
so'zi o'chirilsa, shart bajarilishidan qat'i nazar, 14-qator har qanday
holatda ham bajariladi. Ammo ushbu dasturda if-else if dan keyin blok
yoki else dan keyin blok bajariladi.
IF OPERATORI
Quyida keltirilgan.
1-misol:
if (shart)
{
ifoda;
quyidagi ifoda;
}
Agar shart rost bo'lsa, unda ifoda bajariladi va undan keyin keyingi
ifoda bajariladi. Agar shart noto'g'ri bo'lsa, unda ifoda e'tiborga
olinmaydi va dastur keyingi ifodani bajarishga o'tadi.
Esda tutingki, ifoda o'rniga figurali qavsga olingan butun blok
ishlatilishi mumkin.
2-misol:
if (shart)
ifoda1;
else
ifoda2;
boshqa ifoda;
74
ICHMA-ICH SHART OPERATORLARI
If-else blokidagi ifoda bloklaridagi har qanday operatorlardan
foydalanishda yana qo'shimcha if va else operatorlaridan foydalanishda
hech qanday cheklovlar yo'q. Bunday holda, bir nechta if operatorlari
ichma-ich joylashgan:
if (shart1)
{
if (shart2)
ifoda1;
else
{
if (shart3)
ifoda2;
else
ifoda3;
}
}
else
ifoda4;
Ushbu dasturni quyidagicha tushunish mumkin: agar shart1 to'g'ri
va shart2 to'g'ri bo'lsa, ifoda1 ni bajaring. Agar shart1 rost bo'lsa va
shart2 rost bo'lmasa, shart3 ni tekshiriladi va agar rost bo'lsa, ifoda2 ni
bajariladi. Agar shart1 to'g'ri bo'lsa va shart2 va shart3 bo'lmasa, unda
ifoda3 ni bajariladi. Nihoyat, agar shart1 noto'g'ri bo'lsa, ifoda 4
bajariladi.
Bunday murakkab loyihalashni ichma-ich if ifodalari bilan
ishlatish misoli Listing 6.3 da ko'rsatilgan.
Listing 6.3. Ichma-ich If operatorlari bilan ishlashga misol
1 #include <iostream>
2 using namespace std;
3 int main(){
4 int firstNumber, secondNumber;
5 cout << "Enter two numbers.\nFirst: ";
6 cin >> firstNumber;
7 cout << " nSecond: "
8 cin >> secondNumber;
9 cout << "\n\n";
10 if (firstNumber >= secondNumber)
11 {
12 if ( (firstNumber % secondNumber) == 0)
13 {
14 if (firstNumber == secondNumber)
15 cout << "They are the same!\n";
75
16 else
17 cout << "They are evenly divisible!\n";
18 }
19 else
20 cout << "They are not evenly divisible!\n";
21 }
22 else
23 cout << "Hey! The second one is larger!\n";
24 return 0;
25 }
Natija:
Enter two numbers.
First: 10
Second: 2
They are evenly divisible!
Tahlil:
Birinchidan, foydalanuvchidan ikkita sonni kiritish so'raladi
(navbat bilan), keyin bu sonlar taqqoslanadi. Birinchi if ifodasi bilan
(17-qatorda) biz birinchi son ikkinchisidan katta yoki teng ekanligini
tekshiramiz. Agar shart yolg`on bo'lsa, unda ifoda 29-qatorda
ko'rsatilgan else operatoridan keyin amalga oshiriladi.
Agar birinchi taqqoslash rost bo'lsa, u holda 18-qatordan
boshlanadigan ko'rsatmalar bloki bajariladi, bu yerda 19-qatordagi
ikkinchi if operatoridan foydalanib, birinchi son ikkinchisiga qoldiqsiz
bo'linishi tekshiriladi (ya'ni qoldiq nolga teng). Agar bu shart
tasdiqlansa, unda birinchi son ikkinchisiga tengligi tekshiriladi. 21-
qatordagi if operatorida sonlarning tengligi tekshiriladi va keyin
ekranda sonlar tengligi xabar paydo bo'ladi.
Agar 19-qatordagi if ifodasi false qiymatini qaytarsa, u holda 26-
qatorda else ifodasi bajariladi.
Bu quyida ko'rsatilganidek, bir nechta if operatorlarini qo‘llashda
ham amal qiladi:
if (x > y) / / agar x y dan katta bo'lsa
if (x < z) / / va agar x z dan kichik bo'lsa,
x=y; / / keyin x qiymatini y ga o‘zlashtiring
Biroq, figurali qavslardan foydalanmasdan murakkab ichma-ich
shartlarni yaratishda, qaysi ifoda if operatoriga tegishli ekanligini
aniqlash qiyin bo‘lishi mumkin.
Shuni unutmangki, bo‘sh joylar dasturchi uchun dasturni tushunarli
qiladi, ammo kompilyatorning ishlashiga ta'sir qilmaydi. Listing 6.4 da
boshqa hol ko'rsatilgan.
Listing 6.4. Else-if operatorlaridan foydalanishga misol
76
1 #include <iostream>
2 using namespace std;
3 int main(){
4 int x;
5 cout << " a number less than 10 or greater than 100: ";
6 cin >> x;
7 cout << "\n";
8 if (x >= 10)
9 if (x > 100)
10 cout << "More than 100, Thanks!\n";
11 else // ushbu operator qaysi if operatoriga tegishli
12 cout << "Less than 10, Thanks!\n";
13 return 0;
14 }
Natija:
Enter a number less than 10 or greater than 100: 20
Less than 10, Thanks!
Tahlil:
Dastur 10 dan kichik yoki 100 dan katta sonni kiritishni so'raydi va
kiritilgan qiymatni talab qilingan shartga muvofiqligini tekshirishi va
keyin xabarni chiqarishi kerak.
Agar 11-qatorda joylashgan if ifodasi rost bo'lsa, unda 12-
qatordagi ifoda bajariladi. Bizning misolimizda, agar kiritilgan son 10
dan katta bo'lsa, 11-qator bajariladi. Agar bu son 100 dan katta bo'lsa,
12-qator bajariladi.
Agar kiritilgan son 100 dan kichik bo'lsa, 11-qatordagi if ifodasi
false ni qaytaradi. Bunday holda, else (13-qator) ifodasi bajarilishi
kerak, bu esa tegishli xabarni ko'rsatadi. Ammo ma'lum bo‘lishicha,
agar siz 10 dan kichik sonni kiritsangiz, dastur shunchaki o'z ishini
tugatadi.
Kompilyator nuqtai nazaridan ushbu C++ dasturida hech qanday
xato yo'q. Dastur mantiqiy xato tufayli xohlagancha ishlamaydi.
Bundan tashqari, ushbu dasturni sinab ko'rsangiz ham, u to'g'ri
ishlayotgandek ko‘rinishi mumkin, chunki 100 dan katta sonni
kiritishda dastur normal ishlaydi va xato ko‘rinmaydi.
Listing 6.5. If operatori bilan dasturlash
1 #include <iostream>
2 using namespace std;
3 int main(){
4 int x;
5 cout << "a number less than 10 or greater than 100: ";
6 cin >> x;
7 cout << "\n";
77
8 if (x >= 10)
9{
10 if (x > 100)
11 cout << "More than 100, Thanks!\n";
12 }
13 else
14 cout << "Less than 10, Thanks!\n";
15 return 0;
16 }
Natija:
Enter a number less than 10 or greater than 100: 20
Tahlil:
11 va 14-qatorlardagi figurali qavslar orasidagi hamma narsani
bitta ifodaga aylantiradi va endi 15-qatordagi else operatori 10-qatorda
turgan if ifodasi bilan aniq bog'langan.
Foydalanuvchi 20 sonini kiritdi, shuning uchun 10-qatordagi if
ifodasi true qiymatini qaytaradi ammo, 12-qatordagi if ifodasi false ni
qaytardi, shuning uchun xabar ekranda ko'rinmadi. Agar dasturchi 13-
qatordan keyin boshqa else operatoridan foydalansa yaxshi bo'lardi, u
kiritilgan son talablarga javob bermasligi haqida xabar beradi.
MANTIQIY OPERATORLAR
Ko'pincha biz bitta shartli ifodani emas, balki bir vaqtning o'zida
bir nechtasini tekshirishimiz kerak. Masalan, x y dan kattami yoki y z
dan kichikmi? Bizning dasturimiz, tegishli harakatni amalga
oshirishdan oldin, ushbu ikkala shart ham to'g'ri yoki ulardan biri
noto'g'ri ekanligini aniqlashi kerak.
Operator Nomi Misol
&& va Ifoda1 && ifoda2
|| yoki Ifoda1 || ifoda2
! inkor ! ifoda1
Jadval 4.2. Mantiqiy operatorlar
MANTIQIY VA
ikkita ifodani hisoblab chiqadi va agar ikkala
ifoda ham rostni qaytarsa, u holda operator ham rostni qaytaradi. Agar
ochligingiz rost bo'lsa va pulingiz borligi ham rost bo'lsa,
supermarketga borib, tushlik uchun o'zingizga biror narsa sotib
olishingiz ham to‘g`ri. Masalan, mantiqiy ifoda
78
if ( (x == 5) && (y == 5) )
agar ikkala o'zgaruvchi x=5 va y=5 bo'lsa, true qiymatini qaytaradi.
Agar o'zgaruvchilardan kamida bittasi 5 ga teng bo'lmasa, ifoda false
qaytadi. E'tibor bering, ifoda faqat uning ikkala qismi ham to'g'ri bo'lsa,
rostni qaytaradi.
MANTIQIY YOKI
ikkita ifodani ham hisoblab chiqadi. Agar
ulardan biri rost bo'lsa, u holda operator yoki true-ni qaytaradi. Agar
sizda pul bo'lsa yoki kredit kartangiz bo'lsa, hisobni to'lashingiz
mumkin. Shu bilan birga, bir vaqtning o'zida ikkita shartga rioya
qilishning hojati yo'q: pul va kredit kartasiga ega bo‘lish. Ulardan birini
bajarish sizga kifoya qiladi (garchi ikkalasi birgalikda yaxshiroq bo'lsa
ham). Masalan, ifoda
if ( (x == 5) || (y == 5) )
agar x o'zgaruvchining qiymati yoki y o'zgaruvchining qiymati yoki
ikkalasi ham 5 bo'lsa, true qiymatini qaytaradi.
Iltimos, diqqat qiling: mantiqiy yoki operatori || ikkita belgi bilan
ko'rsatilgan. Bitta belgi bilan ko'rsatilgan operator mutlaqo boshqa
operator.
MANTIQIY INKOR
agar ifoda false bo'lsa (noto'g'ri qiymatga
ega bo'lsa) true qiymatini qaytaradi. Aksincha, agar sinovdan o'tgan
ifoda rost bo'lsa, inkor operatori false ni qaytaradi! Masalan, ifoda
if ( !(x == 5) )
79
bu yerda birinchi ifoda to'g'ri bo'ladi (×=5), keyin kompilyator ikkinchi
ifodani ham hisoblamaydi (y = 5), chunki butun ifodani to‘g`ri deb olish
uchun bitta to‘g`ri natija yetarli.
Shart operatorlari va mantiqiy operatorlar C++ tilidagi ifodalarda
ishlatiladi va true yoki false qiymatlarini qaytaradi. Boshqa barcha
operatorlar kabi, ular ham munosabatlar operatorlarini hisoblash
tartibini belgilaydigan ma'lum bir ustuvorlik darajasiga ega. Bunday
ifodaning ma'nosini aniqlashda ushbu fikrni hisobga olish kerak
if ( x > 5 && y > 5 || z > 5)
Bunday holda, dasturchining maqsadi haqida faqat taxmin qilish
mumkin. Ehtimol, bu ifoda x va y 5 dan katta bo'lsa yoki z 5 dan katta
bo'lsa, true qiymatini qaytarishini xohlagan bo‘lishi mumkin. Boshqa
tomondan, ehtimol dasturchi bu ifodani faqat x 5 dan katta bo'lsa va y
yoki z 5 dan katta bo'lsa, to'g'ri qaytarishini xohlagan bo‘lishi mumkin.
Agar x 3 ga teng bo'lsa va y va z ikkalasi ham 10 ga teng bo'lsa, u
holda 2-taxmin uchun ushbu ifoda true qiymatini qaytaradi (z 5 dan
katta, shuning uchun biz x va y qiymatlarini e'tiborsiz qoldiramiz), lekin
birinchi talqindan foydalanganda false qiymati qaytadi (u true qiymatini
bera olmaydi, chunki bu x qiymati 5 dan katta edi va bu rostni
aniqlagandan so'ng, && operatorining o'ng tomonidagi ifodani
hisoblash natijasi muhim emas, chunki butun ifodaning rosti uchun
uning ikkala qismi ham to'g'ri bo‘lishi kerak).
Bunday ifodalarda operatorlarning ustuvorliklarini tushunish juda
qiyin, shuning uchun siz qavslardan foydalanishingiz kerak, chunki
ularning yordami bilan siz nafaqat ularning ustuvorliklari tufayli
operatorlarning ketma-ketligini o'zgartirishingiz, balki bunday
chalkash ifodalarni ham aniq qilishingiz mumkin:
if ( (x > 5) && (y > 5 || z > 5) )
Yuqoridagi qiymatlardan foydalanganda, bu ifoda false qiymatini
qaytaradi. Ma'lum bo‘lishicha, x (uning qiymati 3 ga teng) 5 dan
oshmaydi, keyin ifoda operatorning chap tomonida false ni qaytaradi va
shuning uchun butun ifoda ham false ni qaytaradi. Shuni esda tutingki,
ifodaning ikkala qismi ham trueni qaytargan taqdirdagina operator
trueni qaytaradi. Misol uchun, agar siz kiygan narsangiz haqida uni
zamonaviy deb ayta olsangiz va u sizga mos kelsa, sizning didingiz
yaxshi deb hisoblanishi mumkin.
ESLATMA: Ko'pincha, qo'shimcha qavslar faqat aniq nimani
guruhlashni xohlayotganingizni aniqlash uchun ishlatilishi kerak. Esda
80
tutingki, dasturchining maqsadi yaxshi ishlaydigan, shuningdek o'qish
va tushunish oson bo'lgan dastur yozishdir.
TRUE VA FALSE HAQIDA KO'PROQ MA'LUMOT
C++ da nol false qiymatiga teng, boshqa barcha sonli qiymatlar esa
true qiymatiga teng. Har qanday ifoda har doim muhim bo'lganligi
sababli, ko'plab dasturchilar ushbu qiymat ekvivalentligidan if
operatorining shart ifodalarida foydalanadilar. Masalan,
if (x)
// agar x nolga teng bo'lmasa, unda shart to'g'ri
x = 0;
buni quyidagicha o'qish mumkin: agar x o'zgaruvchisi nolga teng
bo'lmasa, unga nol qiymatini o‘zlashtiramiz. Ushbu ifodaning
ma'nosini yanada aniqroq qilish uchun uni quyidagicha yozishingiz
mumkin:
if (x != 0) / / agar x nol bo'lmasa
x = 0;
Ikkala ifoda ham bir xil natija qaytaradi, ammo ikkinchisi aniqroq.
Dastur o‘zgarmas mavhum bo‘lib qolmasligi uchun, ifoda nolga teng
emas, balki ba'zi mantiqiy shartlarning rostini tekshirish yaxshiroqdir.
Quyidagi ikkita ifoda ham tengdir:
if (!x)
// to'g'ri, agar x nolga teng bo'lsa
agar (x == 0) // agar nolga teng bo'lsa
Biroq, ikkinchi ifoda tushunish uchun yaxshiroqdir va juda aniq,
chunki x o'zgaruvchisining matematik qiymati aniq tekshiriladi.
Tavsiya etiladi!
Ifodalarni bajarish tartibini aniqroq ko'rsatish yoki ularning
ustuvor yo'nalishlarini o'zgartirish uchun qavslardan foydalaning.
Dastur qismlari o'rtasidagi munosabatlarni aniqlash va
xatolarga yo'l qo'ymaslik uchun ichma-ich if operatorlari bilan
foydalanishda figurali qavslardan foydalaning.
Tavsiya etilmaydi!
If(x) ifodasini if(x != 0) ning o‘rniga qo‘llamang. Oxirgi
variant afzalroqdir, chunki shartni tekshirish mantig'i aniqroq ko'rinadi.
If(!x) ifodasini if(x ==0) ifodasining ekvivalenti sifatida
ishlatmang. Oxirgi variant afzalroqdir, chunki shartni tekshirish
mantig'i aniqroq ko'rinadi.
81
TERNAR OPERATOR
bir vaqtning o'zida uchta operand bilan
ishlaydigan C++ tilidagi yagona operator. Ternar operatordan
foydalanish sintaksisi quyidagicha:
(ifoda1)? (ifoda2): (ifoda3)
Ushbu satr quyidagicha o'qiladi: agar ifoda1 true ni qaytarsa,
ifoda2 bajariladi, aks holda ifoda3 bajariladi. Odatda, qaytish qiymati
ma'lum bir o'zgaruvchiga beriladi.
Listing 6.6. Ternar operatordan foydalanishga misol
1 #include <iostream>
2 using namespace std;
3 int main(){
4 int x, y, z;
5 cout << "Enter two numbers.\n";
6 cout << "First: "
7 cin >> x;
8 cout << "\nSecond: "
9 cin >> y;
10 cout << "\n";
11 if (x > y)
12 z = x;
13 else
14 z = y;
15 cout << “z: " << z;
16 cout << "\n";
17 z = (x > y) ? x : y;
18 cout << "z: " << z;
19 cout << "\n";
20 return 0;
21 }
Natija:
Enter two numbers.
First: 5
Second: 8
z: 8
z: 8
Tahlil:
Birinchidan, uchta butun o'zgaruvchilari yaratiladi: x, y va z.
Dastlabki ikkitasining qiymatlari foydalanuvchi tomonidan kiritiladi.
Keyin 13-qatorda if buyrug'i bajariladi, bu sizga kiritilgan
qiymatlarning qaysi biri kattaroq ekanligini bilib olishga imkon beradi
va aniqlangan katta qiymat 3-o'zgaruvchiga beriladi. Ushbu qiymat 17-
qatorda ko'rsatiladi.
82
Xuddi shu tekshirish 19-qatorda shartli operator tomonidan amalga
oshiriladi va z o'zgaruvchisiga katta qiymat beradi. U quyidagicha
o'qiladi: "agar x y dan katta bo'lsa, x qiymatini qaytaring; aks
holda y qiymatini qaytaring." Qaytish qiymati z o'zgaruvchiga beriladi.
ushbu qiymat ekranda 20-qatorda ko'rsatiladi. Ko'rib turganingizdek,
ternar operatorni o'z ichiga olgan ko'rsatma if...else ko'rsatmasining
qisqaroq ekvivalentidir.
Nazorat savollari va topshiriqlar:
1. Ifoda nima?
2. Yozuv x = 5 + 7; ifodami? Uning ma'nosi nima?
3. 201 / 4 ifodasining ma'nosi nima? 201% 4 ifodasining ma'nosi nima?
4. Agar myAge, a va b o'zgaruvchilari int tipiga ega bo'lsa, unda ifoda
bajarilgandan keyin ularning qiymatlari qanday bo'ladi:
myAge = 39;
a = myAge++;
b = ++myAge;
5. if (x = 3) va if(x == 3) ifodalari o'rtasidagi farq nima?
6. Quyidagi ifodalar true yoki false ni qaytaradimi?
a) 0
b) 1
B) - 1
D) x = 0
e) x == 0 qiymatiga ega deb taxmin qiling
7. Ushbu dasturni tahlil qiling va natijani taxmin qiling:
1 #include <iostream>
2 using namespace std;
3 int main(){
4 int a = 1, b = 1, c;
5 if (c = (a-b))
6 cout << "The value of cis: " << c;
7 return 0;
8 }
8. 7-mashqdan dasturni kiriting, kompilyatsiya qiling va ishga
tushiring. Natija qanday bo'ldi? Nima uchun?
83
7-MAVZU. C++ DA TAKRORLASH OPERATORLARI
84
Tahlil:
7-qatorda counter o'zgaruvchisi nol qiymat bilan ishga tushiriladi.
Loop nishoni 8-qatorda takrorlashning boshlanishi ko'rsatilgan. Har bir
iteratsiyada counter qiymati bittaga oshiriladi va ekranda ko'rsatiladi.
10-qatorda counter o'zgaruvchisining qiymati tekshiriladi. Agar u 5 dan
kichik bo'lsa, unda shart bajariladi va boshqaruv goto operatoriga
o'tkaziladi, natijada 8-qatorga o'tish amalga oshiriladi. Iterativ jarayon
counter o'zgaruvchisining qiymati 5 ga yetguncha amalga oshiriladi.
Shundan so'ng, dastur takrorlashdan tashqariga chiqadi va yakuniy
natija ekranda ko'rsatiladi.
yordamida siz dasturning istalgan nuqtasiga oldinga
yoki orqaga o'tishingiz mumkin. Goto operatori biroz murakkabroq
tuzilishga ega, ammo ko'proq imkoniyatlarga ega bo'lgan takrorlash
operatorlari bilan almashtirildi: for, while va do...while.
WHILE OPERATORI YORDAMIDA
TAKRORLASHLARNI TASHKIL QILISH
ning yordami bilan tashkil etilgan takrorlashlarda
amallar ketma-ketligini bajarish takrorlashni davom ettirish sharti to'g'ri
bo'lguncha davom etadi. Listing 7.1 dastur misolida counter
o'zgaruvchisining qiymati 5 ga teng bo'lgunga qadar oshdi. Listing 7.2
da ushbu dastur while operatori yordamida qayta yozilgan.
Listing 7.2. While operatori
1 #include <iostream>
2 using namespace std;
3 int main()
4{
5 int counter = 0;
6 while(counter < 5)
7{
8 counter++;
9 cout << " counter: " << counter << "\n";
10 }
11 cout << " Complete. Counter: " << counter << ".\n";
12 return 0;
13 }
Natija:
counter: 1
counter: 2
counter: 3
counter: 4
counter: 5
Complete. Counter: 5.
85
Tahlil:
Ushbu oddiy dastur while operatori yordamida takrorlashni tashkil
qilish misolini ko'rsatadi. Har bir iteratsiyaning boshida shart
tekshiriladi va agar u bajarilsa, boshqaruv takrorlashning birinchi
operatoriga o'tkaziladi. Bizning misolimizda loopni davom ettirish
sharti 5 dan kichik bo'lgan counter o'zgaruvchisining barcha
qiymatlarini olishdir (8-qator). Agar shart bajarilsa, takrorlashning
keyingi qadami boshlanadi. 10-qatorda sanagich qiymati bittaga oshadi
va 11-qatorda ekranda ko'rsatiladi. Hisoblagich qiymati 5 ga yetgandan
so'ng, takrorlash tanasi (8-12 qatorlar) o'tkazib yuboriladi va boshqaruv
13-qatorga o'tkaziladi.
While operatoridagi shart bo'lgan mantiqiy ifodaning murakkabligi
cheklanmagan. Bu har qanday C++ mantiqiy ifodalarini while operatori
ishlatishga imkon beradi. Ifodalarni tuzishda mantiqiy amallardan
foydalanishga ruxsat beriladi: && (mantiqiy va), || (mantiqiy yoki), !
(mantiqiy inkor). Listing 7.3 while operatorining ishlashiga boshqa
misol berilgan.
Listing 7.3. While ga doir murakkab misol
1 #include<iostream>
2 using namespace std;
3 int main(){
4 unsigned short small;
5 unsigned long large;
6 const unsigned short MAXSMALL=65535;
7 cout << "Enter a small number: ";
8 cin >> small;
9 cout << "Enter a large number: ";
10 cin >> large;
11 cout << "small: " << small <<"...";
12 while (small < large && large > 0 && small < MAXSMALL)
13 { if (small % 5000 == 0)
14 cout << ".";
15 small++;
16 large-=2;}
17 cout << "\nSmall: " << small << " Large: " << large << endl;
18 return 0;}
Natija:
Enter a small number: 2
Enter a large number: 100000
small: 2…
Small: 33335 Large: 33334
86
BREAK VA CONTINUE OPERATORLARI
Ko'pincha takrorlash tanasining barcha operatorlarini bajarish
tugashidan oldin ham takrorlashning keyingi takrorlanishiga o'tish
kerak. Buning uchun ishlatiladi.
Bundan tashqari, ba'zi hollarda, takrorlashni davom ettirish
shartlari bajarilgan bo'lsa ham, takrorlashdan tashqariga chiqarish talab
qilinadi. Bunday holda ishlatiladi.
Ushbu operatorlardan foydalanishga misol Listing 7.4 da
keltirilgan. Bu allaqachon tanish bo'lgan o'yinning biroz murakkab
versiyasi. Bunday holda, kichik va katta qiymatlardan tashqari, qadam
va berilgan qiymatni kiritish taklif etiladi. Oldingi misolda bo'lgani
kabi, takrorlashning har bir iteratsiyasida kichik o'zgaruvchining
qiymati bittaga ko'payadi. Kichik o'zgaruvchi qiymati katta
o‘zgaruvchidan kattaroq bo'lganda o'yin tugaydi. Agar katta
o'zgaruvchining qiymati berilgan qiymatga (maqsad) to'g'ri kelsa, xabar
ko'rsatiladi va o'yin to'xtatiladi.
Listing 7.4. Break continuedan foydalanish
1 #include <iostream>
2 using namespace std;
3 int main(){
4 unsigned short small;
5 unsigned long large;
6 const unsigned short MAXSMALL=65535;
7 cout<<"Enter a small number:";
8 cin>>small;
9 cout<<"Enter a large number:";
10 cin>>large;
11 cout<<"small:"<<small<<"...";
12 while (small<large&&large>0&&small<MAXSMALL)
13 { if (small%5000==0)
14 cout<<"...";
15 small++;
16 large=2;}
17 cout<<"\nSmall\:-<<-Large:-<<large<<endl";
18 return 0;}
WHILE(TRUE) OPERATORIDAN FOYDALANISH
C++ tilining sintaksisi nuqtai nazaridan to'g'ri bo'lgan har qanday
ifoda takrorlashning keyingi iteratsiyasiga o'tishda tekshirilishi
mumkin bo'lgan shart sifatida harakat qilishi mumkin. Ushbu ifoda
to'g'ri bo'lsa, takrorlash bajariladi. Cheksiz takrorlashlarni tashkil qilish
uchun bunday ifoda sifatida true mantiqiy o‘zgarmasi ishlatiladi.
87
Listing 7.5. while operatoridan foydalanish
1 #include<iostream>
2 using namespace std;
3 int main()
4 {int counter=0;
5 while(true)
6{ counter++;
7 if(counter>10)
8 break; }
9 cout<<"Counter:"<<counter<<"\n";
10 return 0; }
Natija:
Counter:11
While operatori yordamida takrorlashlarni tashkil qilishda,
takrorlash tanasi umuman bajarilmaydigan vaziyat yuzaga kelishi
mumkin. Takrorlashni davom ettirish sharti har bir iteratsiyaning
boshida tekshirilganligi sababli agar ifoda false bo'lsa, takrorlashning
bajarilishi takrorlash tanasining birinchi operatorini ishga tushirishdan
oldin to'xtatiladi.
Listing 7.6. While bilan takrorlashni tugatish
1 #include<iostream>
2 using namespace std;
3 int main() {
4 int counter;
5 cout<<"How many hellos?: ";
6 cin>>counter;
7 while(counter>0)
8 {
9 cout<<"Hello\n";
10 counter--;
11 }
12 cout<<"Counter is OutPut: "<<counter;
13 return 0; }
Natija:
How many hellos? : 2
Hello
Hello
Counter is OutPut:0
DO...WHILE TAKRORLASH OPERATORIDAN
FOYDALANISH
dan foydalanganda, takrorlash tanasi
bajarilgandan so'ng shart tekshiriladi. Bu takrorlash operatorlarini
kamida bir marta bajarilishini kafolatlaydi.
88
Listing 7.7. Do.. while operatoridan foydalanish
1 #include<iostream>
2 using namespace std;
3 int main(){
4 int counter;
5 cout<<"How many hellos?: ";
6 cin>>counter;
7 do
8 {
9 cout<<"Hello\n";
10 counter--;
11 }while(counter>0);
12 cout<<"Counter is OutPut: "<<counter;
13 return 0;}
Natija:
How many hellos? : 2
Hello
Hello
Counter is OutPut:0
Listing 7.8. While operatoridan foydalanishga yana bir misol
1 #include<iostream>
2 using namespace std;
3 int main() {
4 int counter=0;
5 while(counter<5)
6 {counter++;
7 cout<<"Looping! ";
8}
9 cout<<"\nCounter: "<<counter<<"\n";
10 return 0; }
Natija:
Looping! Looping! Looping! Looping! Looping!
Counter : 5
FOR OPERATORI
yordamida takrorlashni tashkil qilish uchun uchta
majburiy amalni bajarish kerak: takrorlash o'zgaruvchilarining
boshlang'ich qiymatlari, so'ngra har bir iteratsiyada takrorlashni davom
ettirish sharti va takrorlash o'zgaruvchisining qiymatini o'zgartirish.
Professional foydalanish bilan for operatori kuchli va
moslashuvchan dasturlash operatoriga aylanadi. For operatorining
uchta mustaqil ni (ishga tushirish, davom etish
sharti va qadam) o'rnatishga imkon berishi takrorlash ishini
boshqarishda cheksiz imkoniyatlarni ochib beradi.
89
FOR TAKRORLASHI PARAMETRLARI
For takrorlashi parametrlari sintaksisi quyidagicha:
for(initsializatsiya, shart, qadam) ifodalari;
90
FOR TAKRORLASHINING NOL PARAMETRLARI
Har qanday for takrorlashi parametrini o'tkazib yuborish mumkin.
O'tkazib yuborish nol parametrdan foydalanishni anglatadi. Nolinchi
parametr for takrorlashining qolgan parametrlaridan nuqta-vergul (;)
belgisi bilan ajratiladi.
Listing 7.9. For takrorlashining nol parametrlari
1 #include<iostream>
2 using namespace std;
3 int main() {
4 int counter=0;
5 for(;counter<5;)
6 {counter++;
7 cout<<"Looping! ";
8}
9 cout<<"\nCounter: "<<counter<<".\n";
10 return 0;}
Natija:
Looping! Looping! Looping! Looping! Looping!
Counter : 5
BO'SH FOR TAKRORLASHLARIDAN FOYDALANISH
For operatorining sintaksisi takrorlashni tavsiflashda juda
murakkab tuzilmalardan foydalanishga imkon berganligi sababli
takrorlash tanasiga ehtiyoj ba'zan umuman yo'qoladi. Bu shuni
anglatadiki, takrorlash tanasi nuqta-vergul (;) belgisi bilan tugaydigan
bo'sh qatordan iborat bo'ladi. Ushbu belgi for operatori bilan bir qatorga
joylashtirilishi mumkin.
Listing 7.10. Bo'sh takrorlashni tashkil qilish uchun operatordan
foydalanish
1 #include <iostream>
2 using namespace std;
3 int main(){
4 for (int i = 0; i<5; cout << "i: " << i++ << endl);
5 return 0;}
Natija:
i: 0
i: 1
i: 2
i: 3
i: 4
91
ICHKI TAKRORLASHLAR
Boshqa takrorlashning tanasida tashkil etilgan takrorlash
deyiladi. Bunday holda, ichki takrorlash tashqi
takrorlashning har bir iteratsiyasida to'liq bajariladi.
Listing 7.11. Ichki takrorlashlar
1 #include <iostream>
2 using namespace std;
3 int main(){
4 int rows, columns;
5 char theChar;
6 cout << "How many rows? "; cin >>rows;
7 cout << "How many columns? "; cin >> columns;
8 cout << "What character? "; cin >> theChar;
9 for (int i = 0; i<rows; i++)
10 { for (int j = 0; j<columns; j++)
11 cout << theChar;
12 cout << "\n";}
13 return 0;}
Natija:
How many rows? 4
How many columns? 12
What character? X
xxxxxxxxxxxx
xxxxxxxxxxxx
xxxxxxxxxxxx
xxxxxxxxxxxx
FOR TAKRORLASHLARINING O'ZGARUVCHAN
HISOBLAGICHLARI DOIRASI
ANSI tomonidan o'rnatilgan yangi standartga ko'ra, bunday
takrorlashda e`lon qilingan o'zgaruvchilar doirasi faqat takrorlash
tanasida amal qilishi kerak. Quyidagi dastur kodini yozib,
kompilyatoringizni yangi standartga muvofiqligini tekshirishingiz
mumkin.
1 #include <iostream>
2 using namespace std;
3 int main()
4{
5 // i o'zgaruvchining ko'lamini tekshirish
6 for (int i = 0; i<5; i++)
7{
8 cout << "i: " << i << endl;
9}
10 i = 7; // i doiradan tashqarida
11 return 0;
12 }
92
Yangi standartga mos keladigan kompilyatorlar i = 7 ifodasi uchun
xato xabari qaytarishi kerak. Ba'zi o'zgarishlar kiritilgandan so'ng,
dastur barcha kompilyatorlar tomonidan xatosiz ishlaydi.
1 #include <iostream>
2 using namespace std;
3 int main(){
4 int i; //sikldan tashqarida o'zgaruvchi
5 for (int i = 0; i<5; i++)
6 {cout << "i: " << i << end1;}
7 i = 7; // endi xatolik mavjud emas
8 return 0;}
Fibonachchi seriyasining n-chi hadi (n-1)-chi va (n-2)-chi hadlarini
qo'shish orqali hisoblanadi. Ushbu muammoni takrorlashlar yordamida
hal qilishni ko'rib chiqamiz.
Listing 7.12. Fibonachchi ketma-ketligining 1-hadini topish.
1 #include <iostream>
2 using namespace std;
3 int fib(int position);
4 int main(){
5 int answer, position;
6 cout << "Which position? ";
7 cin >> position;
8 cout << "\n";
9 answer = fib(position);
10 cout << answer << " is the ";
11 cout << position << " Fibonacci number.\n";
12 return 0;}
13 int fib(int n){
14 int minusTwo=1, minusOne=1, answer=2;
15 if (n < 3)
16 return 1;
17 for (n -=3; n; n--)
18 {minusTwo = minusOne;
19 minusOne = answer;
20 answer = minusOne + minusTwo;}
21 return answer;}
Natija:
Which position? 4
3 is the 4th Fibonacci number.
Which position? 5
5 is the 5th Fibonacci number.
Which position? 20
6765 is the 20th Fibonacci number.
Which position? 100
3314859971 is the 100th
Fibonacci number.
93
6-mavzuda siz if va if/else operatorlari bilan tanishdingiz. Biroq,
ba'zi hollarda ko'p sonli if operatoridan foydalanish dasturni yozishni
ham, tushunishni ham ancha qiyinlashtiradi. Ushbu muammoni hal
qilish uchun C++ tilida switch operatoridan foydalaniladi. Uning if
operatoridan asosiy farqi shundaki, u bir vaqtning o'zida bir nechta
shartlarni tekshirishga imkon beradi, natijada dasturning tarmoqlanishi
yanada samarali tashkil etiladi. Switch operatorining sintaksisi
quyidagicha:
switch (ifoda)
{
case qiymat_1: operator; break;
case qiymat_2: operator;break;
case qiymat_n: operator; break;
default; operator;
}
Switch ifodasidan so‘ng qavs ichida sintaksisi nuqtai nazaridan
to'g'ri bo'lgan har qanday ifoda ishlatilishi mumkin. Operator
identifikatori o'rniga har qanday operatordan, sonli ifodadan yoki
ifodalar ketma-ketligidan foydalanishga ruxsat beriladi. Lekin bu yerda
mantiqiy amallar yoki taqqoslash ifodalaridan foydalanishga yo'l
qo'yilmaydi.
SWITCH OPERATORI
Switch ifodasi bir nechta mumkin bo'lgan qiymatlarni qaytaradigan
ifoda natijalariga ko'ra dasturni tarmoqlashga imkon beradi. Switch
operatorining qavsida berilgan ifoda qiymati bilan case operatorlaridan
keyin ko'rsatilgan qiymatlar taqqoslanadi va qiymatlar mos keladigan
tegishli case operatori bajariladi. Dasturning barcha satrlari tanlangan
case operatoridan so'ng switch operatori blokining tanasi tugaguncha
yoki break operatori uchraguncha bajariladi.
Agar case operatorlarining biror bir qiymati qaytarilgan qiymatga
to'g'ri kelmasa, u holda default operatoridan keyin joylashgan dastur
satrlari bajariladi, agar ushbu operator switch blokining tanasida
bo'lmasa, boshqaruv ushbu blokdan keyingi dastur qatoriga o'tkaziladi.
1-misol:
switch (choice)
{
case 0: cout << "Zero!" << endl; break;
case 1: cout << "One!"<< endl; break;
case 2: cout << "Two!" << endl; break;
default: cout << "Default!" << endl;
}
94
Break operatori bo'lmasa, casedan keyingi operator yoki ifodadan
keyingi case blokining ifodasi bajariladi. Ko'pgina hollarda bu holat
break operatori xato bilan o'tkazib yuborilganda yuzaga keladi.
Listing 7.13. switch takrorlash operatoriga misol.
1 #include <iostream>
2 using namespace std;
3 int main (){
4 unsigned short int number;
5 cout << "Enter a number between 1 and 5:";
6 cin >> number;
7 switch (number)
8 {case 0: cout<< "Too small, sorry!";break;
9 case 5: cout<< "Good job!\n";
10 case 4: cout<< "Ice Pick!\n";
11 case 3: cout<< "Excellent!\n";
12 case 2: cout<< "Masterful!\n";
13 case 1: cout<< "Incredible!\n"; break;
14 default: cout<< "Too large!\n"; break;
15 cout << "\n\n";}
16 return 0;}
Natija
Enter a number between 1 and 5:3
Excellent!
Masterful!
Incredible!
Enter a number between 1 and 5:8
Too large!
Nazorat savollari va topshiriqlar:
1. For takrorlashida bir vaqtning o'zida bir nechta hisoblagich
o'zgaruvchilarini ishga tushirish mumkinmi?
2. Nima uchun goto operatoridan foydalanishdan qochish kerak?
3. For operatori yordamida tanasi bajarilmaydigan takrorlashni tashkil
qilish mumkinmi?
4. For takrorlashi ichida while takrorlashini tashkil qilish mumkinmi?
5. Hech qachon tugamaydigan takrorlashni tashkil qilish mumkinmi?
Misol keltiring.
6. Cheksiz takrorlash boshlanganda nima bo'ladi?
7. For takrorlashi tugagandan so'ng x o'zgaruvchining qiymati qanday
bo'ladi (int x = 0; x <100; x++)?
8. 10×10 massivni nol bilan to‘ldiradigan for takrorlashini yarating.
9. Hisoblagich 100 dan 200 gacha 2-bosqichda o'zgarib turadigan for
takrorlashini tashkil qiling.
95
10. Hisoblagichi 100 dan 200 gacha 2-bosqichda o'zgarib turadigan
vaqt takrorlashini tashkil qiling.
11. Quyidagi dastur qismidagi xatolikni toping.
int counter = 0;
while (counter < 10)
{cout << "counter: " << counter;}
12. Quyidagi dastur qismidagi xatolikni toping.
for (int counter = 0; counter < 10; counter++);
cout << counter << " "
13. Quyidagi dastur qismidagi xatolikni toping.
int counter = 100;
while (counter < 10)
{cout << "counter: " << counter;
counter--;}
96
8-MAVZU. C++ DA MASSIVLAR
Massiv va uni e'lon qilish
Satrlar va ularni belgilar massivi yordamida yaratish
Massivlar va ko'rsatkichlar o'rtasidagi munosabatlar
MASSIVLAR NIMA?
lar kompyuter xotirasida saqlangan bir xil tipdagi
ma'lumotlar to'plamidir. Har bir ma'lumot birligi deb
ataladi.
Massivni e'lon qilish uchun siz uning tipini, nomini va hajmini
ko'rsatishingiz kerak. Hajmi kvadrat qavs ichida olingan son bilan
belgilanadi va ma'lum bir qatorda qancha elementni saqlash
mumkinligini ko'rsatadi, masalan:
long LongArray[25];
Ushbu misolda long int tipidagi 25 ta elementni o'z ichiga olishi
mumkin bo'lgan LongArray nomli massiv e'lon qilinadi. Kompilyator
shunga o'xshash yozuvni topib, ushbu turdagi 25 ta elementni saqlash
uchun kompyuter xotirasida joy ajratadi. Long int tipidagi bitta
qiymatni saqlash uchun 4 bayt xotira talab qilinganligi sababli berilgan
massiv uchun kompilyator 100 baytli xotiraning butun maydonini
ajratadi.
MASSIV ELEMENTLARI
Massiv elementlarining manzili massiv nomida saqlangan birinchi
element manziliga nisbatan indeks bilan aniqlanadi. Massivning
birinchi elementi nol indeksga ega. Shunday qilib, massivning birinchi
elementiga quyidagicha murojaat qilish mumkin: arrayName[0]. Agar
mavzu boshida berilgan massiv misolidan foydalansangiz, massivning
birinchi elementiga murojaat quyidagicha bo‘ladi: LongArray[0],
ikkinchi elementi - LongArray[1] va boshqalar. Umuman olganda, agar
massiv[N] e'lon qilingan bo'lsa, unda uning elementlariga indeksni
ko'rsatish orqali kirish mumkin, ya`ni massiv[0] dan massiv[n-1] kabi
indekslanadi.
97
8.1-rasm. Massiv prototipi
Shunday qilib, bizning misolimizda LongArray [25] massivi
elementlarga murojaat qilish uchun LongArray[0]dan LongArray[24]
gacha bo'lgan indekslardan foydalaniladi. Listing 8.1 beshta
elementdan iborat butun sonlar massivini e'lon qilish va uni ma'lumotlar
bilan to‘ldirish ko'rsatilgan.
Listing 8.1. Butun sonlar massividan foydalanish
1 #include <iostream>
2 using namespace std;
3 int main(){
4 int myArray[5];
5 int i;
6 for ( i=0; i<5; i++)
7 {cout << "Value for myArray[" << i << "]: ";
8 cin >> myArray[i];}
9 for (i = 0; i<5; i++)
10 cout << i << ": " << myArray[i] << "\n";
11 return 0;}
Natija:
Value for myArray[0]: 3
Value for myArray[1]: 6
Value for myArray[2]: 9
Value for myArray[3]: 12
Value for myArray[4]: 15
0: 3
1: 6
2: 9
3: 12
4: 15
ESLATMA: Shuni esda tutish kerakki, massiv elementlarini
hisoblash 1 bilan emas, balki 0 bilan boshlanadi. Agar 10 ta elementdan
iborat massiv ishlatilsa, massiv elementlariga murojaat qilish uchun
ArrayName[0] dan ArrayName[9] gacha bo'lgan indekslardan
foydalaniladi. ArrayName[10] bilan ishlash noto'g'ri bo'ladi.
98
Massivga ma'lumotlarni yozishda kompilyator elementning
kattaligi va birinchi elementga nisbatan ko'rsatilgan indeks asosida
tegishli elementning manzilini hisoblab chiqadi. Aytaylik, biz ilgari
ko'rib chiqqan LongArray massivining oltinchi elementiga ma'lum bir
qiymat yoziladi, buning uchun LongArray[5] indeksi ishlatiladi.
Kompilyator ko'rsatilgan 5 indeks qiymatini element hajmiga
ko'paytiradi (bizning misolimizda 4 bayt) va 20 baytni oladi. Keyin
kompilyator massivning oltinchi elementining manzilini hisoblab,
massiv manziliga 20 bayt indeks qo'shadi va kiritilgan qiymatni shu
manzilga yozadi.
Listing 8.2. Massivdan tashqarida yozish.
1 #include <iostream>
2 using namespace std;
3 int main(){
4 long sentinel0ne[3];
5 long TargetArray [25];
6 long sentinelTwo[3];
7 int i;
8 for (i=0; i<3; i++)
9 sentinel0ne[i] = sentinelTwo[i] = 0;
10 for (i=0; i<25; i++)
11 TargetArray[i] = 0;
12 cout << "Test 1: \n";
13 cout << "TargetArray[0]: " << TargetArray[0] << "\n";
14 cout << "TargetArray[24]: " << TargetArray[24] << "\n\n";
15 for (i = 0; i<3; i++)
16 {cout << "sentinel0ne[" << i << "]: ";
17 cout << sentinel0ne[i] << "\n";
18 cout << "sentinelTwo[" << i << "]: ";
19 cout << sentinelTwo[i]<< "\n";}
20 cout << "\nAssigning...";
21 for (i = 0; i<=25; i++)
22 TargetArray[i] = 20;
23 cout << "\nTest 2: \n";
24 cout << "TargetArray[0]: " << TargetArray[0] << "\n";
25 cout << "TargetArray[24]: " << TargetArray[24] << "\n";
26 cout << "TargetArray[25]: " << TargetArray[25] << "\n\n";
27 for (i = 0; i<3; i++)
28 cout << "sentinelOne[" << i << "]: ";
29 cout << sentinel0ne[i]<< "\n";
30 cout << "sentinelTwo[" << i << "]: ";
31 cout << sentinelTwo[i]<< "\n";
32 return 0;}
99
Natija:
Test 1:
TargetArray[0]: 0
TargetArray[24]: 0
Sentine10ne[0]: 0
SentinelTwo[0]: 0
Sentinel0ne[1]: 0
SentinelTwo[1]: 0
Sentinel0ne[2]: 0
SentinelTwo[2]: 0
Assigning…
Test 2:
TargetArray[0]: 20
TargetArray[24]: 20
TargetArray[25]: 20
Sentinel0ne[0]: 20
SentinelTwo[0]: 0
Sentine10ne[1]: 0
SentinelTwo[1]: 0
Sentinel0ne[2]: 0
SentinelTwo[2]: 0
Masalan quyidagi matematik masalani ko‘rsak. Agar ustunlar
orasidagi masofa 1 m bo‘lishi kerak bo'lsa, 10 metrli panjarani o'rnatish
uchun qancha ustunlarni qazish kerakligini hisoblang. Demak, to'g'ri
javob - 11. Agar nima uchun ekanligini tushunmasangiz, 8.2 rasmga
qarang.
100
Ushbu misolda IntegerArray butun sonlar qatori e'lon qilinadi va
IntegerArray[0] elementiga 10, IntegerArray elementiga[1] - 20 va
boshqalar beriladi.
Agar siz massiv o'lchamini bermasangiz, kompilyator avtomatik
ravishda element qiymatlari Listingi bo'yicha massiv hajmini hisoblab
chiqadi. Shuning uchun quyidagi yozuv xato emas:
int IntegerArray[] = {10, 20, 30, 40, 50};
Natijada, biz oldingi misolda bo'lgani kabi bir xil qiymatlar qatorini
olamiz. Agar siz massiv hajmini o'rnatishingiz kerak bo'lsa, quyidagi
ifoda yordamida kompilyatorga murojaat qiling:
const USHORT IntegerArrayLength;
IntegerArrayLength =
sizeof(IntegerArray)/sizeof(IntegerArray[0]);
Ushbu misolda massiv elementlari soni baytdagi massiv
o'lchamining bitta element hajmiga nisbati sifatida aniqlanadi. Natija
yuqoridagi const USHORT tipidagi IntegerArrayLength
o'zgaruvchisida saqlanadi. Listingda massiv elementlarining
belgilangan sonidan ko'proq qiymatlarni ko'rsatish mumkin emas.
Shunday qilib, quyidagi ifoda kompilyator tomonidan xato xabari
ko'rsatilishiga olib keladi, chunki beshta elementdan iborat massiv
oltita qiymatni o‘zlashtirishga harakat qiladi:
int IntegerArray[5] = (10, 20, 30, 40, 50, 60);
101
Tavsiya etilmaydi!
Massivdan tashqarida ma'lumotlarni yozmang.
103
misol sifatida sakkiz qator va sakkiz ustunli kataklardan tashkil topgan
shaxmat taxtasini misol qilish mumkin.
Aytaylik, dastur SQUARE sinfini e'lon qiladi. Ushbu sinf
obyektlarini saqlash uchun ikki o'lchovli massivni e'lon qilish
quyidagicha bo'ladi:
SQUARE Board[8][8];
Xuddi shu obyektlar 64 elementli bir o'lchovli massivda saqlanishi
mumkin edi:
SQUARE Board[64];
Agar bunday massiv haqiqiy vaziyatni yaxshiroq aks ettirsa,
masalan, shaxmat dasturini yaratishda 2D massivdan foydalanish
afzalroq bo‘lishi mumkin. Shunday qilib, o'yin boshida qirol birinchi
qatorda to'rtinchi ustunni egallaydi. Nol indeksni hisobga olgan holda,
ushbu ko‘rinishning pozitsiyasi massiv obyekti bilan ifodalanadi:
Board[0][3];
Ushbu misolda birinchi indeks qatorlarni, ikkinchisi ustunlarni
raqamlashni nazorat qiladi.
KO'P O'LCHOVLI MASSIVNI ISHGA TUSHIRISH
Birinchi navbatda qiymatlarning butun takrorlashi oxirgi
ko'rsatilgan indeksdan o'tadi, shundan so'ng oldingi indeks o'zgaradi.
Shunday qilib, agar ushbu massiv mavjud bo'lsa:
int theArray[5][3];
birinchi uchta qiymat theArray[0] qatoriga, ikkinchi uchta qiymat
theArray[1] qatoriga yoziladi va hokazo.
Belgilangan qatorni quyidagi qator bilan boshlash mumkin:
int theArray[5][3] = {1,2,3,4,5, 6,7,8,9, 10,11,12,13,14, 15};
Sonlar bilan chalkashmaslik uchun qiymatlarni qo'shimcha figurali
qavslar yordamida guruhlash mumkin, masalan:
int theArray[5][3] ={ {11,2,3},
{4,5,6},
{7, 8,9},
{10, 11, 12},
{13, 14, 15}};
104
tashqi figurali qavslarga joylashtirilishi kerak va yopiladigan qavsdan
keyin nuqta-vergul belgisi qo‘yilishi kerak.
Ikki o'lchovli massivni yaratish misoli listing 8.5 da ko'rsatilgan.
Ikki o'lchovli massivning birinchi qatori 0 dan 4 gacha bo'lgan butun
sonlarni, ikkinchisi esa birinchi qatorning tegishli elementlarining ikki
baravar qiymatlarini o'z ichiga oladi.
Listing 8.5. Ko'p o'lchovli massiv yaratish
1 #include <iostream>
2 using namespace std;
3 int main()
4 {
5 int SomeArray[5][2] = { { 0,0} , { 1,2} , { 2,4} , { 3,6} , { 4,8} };
6 for (int i = 0; i<5; i++)
7 for (int j=0; j<2; j++)
8 {cout << "SomeArray[" << i << "][" << j << "]: ";
9 cout << SomeArray[i][j]<< endl;}
10 return 0;}
Natija:
SomeArray[0][0]:0
SomeArray[0][1]:0
SomeArray[1][0]:1
SomeArray[1][1]:2
SomeArray[2][0]:2
SomeArray[2][1]:4
SomeArray[3][0]:3
SomeArray[3][1]:6
SomeArray[4][0]:4
SomeArray[4][1]:8
105
unda ushbu muammoni hal qilish uchun siz yanada moslashuvchan
xotirani boshqarish vositalaridan foydalanishingiz kerak.
KO'RSATKICH MASSIVLARI
Hozirgacha biz ko'rib chiqqan barcha massivlar o'z elementlarining
qiymatlarini xotira to'plamlarida saqlashgan. Stack xotirasidan
foydalanish dinamik xotiraning yanada moslashuvchan maydoniga
murojaat qilish orqali oldini olish mumkin bo'lgan bir qator cheklovlar
bilan bog'liq. Buni avval massivning barcha obyektlarini dinamik xotira
maydonida saqlash va keyin massivda ushbu obyektlarga
ko'rsatgichlarni yig'ish orqali amalga oshirish mumkin. Ushbu
yondashuv dasturning kompyuter Stack xotirasidan foydalanishni
sezilarli darajada kamaytiradi. Listing 8.6 Listing 8.4 da ishlagan bir xil
qatorni ko'rsatadi, ammo endi uning barcha obyektlari dinamik xotira
maydonida saqlanadi. Dasturning xotiradan foydalanish
samaradorligini oshirish uchun ushbu misolda massiv hajmi 5 dan 500
gacha oshirildi.
Listing 8.6. Dinamik xotira maydonida massivni saqlash
1 #include<iostream>
2 using namespace std;
3 class CAT
4{
5 public:
6 CAT() { itsAge = 1; itsWeight=5; }
7 ~CAT() {}
8 int GetAge() const {return itsAge; }
9 int Getheight() const { return itsWeight; }
10 void SetAge(int age) { itsAge = age; }
11 private:
12 int itsAge;
13 int itsWeight;
14 };
15 int main()
16 {
17 CAT * Family[500];
18 int i;
19 CAT * pCat;
20 for (i = 0; i < 500; i++)
21 {pCat = new CAT;
22 pCat->SetAge(2*i +1);
23 Family[i] = pCat;}
24 for (i = 0; i < 500; i++)
25 {cout << "Cat #" << i+1 <<":";
26 cout << Family[i]->GetAge() << endl;}
27 return 0;
28 }
106
Natija:
Cat #1:1
Cat #2:3
Cat #3:5
...
Cat #499:997
Cat #500:999
Bu yerda ushbu amalning natijasi dinamik almashinuv maydonida
saqlangan qatorga ko'rsatgichdir:
CAT * Family = new CAT[500];
107
Dasturda qaysi e`lon ishlatilishiga qarab, massivni boshqarish
usullari tubdan o'zgaradi. FamilyThree ko'rsatgichi aslida FamilyOne
massiviga ancha yaqinroq, ammo FamilyTwo ko'rsatgichlari
massividan tubdan farq qiladi.
Tavsiya etiladi!
Esda tutingki, 0 dan n-1 gacha bo'lgan indekslar n elementlar
qatoriga kirish uchun ishlatiladi.
Massiv elementlariga kirishni boshqarish uchun ko'rsatkichlar
bilan matematik amallarning xususiyatlaridan foydalaning.
Tavsiya etilmaydi!
Massivdan tashqarida ma'lumotlarni yozmang.
Ko'rsatgichlar qatorini massivga ko'rsatgich bilan aralashtirmang.
Siz massiv elementlarini saralash yoki boshqa tartiblash
mexanizmini ishlab chiqarishingiz yoki massivlarning boshqa ko'plab
samarali variantlaridan foydalanishingiz mumkin, ular orasida eng
mashhurlari quyidagilar:
massivning har bir a'zosi avtomatik ravishda o'z
o'rnini egallaydi;
hech bir a'zo massivda ikki marta takrorlanmaydi;
massiv elementlarining bog'langan juftlari, bu yerda bitta
atama ikkinchi atamani qaytarish uchun kalit vazifasini bajaradi;
tartibsiz to'plamlar, ularning a'zolari tasodifiy tartibda
qo'shiladi va qaytariladi.
108
7. Quyidagi dasturdagi xatolikni toping.
unsigned short SomeArray[5][4];
for (int i = 0; i<=5; i++)
for (int j = 0; j<=4; j++)
SomeArray[i][j] = 0;
8. n(n>0) butun son va n ta haqiqiy sonlardan iborat ketma-ketlik
berilgan. Berilgan ketma-ketlikdagi barcha sonlarning butun qismlari
hamda butun qismlarining yig‘indisi chiqarilsin.
3
3.5 2.6 8.7 3 2 8 13
9. n(n>0) butun son va n ta butun sondan iborat ketma-ketlik berilgan.
Agar ketma-ketlik musbat sonlardan iborat bo‘lsa true, aks holda false
chiqarilsin.
3
5 6 -4 false
10. n(n>0) butun son va n ta butun sondan iborat ketma-ketlik berilgan.
Berilgan ketma-ketlikdagi barcha toq sonlar va ularning miqdori k
chiqarilsin.
4
3645 352
109
9-MAVZU: C++ DA BELGI VA SATRLAR
Belgilar va sonlar
Maxsus belgilar
Belgilar massivi
String sinflari
110
6 return 0;
7}
Natija:
!"#$%'()++,./0123456789:;<>?@ABCDEFGHIJKLMNOP
_QRSTUVWXYZ[\]"'abcdefghijklmnopqrstuvwxyz(|{~
Ushbu oddiy dastur qiymatlari 32-127 oralig'ida bo'lgan belgilarni
chiqaradi.
MAXSUS BELGILAR
C++ kompilyatori matnni formatlash uchun mo'ljallangan ba'zi
ni taniydi. Ushbu belgilarni dasturga kiritish uchun
teskari chiziq ishlatiladi (“\”, boshqaruv ketma-ketligining boshlanish
belgisi deb ataladi), undan keyingi belgilar boshqaruvchi ekanligini
bildiradi. Shuning uchun dasturga tabulyatsiya belgisini kiritish uchun
siz bitta tirnoq, teskari chiziq, t harfini va yana bitta tirnoqni
kiritishingiz kerak:
char tabCharacter = '\t';
Ushbu misolda char turi (tabCharacter nomi bilan), u darhol \t
belgisi qiymati bilan ishga tushiriladi, tabulyatsiya belgisi sifatida tan
olinadi, o'zgaruvchi e'lon qilinadi. Ma'lumotni ekranda, faylda yoki
boshqa chiqarish qurilmasida (masalan, printer) ko'rsatishda maxsus
formatlash belgilaridan foydalaniladi.
“\” belgisi undan keyingi belgining qiymatini o'zgartiradi.
Masalan, odatda n belgisi n harfini anglatadi, lekin oldingi boshqaruv
ketma-ketligi ( \ ) boshlanishining belgisi bo'lsa, u yangi qatorga o‘tish
belgisiga aylanadi.
Belgi Ma'nosi
\n Yangi qatorga o‘tish
\t Tabulyatsiya
\b Bir pozitsiyaga qaytish
\? Savol belgisi
\” Ikki tirnoq
\’ Bitta tirnoq
\\ Teskari Slesh
9.1-jadval. Boshqaruv belgilari
111
string txt = "We are the so-called "Vikings" from the north.";
112
Listing 9.2. Massivni belgilar bilan to‘ldirish
1 #include<iostream>
2 using namespace std;
3 int main()
4{
5 char buffer[80];
6 cout<<"Enter the string:";
7 cin>>buffer;
8 cout<<"Here's the buffer:"<<buffer<<endl;
9 return 0;
10 }
Natija:
Enter the string:Hello World
Here's the buffer:Hello
Foydalanuvchi kiritgan qatorni saqlash uchun cin >> operatoridan
foydalanish mumkin.
Biroq, cin bo'sh joyni (bo'sh joylar, tabulyatsiya va boshqalar)
tugatish belgisi sifatida ko'rib chiqadi, ya'ni u faqat bitta so'zni saqlashi
mumkin (hatto ko'p so'zlarni yozsangiz ham):
string fullName;
cout << "Type your full name: ";
cin >> fullName;
cout << "Your name is: " << fullName;
// Type your full name: John Doe
// Your name is: John
Yuqoridagi misoldan siz dastur "John Doe" ni chop etishini
kutgansiz, lekin u faqat "John" ni chop etadi.
Shuning uchun satrlar bilan ishlaganda qatorni o'qish uchun
ko'pincha getline() funksiyasidan foydalanamiz. U birinchi parametr
sifatida cinni, ikkinchi parametr sifatida satr o'zgaruvchisini oladi:
string fullName;
cout << "Type your full name: ";
getline (cin, fullName);
cout << "Your name is: " << fullName;
// Type your full name: John Doe
// Your name is: John Doe
Siz satrdagi belgilarga uning kvadrat qavs ichidagi indeks
raqamiga murojaat qilish orqali kirishingiz mumkin [].
Masalan, myString dagi birinchi belgini chop etish quyidagicha:
string myString = "Hello";
cout << myString[0];
// Outputs H
ESLATMA: String indekslari 0 dan boshlanadi: [0] birinchi belgi. [1]
ikkinchi belgi va boshqalar. Satrdagi ma'lum bir belgining qiymatini
113
o'zgartirish uchun indeks raqamiga murojaat qiling va bitta tirnoqdan
foydalaning:
string myString = "Hello";
myString[0] = 'J';
cout << myString;
// Outputs Jello instead of Hello
SATR UZUNLIGI
ni olish uchun length() yoki size() funksiyasidan
foydalaning:
string txt = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
cout << "The length of the txt string is: " << txt.length();
cout << "The length of the txt string is: " << txt.size();
C++ qoʻshish va birlashtirish uchun + operatoridan foydalanadi.
Raqamlar qo'shiladi. Satrlar birlashtiriladi. Agar siz ikkita raqam
qo'shsangiz, natijada raqam bo'ladi:
int x = 10;
int y = 20;
int z = x + y; // z = 30
Agar siz ikkita satr qo'shsangiz, natijada satr birikmasi bo'ladi:
string x = "10";
string y = "20";
string z = x + y; // z="1020"
Agar siz satrga raqam qo'shishga harakat qilsangiz, xatolik yuz beradi:
string x = "10";
int y = 20;
string z = x + y;
SATRLARNI BIRLASHTIRISH
Satrlar orasidagi + operatoridan satrlarni bir-biriga qo'shish uchun
foydalanish mumkin. Bunga birikma deyiladi:
string firstName = "John ";
string lastName = "Doe";
string fullName = firstName + lastName;
cout << fullName;
Yuqoridagi misolda biz chiqarishda John va Doe o'rtasida bo'sh
joy yaratish uchun firstName dan keyin bo'sh joy qo'shdik. Shu bilan
birga, siz tirnoqli bo'sh joy qo'shishingiz mumkin (" " yoki ' '). Siz
satrlarni append() funksiyasi bilan ham birlashtirishingiz mumkin:
string firstName = "John ";
string lastName = "Doe";
string fullName = firstName.append(lastName);
cout << fullName;
114
Ko'pgina C++ kompilyatorlari turli xil amaliy muammolarni hal
qilish uchun ishlatilishi mumkin bo'lgan sinf kutubxonalarini o'z ichiga
oladi. O'rnatilgan sinflardan biri String sinfidir.
C++ tili StrCpy () funksiyasini o'z ichiga olgan satr oxiri nol belgisi
va satr funksiyalari kutubxonasidan meros bo'lib qolgan. Ammo bu
xususiyatlarning barchasini obyektga yo'naltirilgan dasturlashda
ishlatib bo'lmaydi. String sinfi o'rnatilgan a'zo va a'zo o'zgaruvchilar
to'plamini, shuningdek, foydalanuvchidan buyruqlar olish orqali matn
satrlarini qayta ishlash bilan bog'liq ko'plab muammolarni avtomatik
ravishda hal qilish imkonini beruvchi kirish usullarini taklif etadi.
Agar sizning kompilyatoringizda o'rnatilgan String sinfi bo'lmasa,
siz o'zingizning string sinfingizni yaratishingiz kerak bo'ladi.
Boshqa massivlar kabi, belgilar massivlari ham statikdir. Siz e'lon
qilganingizda yoki ishga tushirganingizda ularning hajmini
o‘zlashtirishingiz kerak.
Nazorat savollari va topshiriqlar:
1.Satrlar bilan ishlashda qaysi kutubxona funksiyasidan foydalanish
kerak?
2. Quyidagi sarlavhaning ma’nosi nima?
#include <string>
3. Quyidagi dasturdagi xatolikni topishga harakat qiling.
#include <iostream>
using namespace std;
int main()
{
string hello = "Hello World!";
cout << hello << "\n";
return 0;
}
4. ASCII kodida inglizcha "a" kichik harfiga necha qiymat berilgan?
5. ASCII haqida nimalarni bilib oldingiz?
6. Char turi xotiradan necha bayt o’rin egallaydi?
7. ASCII kodida nechta katta va kichik harflar, belgilar bor?
8.3-mashqdan foydalanib inglizcha kichik harflarni ekranga
chiqaradigan dastur tuzing.
115
10-MAVZU. C++ DA FUNKSIYALAR
117
1 #include <iostream>
2 using namespace std;
3 int Add (int x, int y)
4{
5 cout << "In Add(), received " << x << " and " << y << "\n":
6 return (x+y);
7}
8 int main()
9{
10 cout << "I'm in main()!\n";
11 int a, b, c;
12 cout << "Enter two numbers: "
13 cin >> a;
14 cin >> b:
15 cout << "\nCalling Add()\n";
16 c=Add(a, b);
17 cout << "\nBack in main().\n";
18 cout << "c was set to " << c;
19 cout << "\nExiting…\n\n";
20 return 0;
21 }
Natija:
I'm in main()!
Enter two numbers: 3 5
Calling Add()
In Add(), received 3 and 5
Back in main().
c was set to 8
Exiting.
Tahlil:
Add () funksiyasi 3-qatorda aniqlanadi. U ikkita butun parametrini
oladi va butun qiymatini qaytaradi. Dasturning o'zi 9-qatorda
boshlanadi, ekranda birinchi xabarni ko'rsatadi. Keyin
foydalanuvchidan ikkita sonni kiritish so'raladi (13-14 qatorlar).
Foydalanuvchi sonlarni bo'sh joy bilan ajratib kiritadi va keyin
<Enter>tugmachasini bosadi. 16-qatorda main () funksiyasi
foydalanuvchi tomonidan kiritilgan ikkita sonni argument sifatida
Add() funksiyalariga o'tkazadi.
Dasturni boshqarish 3-qatorda boshlanadigan Add () funksiyasiga
o'tadi. a va b parametrlari ekranda ko'rsatiladi va keyin qo'shiladi.
Funksiya natijasi 6-qatorda qaytariladi va shu bilan funksiya o'z ishini
tugatadi.
FUNKSIYA NIMA?
- ma'lumotlarni boshqarishi va ba'zi qiymatlarni
qaytarishi mumkin bo'lgan kichik dasturdir. Har bir C++ dasturida
118
kamida bitta main () funksiyasi mavjud bo'lib, u dasturni ishga
tushirganda avtomatik ravishda chaqiriladi. Main () funksiyasi esa
boshqa funksiyalarni chaqirishi mumkin.
Har bir funksiya o'z nomiga ega va dasturda paydo bo'lganda,
boshqaruv ushbu funksiya tanasiga o'tadi. Ushbu jarayon
(yoki funksiyaga kirish) deb nomlanadi. Funksiyadan
qaytgach, dasturning bajarilishi funksiya chaqirilgandan keyingi
qatordan boshlanadi. Dasturni amalga oshirishning bunday sxemasi
10.1-rasmda ko‘rsatilgan.
Funksiyalar aniq va to'liq tushunarli vazifani bajarsa, ularni
mukammal tuzilgan funksiya deyishimiz kerak.
Funksiyalarning ikki turi mavjud: foydalanuvchi tomonidan
belgilangan ( ) va . O'rnatilgan funksiyalar
kompilyator paketining ajralmas qismi bo'lib, ishlab chiqaruvchi
tomonidan taqdim etiladi. Nostandart funksiyalar dasturchining o'zi
tomonidan yaratiladi.
119
Ushbu prototip shuni anglatadiki, myFunction funksiyasi nafaqat
butun sonni qaytaradi, balki parametr sifatida ikkita qiymatni oladi:
butun va haqiqiy.
funksiya chaqirilganda unga o'tkaziladigan qiymat tipini
tavsiflaydi. Funksiyaga berilgan haqiqiy qiymatlar deb
ataladi.
int theValueReturned = myFunction(5,6.7);
Bu yerda butun theValueReturned o'zgaruvchisi myFunction
funksiyasi tomonidan qaytarilgan qiymat bilan boshlanadi va 5 va 6.7
qiymatlari ushbu funksiya argumentlari sifatida uzatiladi. Argumentlar
tipi e'lon qilingan parametr turlariga mos kelishi kerak.
FUNKSIYANI E'LON QILISH VA ANIQLASH
Dasturda funksiyalardan foydalanishdan avval funksiyani e'lon
qilishni va keyin aniqlashni talab qiladi. orqali
kompilyatorga uning nomi, qaytish tipi va parametrlari haqida xabar
beriladi. orqali kompilyator funksiyaning qanday
ishlashini bilib oladi. Agar u oldindan e'lon qilinmagan bo'lsa, dasturda
biror bir funksiyani chaqirish mumkin emas. deb,
dasturga parametrlar soni va turi, shuningdek funksiya qaytadigan
qiymat tipi to'g'risida ma'lumot beradigan funksiya e`loniga aytiladi.
Funksiyani e'lon qilishning uchta usuli mavjud.
Funksiyaning prototipini faylga yozing va keyin uni dasturingizga
kiritish uchun #include ifodasidan foydalaning.
Funksiya prototipini ushbu funksiyadan foydalanadigan faylga
yozing.
Boshqa har qanday funksiya chaqirilishidan oldin funksiyani
aniqlang.
Bunday holda, funksiyani aniqlash bir vaqtning o'zida uni e'lon qiladi.
Funksiyani ishlatishdan oldin darhol aniqlash va shu bilan funksiya
prototipini yaratish uchta sababga ko'ra yaxshi deb hisoblanmaydi.
Birinchidan, faylda funksiyalarni ma'lum tartibda joylashtirish
talabi dasturni foydalanish shartlarini o'zgartirish jarayonida qo'llab-
quvvatlashni qiyinlashtiradi.
Ikkinchidan, a() funksiyalari b () funksiyasini chaqirishi vaziyati
bo‘lishi mumkin, ammo ba'zi holatlarda c() funksiyalari a ()
funksiyasini chaqirishi kerak bo‘lishi mumkin. Shu bilan birga, b()
funksiyasini aniqlashdan oldin a() funksiyasini va shu bilan birga a()
120
funksiyasini aniqlashdan oldin b () funksiyasini aniqlash mumkin emas,
ya'ni ushbu funksiyalardan kamida bittasi oldindan e'lon qilinishi kerak.
Uchinchidan, funksiya prototipiga ko'ra, funksiya ma'lum bir
parametrlar to'plamini qabul qilishi yoki ma'lum bir turdagi qiymatni
qaytarishi e'lon qilingan bo'lsa, u holda kompilyator ushbu xatoni
dasturni kompilyatsiya qilish bosqichida sezadi, bu esa uni amalga
oshirish jarayonida kutilmagan hodisalardan qochadi.
FUNKSIYA PROTOTIPI
Ko'pgina o'rnatilgan funksiyalarning prototiplari allaqachon
#include yordamida dasturga qo'shilgan sarlavha fayllariga yozilgan.
Foydalanuvchilar tomonidan yaratilgan funksiyalar uchun
dasturchining o'zi dasturga tegishli prototiplarni yaratishi kerak.
Funksiya prototipi nuqta-vergul bilan tugaydigan ifoda bo'lib,
funksiya sarlavhasi, qaytish qiymati tipidan iborat. Funksiya sarlavhasi
uning nomi va parametrlar ro‘yxatini anglatadi.
Prototipda va funksiyani aniqlashda qaytish tipi va sarlavhasi mos
kelishi kerak. Agar bunday moslik bo'lmasa, kompilyator xato xabarini
ko'rsatadi. Biroq, funksiya prototipida parametr nomlari bo‘lishi shart
emas, u faqat ularning turlarini ko'rsatish bilan cheklanishi mumkin.
Masalan, quyidagi prototip xato emas:
long Area(int, int);
Ushbu prototip long int tipidagi qiymatni qaytaradigan va ikkita
butun parametrlarini qabul qiladigan Area () deb nomlangan funksiyani
e'lon qiladi. Prototipning bunday yozuvi juda maqbul bo‘lsada, bu eng
yaxshi variant emas. Parametr nomlarini qo'shish prototipingizni
yanada aniqroq qiladi. Xuddi shu funksiya parametrlar nomlari bilan
aniqroq ko'rinadi:
long Area(int length, int width);
Endi funksiya nima uchun mo'ljallanganligi va uning parametrlari
darhol aniq.
E'tibor bering, har bir funksiya uchun qaytish tipi har doim ma'lum.
Agar u aniq e'lon qilinmasa, int tipi sukut bo'yicha qabul qilinadi.
Ammo, agar har bir funksiya, shu gapdan main () uchun qaytish tipi
aniq e'lon qilinsa, sizning dasturlaringiz aniqroq bo'ladi. Listing 10.3 da
Area () funksiyasining prototipini o'z ichiga olgan dastur mavjud.
Listing 10.3. Funksiyani e'lon qilish, aniqlash
1 #include <iostream>
2 using namespace std;
121
3 int Area(int yardLength; int yardWidth)
4 int main()
5{
6 int lengthOfYard;
7 int widthOfYard;
8 int areaOfYard;
9 cout << "\nHow wide is your yard? ";
10 cin >> widthOfYard;
11 cout << "\nHow long is your yard? ":
12 cin >> lengthOfYard;
13 area0fYard= Area(lengthOfYard,widthOfYard);
14 cout << "\nYour yard is ";
15 cout << area0fYard;
16 cout << " square feet\n\n";
17 return 0;
18 }
19 int Area(int yardLength; int yardWidth)
20 {
21 return yardLength * yardWidth;
22 }
Natija:
How wide is your yard? 100
How long is your yard? 200
Your yard is 20000 square feet
Tahlil:
Area () funksiyasining prototipi 4-qatorda e'lon qilinadi. Prototipni
20-qatorda ko'rsatilgan funksiya ta'rifi bilan solishtiring. E'tibor bering,
ularning nomlari, qaytish qiymatlari tiplari va parametr turlari to'liq
mos keladi. Agar ular boshqacha bo'lsa, kompilyator xato xabarni
ko'rsatgan bo'lar edi. Ularning orasidagi yagona farq shundaki, funksiya
prototipi nuqta-vergul bilan tugaydi va tanasi yo'q.
Shuni ham yodda tutingki, prototipdagi parametr nomlari - uzunlik
va kenglik ta'rifdagi parametr nomlari bilan bir xil: yardLength va
yardWidth.Funksiya - funksiya sarlavhasi va uning tanasidan iborat.
Sarlavha funksiyaning prototipiga o'xshaydi, bundan tashqari, bu holda
parametrlar nomlangan va sarlavha oxirida nuqta-vergul yo'q.
122
Funksiya tanasi figurali qavslarga olingan ifodalar to'plamidir.
Funksiya sarlavhasi va tanasi 10.2-rasmda ko'rsatilgan.
Funksiya prototipi sintaksisi:
funksiya turi funksiya nomi(parametr turi [parametr_nomi]...);
{
ifodalar;
}
Funksiya prototipi kompilyatorga qaytish tipi, funksiya nomi va
parametrlar ro‘yxatini uzatadi. Parametrlarning mavjudligi shart emas,
lekin agar ular mavjud bo'lsa, ularning tiplari prototipda e'lon qilinishi
kerak. Prototip qatori har doim nuqta-vergul (;) bilan tugaydi.
Funksiya ta'rifi qaytish turi va parametrlar ro‘yxati bo'yicha
prototipiga mos kelishi kerak. Unda barcha parametrlarning nomlari
bo‘lishi kerak va funksiyani aniqlash tanasi figurali qavslarda bo‘lishi
kerak.
Agar funksiya qiymatni qaytarsa, u return operatori bilan ifodani
o'z ichiga olishi kerak. Ushbu ifoda funksiya ta'rifining istalgan qismida
bo‘lishi mumkin, lekin odatda uni tugatadi.
FUNKSIYA PROTOTIP LARIGA MISOLLAR:
long FindArea (long length, long width); / / long turdagi qiymatni
qaytaradi, ikkita parametrga ega.
void PrintMessage (int messageNumber); / / void tipidagi qiymatni
qaytaradi, bitta parametrga ega
int GetChoice (); / / int tipidagi qiymatni qaytaradi, parametrlarga
ega emas
FUNKSIYA TA'RIFLARIGA MISOLLAR:
long FindArea(long l, long w)
{
return 1 + w;
}
123
FUNKSIYALARNI BAJARISH
Funksiyani chaqirganda, uning bajarilishi ochiluvchi figurali
qavsidan ({) keyin birinchi bo'lgan ifoda bilan boshlanadi. Shuningdek,
funksiya tanasida if operatori yordamida shart bajarilishini amalga
oshirish mumkin. Funksiyalar boshqa funksiyalarni va hatto o'zlarini
ham chaqirishi mumkin(rekursiv funksiya).
Funksiyada siz nafaqat o'zgaruvchilarning qiymatlarini
o'tkazishingiz, balki funksiya tanasi ichidagi o'zgaruvchilarni ham e'lon
qilishingiz mumkin. Bu yordamida amalga
oshiriladi, ular shunday nomlanadi, chunki ular faqat funksiyaning
o'zida mavjud. Dasturning bajarilishi funksiyadan asosiy kodga
qaytganda, lokal o'zgaruvchilar xotiradan o'chiriladi.
Lokal o'zgaruvchilar boshqa o'zgaruvchilar kabi aniqlanadi.
Funksiyalarga berilgan parametrlar ham lokal o'zgaruvchilar deb
hisoblanadi va ular funksiyalar tanasida aniqlangan sifatida ishlatilishi
mumkin. Listingda funksiya parametrlari va funksiya ichida local
o'zgaruvchilardan foydalanish misoli keltirilgan.
Listing 10.4. Lokal o'zgaruvchilar va funksiya parametrlaridan
foydalanish
1 #include <iostream>
2 using namespace std;
3 float Convert(float);
4 int main()
5{
6 float TempFer;
7 float TempCel;
8 cout << "Please enter the temperature in Fahrenheit: ";
9 cin >> TempFer;
10 TempCel = Convert(TempFer);
11 cout << "\nHere's the temperature in Celsius: ";
12 cout << TempCel << endl;
13 return 0;
14 }
15 float Convert(float TempFer)
16 {
17 float TempCel;
18 TempCel = ((TempFer - 32) • 5) / 9;
19 return TempCel;
20 }
Natija:
Please enter the temperature in Fahrenheit: 212
Here's the temperature in Celsius: 100
Please enter the temperature in Fahrenheit: 32
124
Here's the temperature in Celsius: 0
Please enter the temperature in Fahrenheit: 85
Here's the temperature in Celsius: 29.4444
Tahlil:
6 va 7 - qatorlarda float tipidagi ikkita o'zgaruvchi e'lon qilinadi:
biri (TempFer) harorat qiymatini Farengeytda, ikkinchisi (TempCel)
Selsiy darajasida saqlash uchun. 9-qatorda foydalanuvchidan Farengeyt
haroratini kiritish so'raladi va bu qiymat Convert () funksiyasiga
o'tkaziladi.
Convert () funksiyasini chaqirgandan so'ng, dastur 17-satr bilan
ifodalangan ushbu funksiya tanasida birinchi ifoda bilan ishlashni
davom ettiradi, bu yerda TempCel deb nomlangan local o'zgaruvchi
e'lon qilinadi. E'tibor bering, ushbu local o'zgaruvchi 7 - qatorda e'lon
qilingan bir xil TempCel o'zgaruvchisi emas. Ushbu o'zgaruvchi faqat
Convert () funksiyasi ichida mavjud. TempFer parametri sifatida
berilgan qiymat, shuningdek, xuddi shu nomdagi o'zgaruvchining
main() funksiyasidan olingan local nusxadir.
Convert () funksiyasida siz FerTemp parametrini va local CelTemp
o'zgaruvchisini o'rnatishingiz mumkin, bu dasturning ishlashiga ta'sir
qilmaydi. Bunga ishonch hosil qilish uchun siz yangi nomlarni
kiritishingiz va dasturni qayta kompilyatsiya qilishingiz mumkin.
Lokal TempCel o'zgaruvchisiga quyidagi amallarni bajarish
natijasida olingan qiymat beriladi: TempFer parametridan 32 sonini
ayirish, bu farqni 5 soniga ko'paytirish va keyin 9 soniga bo‘lish. Keyin
hisoblash natijasi funksiyani qaytarish qiymati sifatida qaytariladi va
10-qatorda u tempcel o'zgaruvchisiga main () funksiyasiga beriladi. 12-
qatorda bu qiymat ekranda ko'rsatiladi.
Bizning misolimizda dastur uch marta ishga tushirildi.
Farangeytdagi suvning qaynash nuqtasi (212) Selsiy darajasida (100)
to'g'ri javob hosil qilishiga ishonch hosil qilish uchun birinchi marta 212
qiymati kiritiladi. Ikkinchi sinovda suvning muzlash nuqtasi qiymati
kiritiladi. Uchinchi marta esa kasr natijasini olish uchun tanlangan
tasodifiy son beriladi.
Har bir o'zgaruvchi dasturdagi o'zgaruvchining ishlash muddati va
mavjudligini belgilaydigan o'z doirasi bilan tavsiflanadi. Ba'zi bir
dastur blokida e'lon qilingan o'zgaruvchilar ushbu blok bilan
cheklangan doiraga ega. Ularga faqat ushbu blok ichida kirish mumkin
va dastur bajarilgandan so'ng, uning barcha lokal o'zgaruvchilari
125
avtomatik ravishda xotiradan o'chiriladi. Global o'zgaruvchilar global
miqyosga ega va ularga dasturning istalgan joyidan kirish mumkin.
Odatda, o'zgaruvchilar doirasi ular e'lon qilingan joyda aniq
bo'ladi, ammo ba'zi istisnolar hali ham mavjud.
Listing 10.5 Global va lokal o'zgaruvchilardan foydalanish
1 #include <iostream.h>
2 using namespace std;
3 float Convert(float);
4 int main()
5{
6 float TempFer;
7 float TempCel;
8 cout << "Please enter the temperature in Fahrenheit: ";
9 cin >> TempFer;
10 TempCel = Convert(TempFer);
11 cout << "\nHere's the temperature in Celsius: "
12 cout << TempCel << endl;
13 return 0;
14 }
15 float Convert(float Fer)
16 {
17 float Cel;
18 Cel = ((Fer - 32) 5) / 9;
19 return Cel;
20 }
Odatda, funksiyalarda o'zgaruvchilardan foydalanish, agar siz nom
berishga mas'uliyat bilan yondashsangiz va bitta funksiya ichida bir xil
nomdagi o'zgaruvchilar ishlatilmasligiga ishonch hosil qilsangiz,
muammolarga yuzaga kelmaydi.
GLOBAL O'ZGARUVCHILAR
Har qanday funksiya tanasidan tashqarida aniqlangan
o'zgaruvchilar miqyosga ega va dasturdagi har qanday
funksiyadan, shu bilan birga main () dan foydalanish mumkin.
Nomlari global o'zgaruvchilar nomlari bilan bir xil bo'lgan local
o'zgaruvchilar ikkinchisining qiymatlarini o'zgartirmaydi. Biroq,
bunday local o'zgaruvchi global o'zgaruvchini yashiradi. Agar
funksiyada global bilan bir xil nomdagi o'zgaruvchi bo'lsa, u holda
funksiya ichida ishlatilganda bu nom global emas, balki local
o'zgaruvchiga ishora qiladi.
Listing 10.6. Global va lokal o'zgaruvchilardan foydalanish
1 #include <iostream>
2 using namespace std;
3 void myFunction(): // prototip
126
4 int x = 5, y = 7; // global o'zgaruvchilar
5 int main()
6{
7 cout << "x from main: " << x << "\n";
8 cout << "y from main: " << y << "\n\n";
9 myFunction():
10 cout << "Back from myFunction!\n\n";
11 cout << "x from main: "<<x<<”/n”;
12 cout << "y from main: "<<y<<”/n”;
13 return 0;
14 }
15 void myFunction()
16 {
17 int y = 10;
18 cout << "x from myFunction: " << x << "\n";
19 cout << "y from myFunction: " << y << "\n\n";
20 }
Natija:
x from main: 5
y from main: 7
x from myFunction: 5
y from myFunction: 10
Back from myFunction!
x from main: 5
y from main: 7
Tahlil:
Ushbu oddiy dastur lokal va global o'zgaruvchilardan foydalanish
bilan bog'liq bir nechta muhim fikrlarni aks ettiradi, bu yerda yangi
dasturchilar tez-tez adashishadi. 4 - qatorda ikkita global o'zgaruvchi
e'lon qilinadi: x va y. Global o'zgaruvchi x 5 qiymati, global o'zgaruvchi
y 7 qiymati berilgan.
Main () funksiyasidagi 7 va 8-qatorlarda bu qiymatlar ekranda
ko'rsatiladi. E'tibor bering, ushbu o'zgaruvchilar main () funksiyasida
e'lon qilinmagan bo‘lsada, ular global bo'lib, allaqachon mavjud.
MyFunction () funksiyasining 9-qatoriga murojaat qilganda,
dasturning bajarilishi 15-qatordan davom etadi va 17-qatorda 10-
qiymat bilan boshlanadigan y local o'zgaruvchisi e'lon qilinadi. 18-
qatorda myFunction () funksiyasi x o'zgaruvchining qiymatini
ko'rsatadi. Bu yerda x global o'zgaruvchidan foydalanadi. Biroq, 19-
qatorda y o'zgaruvchiga murojaat qilganda y lokal o'zgaruvchining
qiymati ko'rsatiladi, xuddi shu nomdagi global o'zgaruvchi yashirin
bo'lib chiqadi.
Funksiya tanasi tugagandan so'ng, dasturni boshqarish main ()
funksiyasini qaytaradi, u yana bir xil global o'zgaruvchilarni aniqlash
127
uchun ekranga chiqadi. E'tibor bering, y global o'zgaruvchiga
myFunction () funksiyasida lokal o'zgaruvchiga qiymat berish umuman
ta'sir qilmagan.
GLOBAL O'ZGARUVCHILAR
Shuni ta'kidlash kerakki, C++ da global o'zgaruvchilar deyarli hech
qachon ishlatilmaydi. C++ tili C tilidan kelib chiqdi, bu yerda global
o'zgaruvchilardan foydalanish har doim xatolarning paydo bo‘lishi
bilan to'la edi. Global o'zgaruvchilar dasturchi ko'plab funksiyalar
uchun ma'lumotlarni taqdim etishi kerak bo'lgan va parametr sifatida
funksiyadan funksiyaga ma'lumotlarni uzatish muammoli bo'lgan
hollarda talab qilinadi.
Global o'zgaruvchilardan foydalanish xavfi ularning umumiy
mavjudligidan kelib chiqadi, natijada bitta funksiya o'zgaruvchining
qiymatini boshqa funksiya sezmagan holda o'zgartirishi mumkin.
Bunday vaziyatlarda aniqlash juda qiyin bo'lgan xatolar paydo bo‘lishi
mumkin.
LOKAL O’ZGARUVCHILAR HAQIDA KO'PROQ
MA'LUMOT
Funksiya ichida e'lon qilingan o'zgaruvchilar local doiraga ega
ekanligi aytiladi. Bu shuni anglatadiki, yuqorida aytib o'tilganidek, ular
ko'rinadigan va faqat belgilangan funksiya doirasida foydalanish
mumkin. Aslida, C++ da o'zgaruvchilarni faqat boshida emas, balki
funksiyaning istalgan joyida aniqlash mumkin. O'zgaruvchining
ko'lami u aniqlangan blokdir. Shunday qilib, agar funksiya tanasida bir
juft figurali qavs bilan ajratilgan blok bo'lsa va ushbu blokda
o'zgaruvchi e'lon qilinsa, u Listing 10.7 da ko'rsatilganidek, butun
funksiyada emas, balki faqat blok ichida mavjud bo'ladi.
Listing 10.7. Lokal o’zgaruvchilarning ko'rinishi
1 #include <iostream>
2 using namespace std;
3 void myFunc();
4 int main()
5{
6 int x = 5;
7 cout << "\nIn main x is: " << x;
8 myFunc();
9 cout << "\nBack in main, x is: " << x;
10 return 0;
11 }
12 void myFunc()
13 {
128
14 int x = 8;
15 cout << "\nIn myFunc, local x: " << x << endl;
16 {
17 cout << "\nIn blok in myFunc, x is: " << x;
18 int x = 9;
19 cout << "\nVery local x: " << x;
20 }
21 cout << "\n0ut of blok, in myFunc, x: " << x << end1;
22 }
Natija:
In main x is: 5
In myFunc, local x: 8
In blok in myFunc, x is: 8
Very local x: 9
Out of blok, in myFunc, x: 8
Back in main, x is: 5
Tahlil:
Ushbu dastur main () funksiyasida lokalo'zgaruvchini ishga
tushirish bilan boshlanadi (6-qator). 8-qatorda ko'rsatilgan x
o'zgaruvchining qiymati x o'zgaruvchining rostan ham 5 soni bilan
boshlanganligini tekshirishga imkon beradi. Keyin dasturda myFunc ()
funksiyasi chaqiriladi, uning tanasida 16-qatorda bir xil x nomli lokal
o'zgaruvchi e'lon qilinadi va 8 qiymati bilan ishga tushiriladi. Ushbu
qiymat 17-qatorda ko'rsatiladi.
Blok 18-qatordan boshlanadi va 19-qatorda x local o'zgaruvchining
qiymati yana ko'rsatiladi. Ammo 20-qatorda xuddi shu nomdagi yangi
o'zgaruvchi yaratiladi x, bu berilgan blokga nisbatan lokal hisoblanadi.
Ushbu o'zgaruvchi darhol 9 qiymati bilan ishga tushiriladi.
Yaratilgan oxirgi o'zgaruvchining qiymati x ekranda 21-qatorda
ko'rsatiladi. Lokal blok 22-qator bilan tugaydi va 20-qatorda yaratilgan
o'zgaruvchi ko'rinmaydi va xotiradan o'chiriladi.
23-qatorda 16-qatorda e'lon qilingan x o'zgaruvchining qiymati
ko'rsatiladi. 23-qatorda yangi x o'zgaruvchining ta'rifi unga hech
qanday ta'sir ko'rsatmadi va uning qiymati hali ham 8 ga teng.
24-qatorda myFunc () funksiyasining ko'lami tugaydi va uning
local o'zgaruvchisi x mavjud bo'lmaydi. Dasturni boshqarish 11-
qatorga qaytadi, unda 8-qatorda yaratilgan lokal x o'zgaruvchisining
qiymati ko'rsatiladi. myFunc () funksiyasida belgilangan bir xil
nomdagi o'zgaruvchilardan hech biri unga ta'sir qilmasligiga o'zingiz
ishonch hosil qilishingiz mumkin.
129
FUNKSIYALARDA ISHLATILADIGAN OPERATORLAR
Aslida, funksiyalarda ishlatiladigan operatorlarning soni yoki
turlariga hech qanday cheklovlar qo'yilmaydi. Shuningdek, funksiya
ichida boshqa funksiyani aniqlash mumkin bo'lmasa-da, lekin bitta
funksiyadan siz xohlagancha boshqa funksiyalarni chaqirishingiz
mumkin; deyarli har bir C++dasturida main() funksiyasi aynan shunday
qiladi. Bundan tashqari, funksiyalar hatto o'zlarini ham chaqirishi
mumkin (bu holat rekursiya bo'limida ko'rib chiqiladi).
C++ da funksiya hajmi ham cheklanmagan bo‘lsada, funksiya
tanasi cheksiz miqyosga o'smasligi yaxshiroqdir. Ko'pgina
mutaxassislar ekranning bitta sahifasini egallagan funksiyalarning
kichik hajmini saqlashni maslahat berishadi va shu bilan butun
funksiyani to'liq ko'rishga imkon beradi. Ammo, funksiya qanchalik
kichik bo'lsa, tushunish va keyingi o‘zgartirish osonroq bo'ladi.
Har bir funksiya tushunish oson bo'lgan bitta vazifani bajarishi
kerak. Agar funksiya kengayishni boshlaganini sezsangiz, yangi
funksiyani yaratish vaqti keldimi yoki yo'qligini o'ylab ko'ring.
Funksiya argumentlari har xil bo‘lishi mumkin. Masalan, bitta int
tipidagi qiymatni, ikkita long tipdagi qiymatlarni va bitta belgi
argumentini o'z argumentlari sifatida qabul qiladigan funksiyani yozish
juda maqbuldir.
Funksiya argumenti har qanday C++ ifodasi bo‘lishi mumkin,
masalan, konstantalar, matematik va mantiqiy ifodalar va ba'zi
qiymatlarni qaytaradigan boshqa funksiyalarni olish mumkin.
Bitta funksiya uchun ma'lum bir qiymatni qaytaradigan parametr
sifatida ikkinchi funksiyani olish juda mumkin bo‘lishiga qaramay,
ushbu dasturlash usuli dasturni o'qishni va uni disk raskadrovka qilishni
qiyinlashtiradi.
Misol tariqasida, y sizda ba'zi qiymatlarni qaytaradigan double(),
triple(), square() va cube () funksiyalari mavjud deb taxmin qiling. Siz
quyidagi ko'rsatmalarni yozishingiz mumkin:
Answer = (double(triple(square(cube(myValue)))));
Ushbu ko'rsatma myValue o'zgaruvchisini oladi va uni cube ()
funksiyasiga argument sifatida uzatadi, uning qaytish qiymati (son
kubi) square () funksiyasiga argument sifatida uzatiladi. Shundan so'ng,
square () funksiyasining qaytish qiymati (sonning kvadrati) o'z
navbatida triple () funksiyasining argumenti sifatida uzatiladi. Keyin
triple () funksiyasining qaytish qiymati (uch baravar) double ()
130
funksiyasining argumenti sifatida uzatiladi. Nihoyat, double ()
funksiyasining qaytish qiymati (ikki baravar) Answer o'zgaruvchisiga
beriladi.
Ushbu ifoda qanday muammoni hal qilishi haqida to'liq ishonch
bilan gapirish qiyin (kvadratni hisoblashdan oldin yoki keyin qiymat
uch baravar oshirilganmi?); bundan tashqari, noto'g'ri natija bo'lsa,
"aybdor" funksiyani aniqlash juda qiyin bo'ladi. Muqobil variant
sifatida har bir oraliq hisoblash natijasi oraliq o'zgaruvchiga
tayinlanishi mumkin:
unsigned long myValue = 2;
unsigned long cubed = cube(myValue); // 2 kubda = 8
unsigned long squared = square (cubed); / / 8 kvadrat = 64
unsigned long tripled = triple(squared); // 64 * 3 = 192
unsigned long Answer = double(tripled); // 192 * 2 = 384
Endi siz har bir oraliq natijani osongina tekshirishingiz mumkin va
shu bilan birga barcha hisob-kitoblarni bajarish tartibi aniq.
Funksiyaga berilgan argumentlar berilgan funksiyaga nisbatan
lokaldir. Funksiyani bajarish paytida argumentlarga kiritilgan
o'zgarishlar funksiyaga o'tkaziladigan o'zgaruvchilarga ta'sir qilmaydi.
Parametrlarni uzatishning bu usuli qiymat sifatida uzatish deb
nomlanadi, ya'ni har bir argumentning local nusxasi funksiyaning o'zida
yaratiladi. Tashqi o'zgaruvchilarning bunday local nusxalari boshqa har
qanday lokal funksiya o'zgaruvchilari kabi qayta ishlanadi.
Listing 10.8 Parametrlarni qiymat sifatida uzatish
1 #include <iostream>
2 using namespace std;
3 void swap(int x, int y);
4 int main()
5{
6 int x = 5, y = 10;
7 cout << "Main. Before swap, x: " << x << " y: " << y << "/n”;
8 swap(x,y);
9 cout << "Main. After swap, x: " << x << " y: " << y << "/n”;
10 return 0;
11 }
12 void swap (int x, int y)
13 {
14 int temp;
15 cout << "Swap. Before swap, x: " << x << " y: " << y << "\n";
16 temp = x;
17 x=y;
18 y = temp;
19 cout << "Swap. After swap, x: " << x << " y: " << y << "n";
20 }
131
Natija:
Main. Before swap, x: 5 y: 10
Swap. Before swap, x: 5 y: 10
Swap. After swap, x: 10 y: 5
Main. After swap, x: 5 y: 10
Tahlil:
Dastur main () funksiyasidagi ikkita o'zgaruvchini ishga tushiradi
va keyin ularning qiymatlari swap () funksiyasiga o'tkaziladi, bu
ularning qiymatlarini o'zgartirishi kerak. Biroq, ushbu o'zgaruvchilarni
main () funksiyasida qayta tekshirgandan so'ng, ular o'zgarmaganligi
ma'lum bo'ldi.
Ushbu o'zgaruvchilar 7-qatorda ishga tushiriladi va ularning
qiymatlari ekranda 8-qatorda ko'rsatiladi. Keyin swap () funksiyasi
chaqiriladi va bu o'zgaruvchilar unga argument sifatida uzatiladi.
Dasturning bajarilishi swap () funksiyasiga o'tkaziladi, bu yerda
20-qatorda bizga tanish bo'lgan o'zgaruvchilarning qiymatlari yana
ko'rsatiladi. Kutilganidek, ularning funksiyadan funksiyaga o'tish
qiymatlari o'zgarmadi. 17-19-qatorlarda o'zgaruvchilar o'z qiymatlari
bilan o'zgaradi, bu 20-qatorda keyingi tekshirish bilan tasdiqlanadi.
Ammo bu pozitsiya faqat dastur swap () funksiyasidan chiqmaguncha
davom etadi.
Keyin dasturni boshqarish qiymatlarini qaytarib olganligini va
funksiyada sodir bo'lgan barcha o'zgarishlar bekor qilinganligini
ko'rsatadi.
Eslatib o'tamiz, bu holda o'zgaruvchilar swap() funksiyasiga
qiymat sifatida uzatiladi, ya'ni swap() funksiyasi ushbu funksiyaga
nisbatan local bo'lgan ushbu qiymatlarning nusxalarini yaratdi. 17-19-
qatorlarda bajarilgan qiymat almashinuvi ushbu lokal o'zgaruvchilarda
amalga oshirildi, ammo bu main () funksiyasida qolgan
o'zgaruvchilarga hech qanday ta'sir ko'rsatmadi.
RETURN QIYMATLAR HAQIDA KO'PROQ MA'LUMOT
Funksiyalar haqiqiy qiymatni yoki void tipidagi qiymatni
qaytaradi, bu kompilyator uchun hech qanday qiymat qaytarilmasligi
uchun signal bo'lib xizmat qiladi.
Funksiyadan qiymatni qaytarishni ta'minlash uchun return kalit
so'zini va undan so‘ng qaytarilishi kerak bo'lgan qiymatni yozing.
Qaytish sifatida siz o‘zgarmas qiymatlarni ham, butun ifodalarni ham
o‘zlashtirishingiz mumkin, masalan:
132
return 5;
return (x > 5);
return (MyFunction());
Agar MyFunction() funksiyasi faqat ma'lum bir qiymatni
qaytarishi kerak bo‘lsa, funksiyalarni qaytarish uchun 1-ifodadan
foydalaniladi. Ikkinchi ifoda, return (x > 5), agar x 5 dan katta bo'lmasa,
= yoki <= 5 dan bo'lsa, noto'g'ri bo'ladi. Shunday qilib, agar qaytarishda
mantiqiy ifoda berilgan bo'lsa, u holda x o'zgaruvchisining qiymatlari
emas, balki false yoki true (noto'g'ri yoki rost) mantiqiy qiymatlari
qaytariladi.
Funksiyada return kalit so'zi paydo bo'lgandan so'ng ushbu kalit
so'z ortidagi ifoda bajariladi va uning natijasi funksiya chaqiriladigan
joyda asosiy dasturga qaytariladi. Qaytish operatorini bajargandan
so'ng dastur darhol funksiyani chaqirgandan so'ng keyingi qatorga
o'tadi va return kalit so'zidan keyin funksiya tanasida turgan har qanday
ifodalar bajarilmaydi.
Biroq, funksiya bir nechta return operatorlarini o'z ichiga olishi
mumkin.
Listing 10.9. Bir nechta return operatorlaridan foydalanish
1 #include <iostream>
2 using namespace std;
3 int Doubler(int AmountToDouble);
4 int main()
5{
6 int result = 0;
7 int input;
8 cout << "Enter a number between 0 and 10,000 to double: ";
9 cin >> input;
10 cout << "\nBefore doubler is called…";
11 cout << "\ninput: " << input << " doubled: " << result << "\n";
12 result = Doubler(input);
13 cout << "\nBack from Doubler…\n";
14 cout << "\ninput: " << input << " doubled: " << result << "\n";
15 return 0:
16 }
17 int Doubler(int original)
18 {
19 if (original <= 10000)
20 return original * 2;
21 else
22 return -1;
23 cout << "You can't get here!\n"
24 }
Natija:
Enter a number between 0 and 10,000 to double: 9000
Before doubler is called…
input: 9000 doubled: 0
133
Back from doubler…
input: 9000 doubled: 18000
Enter a number between 0 and 10,000 to double: 11000
Before doubler is called…
input: 11000 doubled: 0
Back from doubler…
input: 11000 doubled: -1
Tahlil:
11-qatorda dastur foydalanuvchiga sonni kiritishni taklif qiladi va
uni input o'zgaruvchisida saqlaydi. 13-qatorda siz kiritgan son local
result o'zgaruvchisining qiymati bilan birga ko'rsatiladi. 14-qatorda
Doubler () funksiyasi chaqiriladi va kiritilgan qiymat unga parametr
sifatida uzatiladi. Funksiya natijasi local result o'zgaruvchisiga beriladi
va 16-qatorda ushbu o'zgaruvchilarning qiymatlari yana ko'rsatiladi.
Doubler () funksiyasiga tegishli 21-qatorda o'tkazilgan parametr
qiymati 10000 soni bilan taqqoslanadi. Agar u 10000 dan oshmasa,
funksiya asl sonning ikki baravar qiymatini qaytaradi. Agar u 10000
dan katta bo'lsa, funksiya xato xabari sifatida -1 sonini qaytaradi.
25-qatordagi ifodaga hech qachon o‘tmaydi, chunki uzatilgan
parametrning har qanday qiymati uchun (10 000 dan katta yoki yo'q)
funksiyadan qaytish 22-qatorda yoki 24-qatorda amalga oshiriladi,
ammo har qanday holatda ham 25-qatorga o‘tmaydi.
STANDART PARAMETR QIYMATLARI
Prototip va funksiya ta'rifida e'lon qilingan har bir parametr uchun
funksiya chaqiruvida tegishli qiymat o'tkazilishi kerak. O'tkazilgan
qiymat e'lon qilingan tipga ega bo‘lishi kerak. Agar e'lon qilingan
parametr turi uzatilgan argument tipiga to'g'ri kelmasa, kompilyator
xato haqida xabar beradi.
long myFunction (int x = 50);
Ushbu prototipni quyidagicha tushunish kerak. MyFunction
funksiyasi long tipdagi qiymatni qaytaradi va int tipidagi parametrni
oladi. Agar ushbu funksiyani chaqirganda argument berilmasa, uning
o'rniga 50 sonidan foydalaniladi. Shuningdek, funksiyalarning
prototiplarida parametr nomlari talab qilinmaganligi sababli, funksiya
e`lonning oxirgi versiyasi boshqacha tarzda ham yozilishi mumkin:
long myFunction (int = 50);
Standart parametr qiymati e'lon qilinganda funksiya ta'rifi
o'zgarmaydi. Shuning uchun ushbu funksiyaning sarlavhasi avvalgidek
bo‘ladi:
134
long myFunction (int x);
Agar ushbu funksiyani chaqirganda argument o'rnatilmagan bo'lsa,
u holda kompilyator x o'zgaruvchisiga 50 qiymatini beradi. Prototipda
standart qiymat o'rnatilgan parametr nomi funksiya sarlavhasida
ko'rsatilgan parametr nomiga mos kelmasligi mumkin: avtomatik
berilgan qiymat nom bilan emas, balki pozitsiya bilan belgilanadi.
Standart qiymatlarni bir yoki barcha funksiya parametrlariga
o‘zlashtirish mumkin. Ammo bitta cheklov amal qiladi: agar biror bir
parametr standart qiymatga ega bo'lmasa, unga nisbatan oldingi
parametrlarning hech biri standart qiymatga ega bo'lmaydi.
Funksiya prototipining ko‘rinishi quyidagicha:
long myFunction (int Param1, int Param2, int Param3);
keyin Param2 parametriga standart qiymat berilishi mumkin, agar
standart qiymat Param3 parametriga o‘zlashtiringan bo'lsa. Param1
parametriga faqat Param2 parametriga ham, Param3 parametriga ham
standart qiymatlar o‘zlashtiringan taqdirdagina standart qiymat berilishi
mumkin.
Listing 10.10. Funksiya parametrlari
1 #include <iostream>
2 using namespace std;
3 int VolumeCube(int length, int width = 25, int height = 1);
4 int main(){
5 int length = 100;
6 int width = 50;
7 int height = 2;
8 int volume;
9 volume = VolumeCube(length, width, height);
10 cout << "First volume equals: " << volume << "\n";
11 volume = VolumeCube(length, width);
12 cout << "Second time volume equals: " << volume << "\n";
13 volume = VolumeCube(length);
14 cout << "Third time volume equals: " << volume << "\n";
15 return 0;}
16 VolumeCube(int length, int width, int height){
17 return (length width height);}
Natija:
First volume equals: 10000
Second time volume equals: 5000
Third time volume equals: 2500
Tahlil:
5-qatorda VolumeCube () funksiyasining prototipi funksiya uchta
parametrni qabul qilishini e'lon qiladi, oxirgi ikkitasi sukut bo'yicha
o'rnatiladi.
135
Ushbu funksiya uzatilgan o'lchamlarga asoslanib parallelepiped
hajmini hisoblab chiqadi. Agar kenglik qiymati o'tkazilmasa, u holda
kenglik 25 ga, balandlik esa 1 ga teng bo‘ladi. Agar kenglik qiymati
uzatilsa va balandlik qiymati bo'lmasa, u holda faqat balandlik qiymati
sukut bo'yicha o'rnatiladi. Ammo kenglik qiymatini uzatmasdan
balandlik qiymatini funksiyaga o'tkazish mumkin emas.
7-9-qatorlarda parallelepiped o'lchamlarini uzunligi, kengligi va
balandligi bo'yicha saqlash uchun mo'ljallangan o'zgaruvchilar ishga
tushiriladi. Ushbu qiymatlar 11-qatorda VolumeCube() funksiyasiga
o'tkaziladi. Parallelepiped hajmini hisoblab chiqqandan so'ng, natija 12-
qatorda ko'rsatiladi.
13-qatorda VolumeCube () funksiyasi yana chaqiriladi, lekin
balandlik uchun qiymati berilmaydi. Bunday holda, parallelepiped
hajmini hisoblash uchun sukut bo'yicha berilgan balandlik qiymati
ishlatiladi va natijada 14-qatorda ko'rsatiladi. VolumeCube ()
funksiyasining uchinchi chaqiruvida (15-qator) kenglik qiymati ham,
balandlik qiymati ham o'tkazilmaydi. Shuning uchun ularning o'rniga
sukut bo'yicha belgilangan qiymatlar ishlatiladi va natijada 16-qatorda
ko'rsatiladi.
Tavsiya etiladi!
Esda tutingki, funksiya parametrlari uning ichida local
o'zgaruvchilar kabi ishlaydi.
Tavsiya etilmaydi!
Agar ikkinchi parametr uchun sukut bo'yicha ishlatiladigan qiymat
berilmagan bo'lsa, birinchi parametr uchun standart qiymatni
o'rnatmang.
Funksiyaga qiymat sifatida berilgan argumentlar funksiyani
chaqirishda ishlatiladigan o'zgaruvchilarga ta'sir qila olmasligini
unutmang.
Shuni unutmangki, bitta funksiyadagi global o'zgaruvchiga
kiritilgan o'zgarishlar ushbu o'zgaruvchining barcha funksiyalar uchun
qiymatini o'zgartiradi.
C++ tilida bir xil nomdagi bir nechta funksiyalarni yaratish
imkoniyati mavjud. Bunga
deyiladi. Qo‘shimcha yuklangan funksiyalar parametrlar ro‘yxati bilan
bir-biridan farq qilishi kerak, ya`ni bir yoki bir nechta parametrlarning
136
tipi yoki har xil parametrlar soni yoki ikkalasi bir vaqtning o'zida.
Quyidagi misolni ko'rib chiqing:
int myFunction (int, int);
int myFunction (long, long);
int myFunction (long);
myFunction () funksiyasi uch xil parametrlar ro‘yxati bilan qo‘shimcha
yuklangan. Birinchi va ikkinchi versiyalar parametr tiplari bilan,
uchinchisi esa ularning soni bilan farq qiladi.
Qo‘shimcha yuklangan funksiyalarning qaytish qiymatlari tiplari
bir xil yoki har xil bo‘lishi mumkin.
Funksiyalarning qo‘shimcha yuklanishi deb
ham ataladi. Poli - ko'p, morfe – ko‘rinish, ya'ni polimorfik funksiya-
bu ko‘rinishilarning xilma-xilligi bilan ajralib turadigan funksiya.
Funksiyaning polimorfizmi deganda dasturda turli maqsadlarga ega
bo'lgan funksiyaning bir nechta qo‘shimcha yuklangan versiyalari
mavjudligi tushuniladi. Parametrlar sonini yoki tipini o'zgartirib, ikki
yoki undan ortiq funksiyaga bir xil nom berilishi mumkin.
Aytaylik, siz unga berilgan har qanday qiymatni ikki baravar
oshiradigan funksiyani yaratyapsiz. Shu bilan birga, siz unga int, long,
float yoki double kabi tiplarni berishni xohlaysiz. Funksiyalarni
qo‘shimcha yuklamasdan, siz to'rt xil funksiyani yaratishingiz kerak
bo'ladi:
int DoubleInt(int);
long DoubleLong(long);
float DoubleFloat(float);
double DoubleDouble(double);
Funksiyalarni qo‘shimcha yuklash orqali quyidagi e`lonlardan
foydalanish mumkin:
int Double(int);
long Double(long);
float Double(float);
double Double(double);
Qo‘shimcha yuklangan funksiyalardan foydalangan holda,
dasturda uzatiladigan o'zgaruvchilar tipiga mos keladigan kerakli
funksiyani chaqirish haqida tashvishlanishning hojati yo'q. Qo‘shimcha
yuklangan funksiyani chaqirganda, kompilyator avtomatik ravishda
qaysi funksiya variantidan foydalanish kerakligini aniqlaydi.
Funksiyaning haddan tashqari yuklanishi Listing 10.11 da ko'rsatilgan.
Listing 10.11 Funksiyalarning polimorfizmi
1 #include <iostream>
2 using namespace std;
137
3 int Double(int);
4 long Double(long);
5 float Double(float);
6 double Double(double);
7 int main()
8{
9 int myInt = 6500;
10 long myLong = 65000;
11 float myFloat = 6.5F;
12 double myDouble = 6.5e20;
13 int doubledInt;
14 long doubledLong;
15 float doubledFloat;
16 double doubledDouble;
17 cout << "myInt: " << myInt << "\n";
18 cout << "myLong: " << myLong << " n";
19 cout << "myFloat: " << myFloat << "\n";
20 cout << "myDouble: " << myDouble << "\n";
21 doubledInt = Double(myInt);
22 doubledLong = Double(myLong);
23 doubledFloat = Double(myFloat):
24 doubledDouble = Double(myDouble);
25 cout << "doubledInt: " << doubledInt << "\n";
26 cout << "doubledLong: " << doubledLong << "\n";
27 cout << "doubledFloat: " << doubledFloat << "\n";
28 cout << "doubledDouble: " << doubledDouble << " n";
29 return 0;
30 }
31 int Double(int original)
32 {
33 cout << "In Double(int)\n";
34 return 2 * original;
35 }
36 long Double(long original)
37 {
38 cout << "In Double(long)\n";
39 return 2 original;
40 }
41 float Double(float original)
42 {
43 cout << "In Double(float)\n";
44 return 2 + original;
45 }
46 double Double(double original)
47 {
48 cout << "In Double(double)\n";
49 return 2 + original;
50 }
Natija:
myInt: 6500
138
myLong: 65000
myFloat: 6.5
myDouble: 6.5e+20
In Double(int)
In Double(long)
In Double(float)
In Double(double)
DoubledInt: 13000
DoubledLong: 130000
DoubledFloat: 13
DoubledDouble: 1. 3e+21
Tahlil:
Double () funksiyasi to'rt tipdagi parametrlarni qabul qilish uchun
qo‘shimcha yuklanadi: int, long, float va double. Funksiyalarning
prototiplari 3-6 qatorlarni, ta'riflar esa 31-50 qatorlarni egallaydi.
Asosiy dastur tanasida 8 ta lokal o'zgaruvchilar e'lon qilinadi. 17-
20-qatorlarda dastlabki to'rtta o'zgaruvchi ishga tushiriladi va 25-28-
qatorlarda qolgan to'rtta o'zgaruvchiga Double() funksiyasining
dastlabki to'rtta o'zgaruvchisining qiymatlarini uzatish natijalari
beriladi. E'tibor bering, murojaat turi bo'yicha bu funksiyalar bir-
biridan farq qilmaydi.
Nazorat savollari va topshiriqlar:
1. Funksiya prototipini e'lon qilish va funksiyani aniqlash o'rtasidagi
farq nima?
2. Prototipda ko'rsatilgan parametr nomlari, funksiya ta'rifi va chaqiruvi
bir-biriga mos kelishi kerakmi?
3. Agar funksiya qiymatni qaytarmasa, qanday qilib bunday funksiyani
e'lon qilish kerak?
4. Lokal o'zgaruvchi nima? Rekursiya nima?
5. Global o'zgaruvchilardan qachon foydalanish kerak?
6. Perimetr funksiyasining ta'rifini 1-mashqdagi e'longa muvofiq
yozing. U qabul qilgan ikkita parametr to'rtburchakning uzunligi,
kengligini anglatadi va funksiya uning perimetrini qaytaradi.
7. Xatolar: bu funksiyada nima noto'g'ri?
#include <iostream>
using namespace std;
void myFunc(unsigned short int x);
int main()
{
unsigned short int x, y;
y = myFunc(int);
cout << "x: " << x << " y: " << y << "\n";
}
void myFunc(unsigned short int x)
139
{
return (4*x);
}
8. a haqiqiy va n butun sonlari berilgan(n>0). a n = a ⋅ a ⋅ ... ⋅ a. (a, n
marta ko‘paytirilgan) a ning n- darajasi hisoblansin.
1,5 2 2,25
9. Sonlar o‘qida 2 ta haqiqiy a, b (a<b) sonlar va n butun son (n>1)
berilgan. [a,b] kesma n ta teng kesmaga bo‘lingan. Kesmachalar
uzunligi h ni hamda (a,a+h, a+2h, …, b). [a,b] kesmani bo‘lishdan hosil
bo‘lgan nuqtalar soni chiqarilsin.
1.0 3.0 5 0.4 1 1.4 1.8 2.2 2.6 3.0
140
11-MAVZU. FUNKSIYANING MASSIVLI
PARAMETRLARI.
Argumentlarni qiymat va havola orqali yuborish
Constant havolalar (o‘zgarmas havolalar)
Funksiya parametrida massiv
Siz massivlarni funksiyaga o'tkazishingiz mumkin: Misolda
funksiya (myFunction) parametr sifatida massivni oladi (int
myNumbers[5]). Funksiyani chaqirganda, uni argument sifatida
o'tkazishda faqat massiv nomidan foydalanish kerak
myFunction(myNumbers). Biroq, massiv to'liq e`lon qilinishi uchun
parametr sifatida massiv o‘lchami berilishi zarur (int myNumbers[5]).
void myFunction(int myNumbers[5]) {
for (int i = 0; i < 5; i++) {
cout << myNumbers[i] << "\n";
}
}
int main() {
int myNumbers[5] = {10, 20, 30, 40, 50};
myFunction(myNumbers);
return 0;
}
C++ butun massivni funksiyaga argument sifatida o'tkazishga
ruxsat bermaydi. Biroq, siz indekssiz massiv nomini ko'rsatib,
ko'rsatgichni massivga o'tkazishingiz mumkin. Agar siz bitta o'lchovli
massivni funktsiyadagi argument sifatida o'tkazmoqchi bo'lsangiz,
funksiyani quyidagi uchta usuldan birida e'lon qilishingiz kerak bo'ladi:
142
Funksiyani kompilyatsiya qilishda uning parametrlari uchun
alohida xotira bo'limlari ajratiladi. Funksiya chaqirilganda, parametrlar
o'rniga uzatiladigan argumentlarning qiymatlari hisoblanadi. Keyin
argumentlarning qiymatlari ushbu xotira bo'limlariga kiritiladi. Ya'ni,
funksiya obyektlarning o'zlarini emas, balki obyektlar qiymatlarining
nusxalarini boshqaradi.
Parametrlarni havola orqali uzatishda obyektga havola uzatiladi,
bu orqali biz uning qiymatini emas, balki obyektlarning o'zini
boshqarishimiz mumkin. Shunday qilib, avvalgi misolni havola orqali
uzatish yordamida qayta yozamiz:
Listing 11.3.
#include <iostream>
using namespace std;
void square(int &, int &);
int main()
{
int a = 4;
int b = 5;
cout << "Before square: a = " << a << "\tb="<< b << endl;
square(a, b);
cout << "After square: a = " << a <<"\tb=" << b << endl;
return 0;
}
void square(int &a, int &b)
{
a = a * a;
b = b * b;
cout << "In square: a = " << a <<"\tb=" << b << endl;
}
Havola orqali uzatish funksiyadan bir vaqtning o'zida bir nechta
qiymatlarni qaytarishga imkon beradi. Shuningdek, parametrlarni
havola orqali uzatish juda katta obyektlarni uzatishda samaraliroq.
Chunki bu holda qiymatlarni nusxalash sodir bo'lmaydi va funksiya
obyektning o'zi emas, balki uning qiymatidan foydalanadi.
Listing 11.4. Argumentlarni havola orqali uzatishdan, havolalarni
argument sifatida uzatishni farqlash kerak:
143
#include <iostream>
1
using namespace std;
2
void square(int, int);
3
int main()
4
{
5
int a = 4;
6
int b = 5;
7
int &aRef = a;
8
int &bRef = b;
9
cout << "Before square: a = " << a << "\tb="<< b <<
10
endl;
11
square(aRef, bRef);
12
cout << "After square: a = " << a <<"\tb=" << b << endl;
13
return 0;
14
}
15
void square(int a, int b)
16
{
17
a = a * a;
18
b = b * b;
19
cout << "In square: a = " << a <<"\tb=" << b << endl;
20
}
Agar funksiya qiymat bo'yicha argumentlarni qabul qilsa, u holda
funksiya ichidagi parametrlarning o'zgarishi tashqi obyektlarga ham
ta'sir qilmaydi, hatto funksiya chaqirilganda obyektlarga havolalar unga
o'tkazilsa ham.
Parametrlarni qiymat bo'yicha uzatish kichik obyektlarni
funksiyaga o'tkazish uchun ko'proq mos keladi, ularning qiymatlari
keyinchalik funksiya foydalanadigan xotiraning ma'lum qismlariga
ko'chiriladi.
Parametrlarni havola orqali uzatish katta obyektlarni funksiyaga
o'tkazish uchun ko'proq mos keladi, bu holda siz obyektning barcha
tarkibini xotira maydoniga nusxalashingiz shart emas, buning natijasida
dasturning ishlashi oshadi.
Agar funksiya mos havolalar bo'yicha argumentlarni qabul qilsa, u
holda funksiyaga o‘zgarmasni(constant) o'tkazish uchun parametrlar
ham o‘zgarmasga havolani ko'rsatishi kerak.
FUNKSIYA PARAMETRIDA MASSIV
Agar funksiya massivni parametr sifatida qabul qilsa, aslida
ko'rsatgich massivning birinchi elementiga ushbu funksiyaga
o'tkaziladi. Ya'ni, ko'rsatgichlarda bo'lgani kabi, biz qiymatlarni
o'zgartirishimiz mumkin bo'lgan manzilga egamiz. Shuning uchun
quyidagi funksiya e`lonlari teng kuchli:
void print(int numbers[]);
144
void print(int *numbers);
Listing 11.5.
1 #include <iostream>
2 void print(int []);
3 int main()
4{
5 int nums[] = {1, 2, 3, 4, 5};
6 print(nums);
7 return 0;
8}
9
10 void print(int numbers[])
11 {
12 for(int i=0;i<5;i++ )
13 {
14 std::cout << i<<" number: " << numbers[i] << std::endl;}
15 }
Massiv sifatida aniqlangan parametr birinchi elementga ko'rsatgich
sifatida aniq ko'rib chiqilganligi sababli, biz massiv uzunligini to'g'ri
ololmaymiz, masalan, quyidagicha:
Listing 11.6.
#include <iostream>
1
void print(int *);
2
int main()
3
{
4
int nums[] = {1, 2, 3, 4, 5};
5
print(nums);
6
return 0;
7
}
8
9
void print(int *numbers)
10
{
11
std::cout << "First number: " << *numbers <<
12
std::endl;
13
}
145
Nazorat savollari va topshiriqlar:
1. C++ da havolalar qanday hosil qilinadi?
2. C++ da havolalar qanday ishlatish mumkin?
3. C++ da havola va ko‘rsatkich orasidagi farq nimadan iborat?
4. Ko‘rsatkich va havolalar yana qayerda uchratish mumkin?
5. Berilgan x va y o‘zgaruvchilardagi qiymatlarning kichigini x ga
kattasini y ga yozadigan Minmax(x,y) protsedurasi tasvirlansin(x,y
haqiqiy parametrli bir vaqtning o‘zida kiruvchi va chiquvchi). Bu
protsedura 4 marta chaqirilib, berilgan a b c d sonlarining eng kattasi va
eng kichigi aniqlansin.
4319 91
6. MonthDays(m,y) funksiyasidan foydalanib berilgan, to‘g‘ri
(d,m,y) kun, oy, yil formatdagi sanadan oldingi kun sanasini
hisoblovchi PrevDate(d,m,y) prosedurasi tasvirlansin. Prosedurani
qo‘llab berilgan 3 ta sanadan oldingi sanalar topilsin.
1 3 2004 29 2 2004
1 1 2007 31 12 2006
1 9 2008 31 8 2008
146
12-MAVZU. REKURSIV VA QAYTA YUKLANUVCHI
FUNKSIYALAR
O'rnatilgan inline funksiyalari
Rekursiya
Rekursiv funksiyalar
Dasturchiga beminnat xizmat ko'rsatadigan maxsus mavzular
qatoriga kiritilgan inline funksiyalari va funksiyalarning rekursiyasi
kiradi. Rekursiyaga kelsak, dasturchilarning ushbu ajoyib ixtirosi bilan
boshqa yo'llar bilan hal qilinmaydigan ba`zi muammolarni hal qilishga
imkon beradi.
INLINE FUNKSIYALARI
Odatda, funksiyani o‘zlashtirishda kompilyator funksiya
operatorlarini saqlash uchun xotirada faqat bitta katakcha blokini
saqlaydi. Funksiya chaqirilgandan so'ng, dasturni boshqarish ushbu
operatorlarga o'tkaziladi va funksiyadan qaytgach, dastur
chaqirilgandan keyingi qatordan dasturning bajarilishi davom etadi.
Agar siz ushbu funksiyani 10 marta chaqirsangiz, unda har safar sizning
dasturingiz bir xil buyruqlar to'plamini ishlab chiqadi. Bu shuni
anglatadiki, funksiyaning 10 emas, balki faqat bitta nusxasi mavjud.
Ammo funksiya operatorlarini o'z ichiga olgan xotira maydoniga
har bir o'tish dasturning bajarilishini sekinlashtiradi. Agar funksiya
hajmi kichik bo'lsa (bitta yoki ikkita satrdan iborat bo'lsa), dasturdan
funksiyaga va orqaga o'tish o'rniga, kompilyatorga funksiya kodini
to'g'ridan-to'g'ri dasturga kiritish buyrug'ini bersangiz, samaradorlikda
ba'zi yutuqlarni olishingiz mumkin. Samaradorlik deganda, odatda
dasturni bajarish tezligi tushuniladi.
Agar funksiya inline kalit so'zi bilan e'lon qilingan bo'lsa,
kompilyator kompyuter xotirasida funksiyani yaratmaydi, balki uning
satrlarini to'g'ridan-to'g'ri dastur kodiga ko'chiradi.
Inline funksiyadan foydalanish Listing 12.1 da ko'rsatilgan.
Listing 12.1. Inline funksiyalaridan foydalanish
1 #include <iostream>
2 using namespace std;
3 inline int Double(int);
4 int main()
5 int target;
6 cout << "Enter a number to work with:
7 cin >> target;
8 cout << " n";
9 target = Double(target);
147
10 cout << "Target: " << target << endl;
11 target = Double(target);
12 cout << "Target: " << target << endl;
13 target = Double(target);
14 cout << "Target: " << target << endl;
15 return 0;
16 }
17 int Double(int target)
18 {
19 return 2•target;
20 }
Natija:
Enter a number to work with: 20
Target: 40
Target: 80
Target: 160
Tahlil:
3-qatorda int tipidagi parametrni qabul qiladigan va int tipidagi
qiymatni qaytaradigan o'rnini bosuvchi double () funksiyasi e'lon
qilinadi. Ushbu e'lon boshqa har qanday prototipga o'xshaydi, faqat
qaytish tipidan oldin inline kalit so'zi mavjud.
Ushbu prototipni kompilyatsiya qilish natijasi dasturdagi satrlarni
almashtirishga teng:
target = 2 * target;
double()funksiyasini chaqirish:
target = Double(target);
ESLATMA: Inline kalit so'zi kompilyator uchun funksiya kodini
chaqiruv joyidagi dasturga nusxalash uchun xizmat qiladi.
Funksiya o'zini o'zi chaqirishi to'g'ridan-to'g'ri yoki bilvosita
bo‘lishi mumkin. Bu jarayonga deb ataladi. Agar funksiya
o'zini o'zi chaqirsa deb ataladi. Agar funksiya boshqa
funksiyani chaqirsa, u holda birinchisini keltirib chiqaradigan bo'lsa,
unda bu holda sodir bo'ladi.
Ba'zi muammolar rekursiya yordamida osongina hal qilinadi.
Shunday qilib, rekursiya ma'lumotlar bo'yicha ma'lum bir funksiya
bajarilgan va keyin olingan natijalar bo'yicha xuddi shu funksiya
bajarilgan hollarda foydalidir.
Rekursiyaning ikkala turi (to'g'ridan-to'g'ri va bilvosita) ikkita
rolda paydo bo'ladi: ba'zilari oxir-oqibat tugaydi va qaytib keladi,
boshqalari esa hech qachon tugamaydi va ish vaqti xatosini keltirib
chiqaradi.
148
Shuni ta'kidlash kerakki, funksiya o'zini o'zi chaqirganda, ushbu
funksiyaning yangi nusxasi bajariladi. Bunday holda, ikkinchi xil
rekursiyada lokal o'zgaruvchilar birinchisidagi lokal o'zgaruvchilardan
mustaqil bo'lib, bir-biriga bevosita ta'sir o'tkaza olmaydi, hech
bo'lmaganda main() funksiyasidagi lokal o'zgaruvchilar har qanday
boshqa funksiyadagi lokal o'zgaruvchilarga ta'sir qilishi mumkin.
Misolni ko'rsatish uchun rekursiya yordamida muammoni hal
qilish, Fibonachchi seriyasini ko'rib chiqing:
1, 1, 2, 3,5, 8, 13, 21, 34…
Qatorning har bir soni undan oldingi ikkita sonning yig'indisidir.
Masalan, Fibonachchi seriyasining 12-sonini aniqlash kerak bo‘lsin.
Ushbu muammoni hal qilishning bir usuli bu qatorni tahlil
qilishdir. Birinchi ikkita son 1 ga teng. Har bir keyingi son oldingi
ikkitasining yig'indisiga teng. Shunday qilib, o'n yettinchi son o'n
oltinchi va o'n beshinchi son yig'indisiga teng. Umumiy holda, n - son
(n-2)-chi va (n-1)-chi yig'indisiga teng, agar n>2 bo'lsa.
Rekursiv funksiyalar uchun rekursiyani tugatish shartini
o‘zlashtirish kerak. Dasturda rekursiyani to'xtatishga majbur qiladigan
shart bo‘lishi kerak yoki u hech qachon tugamaydi. Fibonachchi
qatorida to'xtash sharti n < 3 ifodasidir.
Bu quyidagi algoritmdan foydalanadi:
1. Biz foydalanuvchiga Fibonachchi qatoridagi qaysi atamani
hisoblash kerakligini ko'rsatishni taklif qilamiz.
2. Biz fib () funksiyasini chaqiramiz, argument sifatida
foydalanuvchi tomonidan belgilangan Fibonachchi qatoridagi sonlarni
uzatamiz.
3. fib () funksiyasida argument tahlili (n) amalga oshiriladi. Agar n
< 3 bo'lsa, funksiya 1 qiymatini qaytaradi; aks holda fib () funksiyasi n-
2 qiymatini argument sifatida o'tkazib, o'zini o'zi chaqiradi (rekursiv),
n-1 qiymatini argument sifatida uzatadi va keyin yig'indini qaytaradi.
Agar siz fib (1) funksiyasini chaqirsangiz, u 1 ni qaytaradi. Agar
siz fib (2) funksiyasini chaqirsangiz, u ham 1 ni qaytaradi. Agar siz fib
(3) funksiyasini chaqirsangiz, u fib (2) va fib (1) funksiyalari tomonidan
qaytarilgan qiymatlar yig'indisini qaytaradi. fib (2) funksiyasini
chaqirish 1 qiymatini va fib (1) funksiyasini chaqirish 1 qiymatini
qaytarganligi sababli, fib (3) funksiyasi 2 qiymatini qaytaradi.
Agar siz fib (4) funksiyasini chaqirsangiz, u fib (3) va fib (2)
funksiyalari tomonidan qaytarilgan qiymatlar yig'indisini qaytaradi. Biz
149
allaqachon fib (3) funksiyasi 2 qiymatini qaytarishini va fib (2)
funksiyasi 1 qiymatini qaytarishini aniqladik, shuning uchun fib (4)
funksiyasi bu sonlarni qo‘shadi va Fibonachchi qatorining to'rtinchi
elementi 3 qiymatini qaytaradi.
Keling, keyingi qadamni ko‘ramiz. Agar siz fib(5) funksiyasini
chaqirsangiz, u fib (4) va fib (3) funksiyalari tomonidan qaytarilgan
qiymatlar yig'indisini qaytaradi. fib(4) funksiyasi 3 qiymatini va fib (3)
funksiyasi 2 qiymatini qaytaradi, shuning uchun yig`indi 5 soniga teng
bo'ladi.
Ushbu usul bu muammoni hal qilishning eng samarali usuli emas.
Masalan, fib(20) funksiyasini chaqirganda, fib() funksiyasi 13529
marta chaqiriladi. Agar siz Fibonachchi qatorining ko'p elementlarini
chaqirsangiz, sizda yetarli xotira bo'lmasligi mumkin. Har bir fib()
funksiyasi chaqirilganda, ma'lum bir xotira maydoni saqlanadi.
Funksiyadan qaytgach, xotira bo'shatiladi. Ammo rekursiv murojaatlar
bilan xotiraning barcha yangi sohalari zaxiralanadi va ushbu yondashuv
bilan tizim xotirasi juda tez tugashi mumkin. fib() funksiyasini amalga
oshirish Listing 12.2 da ko'rsatilgan.
Listing 12.2 da keltirilgan dasturni ishga tushirganda, Fibonachchi
qatorining kichik elementlarini (15 dan kam) o'rnating. Ushbu dastur
rekursiyadan foydalanganligi sababli katta xotira ishlatishi mumkin.
Listing 12.2. Fibonachchi sonini topish
1 #include <iostream>
2 using namespace std;
3 int fib (int n);
4 int main()
5{
6 int n, answer;
7 cout << "Enter number to find: "; cin >> n;
8 cout << "\n\n";
9 answer = fib(n);
10 cout << answer << " is the " << n << "Fibonacci number\n";
11 return 0;
12 }
13 int fib (int n)
14 {
15 cout << "Processing fib(" << n << ")… ";
16 if (n < 3 )
17 {
18 cout << "Return 1!\n";
19 return (1);
20 }
21 else
150
22 {
23 cout << "Call fib(" << n-2 << ") and fib(" << n-1 <<
24 ").\n";
25 return( fib(n-2) + fib(n-1));
26 }
}
Natija:
Enter number to find: 6
Processing fib(6)… Call fib(4) and fib(5).
Processing fib(4)… Call fib(2) and fib(3).
Processing fib(2)… Return 1!
Processing fib(3)… Call fib(1) and fib(2).
Processing fib(1)… Return 1!
Processing fib(2)… Return 1!
Processing fib(5)… Call fib(3) and fib(4).
Processing fib(3)… Call fib(1) and fib(2).
Processing fib(1)… Return 1!
Processing fib(2)… Return 1!
Processing fib(4)… Call fib(2) and fib(3).
Processing fib(2)… Return 1!
Processing fib(3)… Call fib(1) and fib(2).
Processing fib(1)… Return 1!
Processing fib(2)… Return 1!
8 is the 6th Fibonacci number
Tahlil:
ESLATMA: Ba'zi kompilyatorlar cout obyekti bilan ifodalardagi
operatorlardan foydalanishda qiyinchiliklarga duch kelishadi. Agar siz
23-qatorda ogohlantirish olsangiz, 23-qator uchun ayirish amalini qavs
ichiga yozing:
cout << "Call fib(" << (n-2) << ") and fib(" << n-1 << ").\n";
151
Ushbu misolda n o'zgaruvchisi 6 qiymatiga teng, shuning uchun fib
(6) funksiyasi main () funksiyasidan chaqiriladi. Dasturning bajarilishi
fib() funksiyasining tanasiga o'tadi va 16-qatorda uzatilgan
argumentning qiymati 3 soni bilan taqqoslanadi. 6 soni 3 sonidan katta
bo'lgani uchun, fib(6) funksiyasi fib(4) va fib(5) funksiyalari tomonidan
qaytarilgan qiymatlar yig'indisini qaytaradi:
return( fib(n-2) + fib(n-1));
12.1-rasm
fib(5) funksiyasi chaqirilganda, 3 sonidan kichik bo'lmagan
argument o'tkazilganligi sababli, fib() funksiyasi yana chaqiriladi, bu
safar 4 va 3 argumentlar bilan chaqiriladi. fib (4) funksiyasi o'z
navbatida fib(3) va fib(2) funksiyalarini chaqiradi.
Listing 12.2 da keltirilgan dasturning natijalari va oraliq
bosqichlari ekranda ko'rsatiladi. Avval 1, keyin 2, 3 sonlarini kiritib,
ushbu dasturni kompilyatsiya qiling va bajaring va ko'rsatilgan
ma'lumotlarni diqqat bilan kuzatib, 6 sonigacha yetib boring. fib()
funksiyasining har bir rekursiv chaqiruvida n o'zgaruvchining qiymati
o‘zgarib boradi. C++ dasturlashda rekursiya tez-tez uchratish mumkin,
152
lekin ba'zi hollarda u kuchli vositadir. Shuni ta`kidlash kerakki,
rekursiya dasturlashning eng qiyin mavzularidan biridir.
153
13-MAVZU. C++ DA FAYL TUSHUNCHASI. FAYLDAN
O’QISH VA YOZISH FUNKSIYALARI. FAYLLAR USTIDA
AMALLAR.
Fayl yaratish
Faylga yozish va fayldan o’qish
Get va getline funksiyalari
Agar dasturda juda ko'p kod mavjud bo'lsa, unda kodning alohida
qismlarini alohida fayllarga yozish yanada maqbul bo'ladi. Masalan,
ba'zi funksiyalar bitta dastur kodi faylida, boshqa funksiyalar boshqa
faylda saqlanishi mumkin.
Masalan, quyidagi kodga ega bo'lgan faktorial cpp faylini
aniqlaymiz.
Bu faktorialni hisoblash funksiyasi. Boshqa faktorial funksiyani
e`lon qilishni o'z ichiga olgan faktorial faylini qo'shamiz.
factorial.cpp:
1 int factorial(int);
2 int factorial(int n)
3{
4 if (n > 1)
5 return n * factorial(n - 1);
6 return 1;
7}
sum.cpp:
1 int sum(int a)
2{
3 if(a>0)
4 return (1+a)*a/2.0-a;
5 return 0;
6}
Listing 13.1.
1 #include "iostream"
2 #include "factorial.cpp"
3 #include "sum.cpp"
4 int main()
5{
6 int result = factorial(7);
7 std::cout << "result = " << result <<
8 std::endl;
9 std::cout<<sum(6);
10 return 0;
11 }
154
Asosiy funksiya sonning faktorialini hisoblash uchun faktorial
funksiyasini chaqiradi. Ammo boshqa faylda aniqlangan funksiyadan
foydalanish uchun siz uning e`lonini qo'shishingiz kerak.
Funksiya e`loni to'g'ridan-to'g'ri dasturning asosiy fayliga qo'shildi.
Ammo, agar funksiyalar alohida fayllarda aniqlangan bo'lsa, unda
funksiya e`lonini maxsus sarlavha fayllariga joylashtirish va keyin
ushbu fayllarni ulash maqbuldir.
Faktorial faylini cpp. fayliga ulash mumkin. Ammo funksiyani
o'zgartirganda, uning e`lonini o'zgartirish kerak bo‘lishi mumkin. Agar
faktorial funksiyasi bir nechta fayllarda ishlatilsa, unda ushbu
fayllarning har birida siz uning e`lonini o'zgartirishingiz kerak bo'ladi.
Bunday holda, funksiya e`lonini bitta faylda o'zgartirish kifoya -
faktorial.cpp.
Ko'pgina kompyuter dasturlari fayllar bilan ishlaydi va shuning
uchun fayllarni yaratish, o'chirish, yozish, o'qish, ochish kerak bo'ladi.
Fayl nima? -ma'lum bir diskda saqlanishi mumkin bo'lgan
baytlarning nomlangan to'plami. Shuningdek, fayl .txt kabi o'ziga xos,
noyob nomga ega bo'lgan ba'zi baytlar ketma-ketligini anglatishi aniq.
Xuddi shu katalogda bir xil nomdagi fayllar bo‘lishi mumkin emas.
Fayl nomi nafaqat uning nomini, balki kengaytmani ham anglatadi,
masalan: fayl.txt va fayl.dat - turli xil fayllar, garchi ular bir xil
nomlarga ega bo'lsa ham. To'liq fayl nomi esa fayl nomi ko'rsatilgan
fayl katalogiga to'liq manzil, masalan: D:\docs\file.txt. Ushbu asosiy
tushunchalarni tushunish juda muhim, aks holda fayllar bilan ishlash
qiyin bo'ladi.
Fayllar bilan ishlash uchun siz <fstream> sarlavha faylini
ulashingiz kerak. bu fayllarni o'qish va yozish uchun asosiy turlarni
belgilaydi.
Xususan, bu:
ifstream: fayldan o'qish uchun
ofstream: faylga yozish uchun
fstream: yozish va o'qishni birlashtiradi.
Faylga kirish / chiqish konsolga kirish/chiqishga o'xshaydi, yagona
farq shundaki, kirish/chiqish ekranda emas, balki faylda amalga
oshiriladi. Agar standart qurilmalarga kirish/chiqish cin va cout
obyektlari yordamida amalga oshirilsa, u holda fayl kirish/chiqishni
155
tashkil qilish uchun cin va cout operatorlariga o'xshash ishlatilishi
mumkin bo'lgan maxsus obyektlarni yaratish kifoya.
Masalan, siz matnli fayl yaratishingiz va unga C++ da fayllar bilan
ishlash uchun dastur kodlarini yozishingiz kerak. Buning uchun siz
quyidagi amallarni bajarishingiz kerak:
ofstream sinf obyektini yarating;
sinf obyektini yozish amalga oshiriladigan fayl bilan
bog'lang;
faylga satr yozing;
faylni yoping.
Nima uchun ifstream sinfini emas, balki ofstream sinf obyektini
yaratish kerak? Chunki siz faylga yozishingiz kerak va agar siz fayldan
ma'lumotlarni o‘qishingiz kerak bo'lsa, unda ifstream sinfining obyekti
yaratiladi.
ofstream /*obyekt nomi*/;
Keling, obyektni – fout deb ataymiz.
ofstream fout;
Faylga yozishni amalga oshirish uchun obyekt kerak.
fout.open("cppstudio.txt"); // obyektni faylga ulash
Nuqta amali orqali biz open () sinf funksiyasiga kiramiz, uning
qavslarida fayl nomini ko'rsatamiz. Belgilangan fayl dastur bilan joriy
katalogda yaratiladi. Agar ushbu nomdagi fayl mavjud bo'lsa, unda
mavjud fayl yangisi bilan almashtiriladi. Shunday qilib, faylga satrni
yozish qoladi. Bu shunday amalga oshiriladi:
fout << "C++ da fayl bilan ishlash"; // faylga satr yozish
fout obyekti bilan birgalikda oqimga o'tkazish amalidan
foydalanib, C++ da fayllar bilan ishlash satri faylga yoziladi. Fayl
tarkibini o'zgartirishning hojati yo'qligi sababli, uni yopish kerak.
fout.close(); // faylni yopish
1 va 2-bosqichlarni birlashtirish mumkin, ya'ni bitta satrda obyekt
yaratish va uni fayl bilan bog'lash mumkin. Bu quyidagicha amalga
oshiriladi:
ofstream fout("cppstudio.txt");
Biz barcha kodni birlashtiramiz va quyidagi dasturni olamiz.
Listing 13.2.
1 #include <fstream>
2 using namespace std;
3
156
4 int main(int argc, char* argv[])
5{
6 ofstream fout("cppstudio.txt");
7 fout << "C++ da fayl bilan ishlash";
8 fout.close();
9 return 0;
10 }
157
Dastur to'g'ri ishladi, lekin har doim ham shunday bo'lmaydi, hatto
kod to‘g`ri yozilgan bo'lsa ham.
Shunday qilib, C++ da barcha kodlar juda aniq bo‘lishi uchun
butun qiymatlarni qaytaradigan — is_open () funksiyasi taqdim etiladi:
1 — agar fayl muvaffaqiyatli ochilgan bo'lsa, 0 — agar fayl ochilmagan
bo'lsa. Agar fayl ochilmasa, tegishli xabar ko'rsatiladi.
Listing 13.4.
1 #include <fstream>
2 #include <iostream>
3 using namespace std;
4
5 int main(int argc, char* argv[])
6{
7 char buff[50]; // satrni saqlash uchun massiv
8 ifstream fin("cppstudio.doc"); // fayl nomi notogri
9
10 if (!fin.is_open())
11 cout << "Faylni ochib bo‘lmaydi!\n";
12 else
13 {
14 fin >> buff; // fayldan 1-so'zni oqib olish
15 cout << buff << endl; // shu so'zni chop etish
16
17 fin.getline(buff, 50); // fayldan satrni o'qib olish
18 fin.close(); // faylni yopish
19 cout << buff << endl; // satrni chop etish
20 }
21 return 0;
22 }
13.2-rasm
13.2-rasmdan ko'rinib turibdiki, dastur faylni ochib bo‘lmasligi
haqida xabar berdi. Shuning uchun, agar dastur fayllar bilan ishlayotgan
bo'lsa, fayl mavjudligiga amin bo'lsangiz ham is_open () funksiyadan
foydalanish tavsiya etiladi.
Fayllarni ochish rejimlari fayllardan foydalanish xususiyatini
belgilaydi. ios_base sinfida rejimni o'rnatish uchun fayllarni ochish
rejimini belgilaydigan o‘zgarmaslar mavjud (13.1-jadvalga qarang).
158
Rejim Izoh
ios_base::in Faylni o‘qish uchun ochish
ios_base::out Faylni yozish uchun ochish
ios_base::ate Faylni ochishda ko‘rsatkichni fayl oxiriga
o‘tkazish
ios_base::app Fayl oxiriga yozish uchun faylni ochish
ios_base::trunc Fayl ma`lumotlarini o‘chirish (agar u mavjud
bo‘lsa)
ios_base::binary Faylni ikkilik rejimda ochish
13.1-jadval
Fayllarni ochish rejimlari to'g'ridan-to'g'ri obyekt yaratilganda yoki
open () funksiyasi chaqirilganda o'rnatilishi mumkin.
ofstream fout("cppstudio.txt", ios_base::app);
fout.open("cppstudio.txt", ios_base::app);
Fayllarni ochish rejimlari mantiqiy operatorlar yoki | yordamida
birlashtirilishi mumkin, masalan: ios_base:: out | ios_base:: trunc —
faylni avval tozalash orqali yozib olish uchun ochish.
Ofstream sinfidagi obyektlar sukut bo'yicha fayllar bilan
bog'langanda ios_base::out | ios_base::trunc fayllarini ochish
rejimlarini o'z ichiga oladi. Ya'ni, agar mavjud bo'lmasa, fayl yaratiladi.
Agar fayl mavjud bo'lsa, unda uning tarkibi o'chiriladi va faylning o'zi
yozishga tayyor bo'ladi.
Ifstream sinfidagi obyektlar fayl bilan bog'lanib, sukut bo'yicha
ios_base::in faylini ochish rejimiga ega. Shuni esda tutingki, ate va app
rejimlari tavsifga ko'ra juda o'xshash, ikkalasi ham ko'rsatgichni
faylning oxiriga ko'chiradi, lekin app rejimi faqat faylning oxiriga
yozishga imkon beradi va ate rejimi shunchaki bayroqni faylning
oxiriga o'zgartiradi va yozish joylarini cheklamaydi. Biz sizeof ()
amalidan foydalanib, C++ da asosiy ma'lumotlar tiplarining
xususiyatlarini hisoblaydigan va ularni faylga yozadigan dasturni ishlab
chiqamiz.
Faylga yozish ushbu formatda amalga oshirilishi kerak:
159
/* data type byte max value
bool = 1 255.00
char = 1 255.00
short int = 2 32767.00
unsigned short int = 2 65535.00
int = 4 2147483647.00
unsigned int = 4 4294967295.00
long int = 4 2147483647.00
unsigned long int = 4 4294967295.00
float = 4 2147483647.00
long float = 8 9223372036854775800.00
double = 8 9223372036854775800.00 */
Listing 13.5.
#include <iostream>
#include <fstream> // fayllar bilan ishlash
#include <iomanip> // kiritish/chiqarish manipulyatori
#include <math.h>
using namespace std;
int main(int argc, char* argv[])
{
ofstream fout("data_types.txt", ios_base::out |
ios_base::trunc);
160
/*unsigned short int*/ << (pow(2,sizeof(unsigned
short int) * 8.0) - 1) << endl
<< "int = " << sizeof(int)
<< " " << fixed << setprecision(2)
/*int*/ << (pow(2,sizeof(int) * 8.0
- 1) - 1) << endl
<< "unsigned int = " << sizeof(unsigned
int) << " " << fixed << setprecision(2)
/*int*/ << (pow(2,sizeof(unsigned int) *
8.0) - 1) << endl
<< "long int = " << sizeof(long int)
<< " " << fixed << setprecision(2)
/*long int*/ << (pow(2,sizeof(long int)
* 8.0 - 1) - 1) << endl
<< "unsigned long int = " << sizeof(unsigned
long int) << " " << fixed << setprecision(2)
/*long int*/ << (pow(2,sizeof(unsigned long int)
* 8.0) - 1) << endl
<< "float = " << sizeof(float)
<< " " << fixed << setprecision(2)
/*float*/ << (pow(2,sizeof(float) *
8.0 - 1) - 1) << endl
<< "long float = " << sizeof(long)
<< " " << fixed << setprecision(2)
/*float*/ << (pow(2,sizeof(long) * 8.0 -
1) - 1) << endl
<< "double = " << sizeof(double)
<< " " << fixed << setprecision(2)
/*double*/ << (pow(2,sizeof(double) *
8.0 - 1) - 1) << endl;
fout.close(); // faylni yopish
cout << "Berilganlar data_types.txt ga muvaffaqiyatli
joylashtirildi\n";
return 0;
}
162
bo'ladi. Xato xabarni quyidagi dastur kodini kompilyatsiya qilish va
ulashga urinayotganda bog'lovchidan kelib chiqadi:
Listing 14.1
// birinchi fayl.cpp
int integerValue = 0 ;
int main( ) {
int integerValue = 0
//….
return 0 ;}
// ikkinchi fayl.cpp
int integerValue = 0 ;
// ikkinchi oxiri.cpp
Kompilyatordan bunday eslatma ham bo‘lishi mumkin: identifier
hiding (ID yashiringan). Uning mohiyati birinchi faylda.cpp
integerValue o'zgaruvchisini main () funksiyasida e'lon qilish xuddi shu
nomdagi global o'zgaruvchini yashiradi.
Main () funksiyasida main () dan tashqarida e'lon qilingan
integervaalue global o'zgaruvchisidan foydalanish uchun ko'rish
operatori (::) yordamida ushbu o'zgaruvchining globalligini aniq
ko'rsatish kerak. Shunday qilib, quyidagi misolda 10 qiymati
main()ichida e'lon qilingan bir xil nomdagi o'zgaruvchiga emas, balki
integervalue global o'zgaruvchisiga beriladi:
Listing 14.2
// birinchi fayl.cpp
int integerValue = 0 ;
int main( ){
int integerValue = 0 ;
:: integerValue=10; // global o'zgaruvchisini o‘zlashtirish
return 0 ;}
// ikkinchi fayl.cpp
int integerValue = 0 ;
// ikkinchi oxiri.cpp
O'zgaruvchi, sinf yoki funksiya bo‘lishi mumkin bo'lgan
obyektning ko'rinishi ostida ushbu obyekt ishlatilishi mumkin bo'lgan
dasturning qismi tushuniladi. Masalan, har qanday funksiyadan
tashqarida e'lon qilingan va aniqlangan o'zgaruvchi fayl yoki global
miqyosga ega. Uning ko'rinishi e`lon nuqtasidan faylning oxirigacha
tarqaladi. Modulli yoki lokal ko'lamga ega bo'lgan o'zgaruvchi dasturiy
modul ichida e'lon qilinadi. Ko'pincha lokal o'zgaruvchilar funksiya
tanasida e'lon qilinadi. Quyida turli xil ko'rish sohalariga ega bo'lgan
obyektlarning namunalari keltirilgan:
163
Listing 14.3
int globalScopeInt = 5 ;
void f( )
{ int localScopeInt = 10 ; }
int main( )
{ int localScopeInt = 15 ;
{ int anotherLocal = 20 ;
int localScopeInt = 30 ;}
return 0 ;}
164
// fayl: ikkinchi.cpp
extern int externalInt ;
int anExternalInt = 10 ;
const int j = 10 ;
Birinchi .cpp faylda e'lon qilingan externalInt o'zgaruvchisi tashqi
aloqaga ega. Birinchi faylda e'lon qilinganiga qaramay .cpp ushbu
o'zgaruvchiga i.cpp kkinchi fayldan kirish mumkin. Ikkala faylda ham
sukut bo'yicha ichki aloqalarga ega bo'lgan j konstantalari mavjud.
Standart konstantalarning ichki aloqasini o'zgartirish uchun siz
quyidagi misolda bo'lgani kabi ularning globalligini aniq ko'rsatishingiz
kerak:
Listing 14.5
// fayl: birinchi.cpp
extern const int j = 10 ;
// fayl: ikkinchi.cpp
extern const int j ;
#include <iostream>
int main(){
std::cout << "j = " << j << std::endl ;
return 0;}
Coutdan oldin std nom maydoni belgisidan foydalanishga e'tibor
bering, bu sizga standart ANSI kutubxonasining barcha obyektlariga
murojaat qilish imkonini beradi. Ushbu kod bajarilgandan so'ng
ekranda qator paydo bo'ladi:
j = 10;
Standartlashtirish qo'mitasi quyidagi misolda bo'lgani kabi tashqi
o'zgaruvchining ko'lamini cheklash uchun statikdan foydalanishni
tavsiya etmaydi:
static int staticInt = 10 ;
int main()
{ //…
}
Agar hozirda statikdan bunday foydalanish shunchaki tavsiya
etilmasa, kelajakda bunday ifodani umuman noto'g'ri deb hisoblash
mumkin. Shuning uchun, endi statik o'rniga nomlar maydonidan
foydalanish yaxshiroqdir.
Tavsiya etiladi!
Nomlar maydonidan foydalaning.
165
NOMLAR MAYDONINI YARATISH
Ism maydonini e'lon qilish sintaksisi tuzilmalar va sinflarni e'lon
qilish sintaksisiga o'xshaydi. Kalit so'zdan keyin pamesras mavjud
bo'lmasligi mumkin bo'lgan nom maydonining nomi, so'ngra
ochiladigan figurali qavs. Ism maydoni ifoda oxirida nuqta-vergulsiz
yopiladigan figurali qavs bilan yakunlanadi. Masalan,:
namespace Window
{
void move( int x, int y) ;}
Window nomi nomlar maydonini aniqlaydi. Bitta fayl ichida yoki
turli xil tarjima birliklarida joylashgan nomlangan nom maydonlarining
ko'plab nusxalarini yaratish mumkin. Bunga C++standart
kutubxonasining std nom maydoni misol bo'la oladi. Uning ishlatilishi
bu holatda standart kutubxona mantiqiy jihatdan yagona funksiyalar
guruhi ekanligi bilan asoslanadi.
Ism maydonlarining asosiy maqsadi dasturning nomlangan
hududida bog'langan elementlarni guruhlashdir. Quyida bir nechta
sarlavha fayllarini birlashtirgan nom maydonining misoli keltirilgan:
Listing 14.6
// header1. h
namespace Window
void move( int x, int y) ;
// header2. h
namespace Window
void resize( int x, int y ) ;
Nomlar maydoni ichida turlari va funksiyalarini e'lon qilish va
aniqlash mumkin. C++da dasturlashning strategik yondashuvlarini
muhokama qilmasdan qilolmaysiz. Dastur tuzilishining to'g'riligi dastur
interfeysi uning protsessual qismidan qanchalik aniq ajratilganligi bilan
belgilanadi. Ushbu prinsipga nafaqat sinflar bilan ishlashda, balki nom
maydonlarini yaratishda ham amal qilish kerak. Quyida yana bir misol
keltirilgan:
Listing 14.7
namespace Window {
// .boshqa prototiplar va o'zgaruvchan ta'riflar.
void move (int x, int y); / / e'lonlar
void resize( int x, int y ) ;
// . . . boshqa prototiplar va o'zgaruvchan ta'riflar.
void move( int x, int y )
if( x < MAX_SCREEN_X && x > 0 )
if( y < MAX_SCREEN_Y && y > 0 )
166
platform.move (x. ) // maxsus dastur
void resize( int x, int y )
if( x < MAX_SIZE_X && x > 0 )
if( y < MAX_SIZE_Y && y > 0 )
platform.resize (x, y ) ; // maxsus dastur
Ismlar maydoni qanchalik tez tartibli va tartibsiz bo‘lishini aniq
ko'rish mumkin! Bundan tashqari, ushbu misolda nomlar maydonini
e'lon qilish atigi 20 satrni tashkil etadi.
Nom maydonining funksiyalari nomlar maydoni tanasidan
tashqarida e'lon qilinishi kerak.
Bu sizga funksiyalar prototipini ularning bajarilishini aniqlashdan
nomlar maydonining tanasini buzmasdan aniq ajratish imkonini beradi.
Bundan tashqari, funksiya prototipini ayirish nom maydonini va uning
joriy qilingan e'lonlarini sarlavha fayliga joylashtirishga imkon beradi
va bajarilish ta'riflarini dasturning bajariladigan fayliga joylashtiradi.
Masalan:
Listing 14.8
// header fayli.h
namespace Window {
void move( int x, int y) ;
// boshqa e'lonlar
// file impl.cpp
void Window::move( int x, int y )
// Oynani ko'chirish kodi
}
YANGI A'ZOLARNI QO'SHISH
Ismlar maydoniga yangi a'zolarni qo'shish faqat nomlar maydoni
tanasida amalga oshiriladi. Kompilyator bunga xato xabari bilan javob
beradi. Bunday xatoning misoli quyida keltirilgan.
Listing 14.9
namespace Window {
// bir qator e'lonlar
// dastur kodi
int Window:: newIntegerInNamespace; / / xato
Oxirgi satr noto'g'ri va kompilyator bu haqida xabar beradi. Xatoni
tuzatish uchun newintegerinnamespace a'zo o'zgaruvchisi prototipini
nomlar maydoni tanasiga o'tkazing.
namespace Window {
private:
void move( int x, int y ) ;
}
167
Bir nom maydoni boshqa nom maydoniga joylashtirilishi mumkin.
Bunday investitsiya bitta nom maydonining bajarilishini aniqlashda
yangi makon prototipi bo‘lishi kerak bo'lgan hollarda qo'llaniladi.
Ichki nomlar maydonining a'zosiga murojaat qilish uchun ikkala
bo‘sh joyning nomlarini aniq ko'rsatish kerak. Shunday qilib, quyidagi
misolda bitta nomlangan bo‘sh joy boshqa nomlangan bo‘sh joy ichida
e'lon qilinadi:
namespace Window{
namespace Pane
void size( int x, int y ) ;
Windows nom maydonidan tashqarida size() funksiyasiga kirish
uchun siz chaqirilgan funksiya nomini u e'lon qilingan nom maydonlari
nomlari bilan to‘ldirishingiz kerak, masalan:
int main( )
Window::Pane::size( 10, 20 ) ;
return 0 ;
NOMLAR MAYDONIDAN FOYDALANISH
Endi nomlar maydoni va tegishli ko'rish operatoridan foydalanish
misolini ko'rib chiqing. Birinchidan, barcha turdagi va funksiyalar
Windows nom maydonida e'lon qilinadi, shundan so'ng a'zo
funksiyalarning ta'riflari undan keyin keladi. Ism maydonida e'lon
qilingan funksiyani aniqlash uchun, Listing 14.10 da bo'lgani kabi,
funksiya nomidan oldin nom maydoni nomi va ko'rish operatorini
o'rnatishingiz kerak.
Listing 14.10. Ism maydonidan foydalanish
1 #include <iostream>
2 using namespace std;
3 namespace Window
4{
5 const int MAX_X = 30 ;
6 const int MAX_Y = 40 ;
7 class Pane
8{
9 public:
10 Pane() ;
11 ~Pane();
12 void size( int x, int y ) ;
13 void move( int x, int y ) ;
14 void show( ) ;
15 private:
16 static int cnt ;
17 int x ;
18 int y ;
19 };
168
20 }
21 int Window::Pane::cnt = 0 ;
22 Window::Pane::Pane() : x(0), y(0) {}
23 Window::Pane::~Pane() {}
24 void Window::Pane::size( int x, int y )
25 {if( x < Window::MAX_X && x > 0 )
26 Pane::x = x;
27 if( y < Window::MAX_Y && y > 0 )
28 Pane::y = y ;}
29 void Window::Pane::move( int x, int y )
30 {if( x < Window::MAX_X && x > 0 )
31 Pane::x = x;
32 if( y < Window::MAX_Y && y > 0 )
33 Pane:: y = y;}
34 void Window:: Pane:: show( )
35 {cout << "x " << Pane::x ;
36 cout << " y " << Pane::y << std::endl ;}
37 int main(){
38 Window::Pane pane ;
39 pane. move( 20, 20 ) ;
40 pane. show( );
41 return 0 ;
42 }
Natija:
x 20 y 20
USING KALIT SO’ZI
Using kalit so'zi nom maydoni a'zolarini e'lon qilishda operator
sifatida ham, sifatida ham ishlatilishi mumkin, ammo
using foydalanish sintaksisi o'zgaradi.
Using kalit so'zi bilan nomlar maydonining barcha a'zolarining
ko'lami kengayadi. Keyinchalik, bu bo‘sh joyning tegishli nomini
ko'rsatmasdan, nomlar maydoni a'zolariga murojaat qilish imkonini
beradi. Foydalanish quyidagi misolda ko'rsatilgan:
Listing 14.11
1 namespace Window {
2 int value1 = 20;
3 int value = 40;
4 Window::value1 = 10 ;
5 using namespace Window ;
6 value2 = 30;}
Windows nom maydonining barcha a'zolari namespace Window-
dan foydalanish satridan boshlab ko'rinadi va tegishli dastur modulining
oxirigacha. E'tibor bering, agar dastur fragmentining yuqori qismidagi
value1 o'zgaruvchisiga kirish uchun nomlar maydoni ko'rsatilishi kerak
169
bo'lsa, value2 o'zgaruvchisiga kirishda bu kerak emas, chunki using
operatori Window nom maydonining barcha a'zolarini ko'rinadigan
qilib qo'ygan.
Using operatori har qanday modulda turli xil doiradagi
dasturlardan foydalanishi mumkin. Dasturning bajarilishi ushbu modul
doirasidan tashqariga chiqqanda, ushbu modulda ochilgan nom
maydonining barcha a'zolari avtomatik ravishda ko'rinmas bo'lib
qoladi. Buni quyidagi misol bilan tahlil qiling:
Listing 14.12
1 namespace Window {
2 int value1 = 20 ;
3 int value2 = 40 ;
4 //.
5 void f()
6 using namespace Window ;
7 value2 = 30 ;
8 value2 = 20; / / xato!
Funksiya kodining oxirgi qatori f () - value2 = 20-kompilyatsiya
vaqtida xatolikka olib keladi, chunki value2 o'zgaruvchisi bu joyda
ko'rinmaydi. Using operatori tomonidan berilgan ushbu
o'zgaruvchining ko'rinishi dasturning oldingi qatoridagi yopilish
qavslari orqasida tugadi.
Lokal o'zgaruvchilar moduli ichida e'lon qilingan taqdirda, ushbu
modulda ochilgan nom maydonining barcha bir xil nomdagi
o'zgaruvchilari yashirin bo'ladi. Bu global o'zgaruvchilarni, agar
ularning ko'lami bir-biriga to'g'ri kelsa, lokal o'zgaruvchilarni
yashirishga o'xshaydi. Nom maydonida e'lon qilingan o'zgaruvchi lokal
o'zgaruvchi e'lon qilinganidan keyin using yordamida ochilgan bo'lsa
ham, ikkinchisi hali ham ustuvor bo'ladi. Bu quyidagi misolda aniq
ko'rsatilgan:
Listing 14.13
namespace Window {
int value1 = 20 ;
int value2 = 40 ;
void f()
int value2 = 10 ;
using namespace Window ;
std::cout << value2 << std::endl;}
170
yashirilganligini tasdiqlovchi 40 emas, balki 10 qiymati ekranda paydo
bo'ladi. Agar siz hali ham nom maydoni o'zgaruvchisidan
foydalanmoqchi bo'lsangiz, bo'sh joy nomini aniq ko'rsating.
Ulardan biri global deb e'lon qilingan, ikkinchisi esa nomlar
maydoni ichida bir xil nomdagi identifikatorlardan foydalanganda ham
noaniqlik paydo bo‘lishi mumkin. Bunga yo'l qo'ymaslik uchun,
dasturning keyingi qismida bo'lgani kabi, obyektni chaqirishda har
doim bo'sh joy nomini aniq ko'rsating:
Listing 14.14
namespace Window{
int value1 = 20 ;
using namespace Window ;
int value1 = 10 ;
void f( )
value1 = 10 ;
Ushbu misolda noaniqlik f () funksiyasi ichida paydo bo'ladi. Using
operatori Window::value1 o'zgaruvchisiga global ko'lamni bildiradi.
Biroq, dastur xuddi shu nomdagi boshqa global o'zgaruvchini e'lon
qiladi. F () funksiyasida qaysi biri ishlatiladi? E'tibor bering, xato xuddi
shu nomdagi global o'zgaruvchini e'lon qilish paytida emas, balki f ()
funksiyasining tanasida unga murojaat qilganda ko'rsatiladi.
Ushbu usul quyidagi misolda ko'rsatilganidek, nomlar maydonida
e'lon qilingan faqat bitta identifikator uchun ko'rinishni ochish uchun
ishlatiladi:
Listing 14.15
namespace Window {
int value1 = 20 ;
int value2 = 40
int value3 = 60 ;
Windows:: value2; / / value2ga kirishni ochish
Window:: value1 = 10; / / value1 uchun nom maydoni
value2 = 30 ;
Window:: value3 = 10: / / value3 uchun nom maydoni
Shunday qilib, using yordamida siz ushbu maydonda berilgan
boshqa identifikatorlarga ta'sir qilmasdan, alohida nom maydoni
identifikatoriga joriy doiraga kirishni ochishingiz mumkin. Oldingi
misolda value2 o'zgaruvchisi nom maydonini aniq ko'rsatmasdan
chaqiriladi, bu value1 va value3 ga kirishda mumkin emas. E'londa
usingdan foydalanish har bir nom maydoni identifikatorining
ko'rinishini qo'shimcha nazorat qilishni ta'minlaydi. Bu bir vaqtning
171
o'zida nom maydonining barcha identifikatorlariga kirishni ochadigan
operator sifatida foydalanishdan farq qiladi.
Agar nomlar maydonidan identifikator allaqachon e'lon qilingan
lokal maydonga bir xil nomdagi boshqa identifikator qo'shilsa, bu
kompilyatsiya xatosiga olib keladi. Shuningdek, xuddi shu nomdagi
boshqa identifikator mavjud bo'lgan hududdagi nomlar maydonidan
identifikatorni e'lon qilish bo'ladi. Bu quyidagi misolda ko'rsatilgan:
Listing 14.16
namespace Window{
int value1 = 20 ;
int value2 = 40 ;
void f()
int value2 = 10 ;
Windows:: value2; / / bir qator e'lonlar
std::cout << value2 << std::endl ;}
F () funksiyasining ikkinchi qatorini kompilyatsiya qilish xatoga
olib keladi, chunki ushbu blokda value2 deb nomlangan o'zgaruvchi
allaqachon e'lon qilingan. Agar lokal value2 o'zgaruvchisini e'lon
qilishdan oldin using bilan e'lon joylashtirilsa, xuddi shu natija olinadi.
Using yordamida lokalhududga kiritilgan nom maydoni
identifikatori ushbu hududdan tashqarida e'lon qilingan shunga
o'xshash identifikatorni yashiradi. Quyidagi misolni tahlil qiling:
Listing 14.17
namespace Window {
int value1 = 20;
int value2 = 40 :
int value2 = 10 ;
void f()
using Window:: value2 ;
std::cout << value2 << std::endl;}
Yuqorida ta'kidlab o'tilganidek, usingdan foydalanishning ushbu
usuli sizga alohida nomlar maydoni identifikatorlarining ko'lamini
qo'shimcha ravishda boshqarish imkonini beradi. Using operatori
nomlar maydonida e'lon qilingan barcha identifikatorlarga lokal
hududda kirish huquqini ochadi. Using operatoridan foydalanish faqat
nomlar maydonining barcha identifikatorlariga bir vaqtning o'zida
kirish huquqini ochish zarur bo'lganda oqlanadi.
ISMLAR MAYDONI
Ismlar maydoni nomlangan maydonning qo'shimcha nomini
yaratish uchun ishlatiladi. Quyidagi misolni ko'rib chiqing:
172
Listing 14.18
namespace the_software_company {
int value ;
the_software_company::value = 10 ;
namespace TSC = the_software_company ;
TSC::value = 20 ;
Ushbu usulning salbiy tomoni shundaki, bunday nom ko'rsatilgan
ko‘lamda mavjud bo‘lishi mumkin. Bunday holda, kompilyator xato
haqida xabar beradi va siz shunchaki nomlar maydonini
o'zgartirishingiz mumkin.
Bunday ismlar nomlari nomlanganlardan farq qiladi, chunki ular
nomga ega emaslar. Ular ko'pincha global ma'lumotlarni potensial nom
to'qnashuvlaridan himoya qilish uchun ishlatiladi. Bunday nom
maydonida e'lon qilingan barcha identifikatorlar hech qanday prefikssiz
oddiygina nom bilan chaqiriladi. Quyidagi kod ikki xil faylda
joylashgan ikkita nomlanmagan nomlar maydonining namunalarini
taqdim etadi.
Listing 14.19
// fayl: one. cpp
namespace
int value ;
char p( char ×p ) ;
//.
// fayl: ikki.cpp
namespace
int value :
char p( char •p ) ;
//.
int main( )
char c = p( ptr ) ;
Har bir faylda qiymat o'zgaruvchisi va p () funksiyasi e'lon qilinadi.
Har bir fayl uchun o'ziga xos nomlanmagan maydon berilganligi
sababli, bitta dastur fayllari ichidagi bir xil nomdagi identifikatorlarga
murojaat qilish nomlarning to'qnashuviga olib kelmaydi. Bu p()
funksiyasini chaqirganda aniq ko'rinadi. Nomlanmagan nomlar
maydonining ishlashi tashqi bog'langan statik obyektning ishiga
o'xshaydi, masalan
static int value = 10 ;
Shuni unutmangki, statik kalit so'zidan bunday foydalanish
standartlashtirish qo'mitasi tomonidan tavsiya etilmaydi. Bunday
muammolarni hal qilish uchun endi standart nomlar maydonlari
qo'llaniladi.
173
STD STANDART NOM MAYDONI
Standart nomlar maydonlari eng yaxshi namunasini C++ standart
kutubxonasida topish mumkin. Standart kutubxonaning barcha
funksiyalari, sinflari, obyektlari va shablonlari std nom maydonida e'lon
qilinadi.
Ehtimol, siz bunday ifodalarni ko'rishingiz kerak edi:
#include <iostream>
using namespace std;
Shuni unutmangki, using e’lonidan foydalanish nomlangan nom
maydonining barcha identifikatorlariga kirish imkonini beradi. Shuning
uchun standart kutubxonalar bilan ishlashda ushbu operatorning
yordamiga murojaat qilmaslik yaxshiroqdir.
Global maydon tom ma'noda standart kutubxonaning sarlavha
fayllaridan turli xil identifikatorlarning nomlari bilan to‘ldiriladi,
ularning aksariyati ushbu dasturda ishlatilmaydi. Esda tutingki, barcha
sarlavha fayllari nom maydoni vositasidan foydalanadi, shuning uchun
agar siz dasturga bir nechta sarlavha fayllarini qo'shsangiz va using
operatoridan foydalansangiz, ushbu sarlavha fayllarida e'lon qilingan
barcha identifikatorlar global ko'rinishga ega bo'ladi. Siz ushbu
kitobning aksariyat misollarida ushbu qoida buzilganligini payqagan
bo‘lishingiz mumkin. Bu faqat misollarning qisqacha mazmuni uchun
qilingan. Siz o'zingizning dasturlaringizda quyidagi misolda bo'lgani
kabi foydalanish kalit so'zi bilan e`lonlardan foydalanishingiz kerak:
Listing 14.20
#include <iostream>
using std::cin ;
using std::cout ;
using std::endl ;
int main( ){
int value = 0 ;
cout << "So, how many eggs did you say you wanted?" << endl ;
cin >> value ;
cout << value << " eggs, sunny-side up!" << endl ;
return( 0 ) ;}
Ushbu dasturni bajarish quyidagi xulosaga olib keladi:
So, how many eggs did you say you wanted?
4
4 eggs, sunny-side up!
Shu bilan bir qatorda, nomlar maydonida e'lon qilingan
identifikatorlarga aniq murojaat qilish mumkin:
174
Listing 14.21
#include <iostream>
int main( ){
int value = 0 ;
std::cout << "How many eggs did you want?" << std::endl ;
std::cin >> value ;
std::cout << value << " eggs, sunny-side up!" << std::endl ;
return( 0 );}
Dastur quyidagi ma'lumotlarni chiqaradi:
How many eggs did you want?
4
4 eggs, sunny-side up!
Ushbu yondashuv kichik dastur uchun juda mos keladi, ammo katta
dasturlarda nom maydoni identifikatorlariga barcha aniq murojaatlarni
kuzatish juda qiyin bo'ladi. Tasavvur qiling: standart kutubxonadan har
bir nom uchun std:: qo'shishingiz kerak bo'ladi!
Nazorat savollari va topshiriqlar:
1. Ism maydonida e'lon qilingan identifikatorlardan foydalanish kalit
so'zini ishlatmasdan foydalanish mumkinmi?
2. Nomlangan va nomlanmagan nomlar maydoni orasidagi asosiy
farqlarni ayting.
3. Standart std nom maydoni nima?
4. Xatolar: quyidagi kodda xato toping:
#include <iostream>
int main()
{
cout << "Hello world!" << end;
return 0;}
5. 4-mashq kodida topilgan xatoni tuzatishning uchta usulini sanab
o'ting.
175
15-MAVZU. OOP (OBYEKTGA YO ’NALTIRILGAN
DASTURLASH ) HAQIDA TUSHUNCHA. C++ DA STRUKTURALAR .
Obyektga yo'naltirilgan dasturlash yondashuvlari asosida
muammolarni tahlil qilish va yechimlarni topish
Vazifalarning maqbul yechimlarini topish uchun samarali
obyektga yo'naltirilgan dasturlarni qanday loyihalash kerak?
Tahlil va loyihalashni hujjatlashtirish uchun yagona
modellashtirish tilidan (UML) qanday foydalanish kerak?
177
15.1-rasm. Sinf merosining sxematik tasviri
Rasmda Geranium gulning o'ziga xos turi ekanligi ko'rsatilgan va
bu haqiqiylikka to'liq mos keladi. Vaqt o'tishi bilan biz ko'plab
murakkab munosabatlarni modellashtirishni xohlaymiz va dastur
obyektlarining o'zaro bog'liqligini aks ettiruvchi diagrammalar yaratish
bo'yicha Konvensiya va qoidalar to'plamini ishlab chiqamiz.
Bunday holda, hamma uchun tushunarli bo'lgan yagona
modellashtirish tilining mavjudligi foydali bo'ladi. Shunga qaramay,
bunday til yaratildi va uning nomi UML (Unified Modeling Language-
yagona modellashtirish tili). Uning vazifasi diagrammalardagi
obyektlar o'rtasidagi munosabatlarni xaritalashda bir xillikka
erishishdir. UML tili konvensiyalariga muvofiq, bizning sxemamiz
15.1-rasm boshqacha tasvirlangan bo‘lishi kerak (15.2-rasm).
178
DASTURLARNI LOYIHALASH JARAYONI
Obyektga yo'naltirilgan dasturni tahlil qilish va loyihalashni to'g'ri
bajarish modellashtirish tili konvensiyalariga rioya qilishdan ko'ra
muhimroqdir.
Ko'pgina nashrlar va konferensiyalar ushbu mavzuga
bag'ishlangan. Va agar modellashtirish tili haqida umumiy
kelishuvlarga erishish va UML ishlab chiqarish mumkin bo'lsa, unda
dasturlarni tahlil qilish va loyihalashning asosiy sabablari bo'yicha
tortishuvlar bugungi kungacha davom etmoqda.
Hatto yangi kasb paydo bo'ldi, bular dasturlash
usullarini o'rganadigan va ishlab chiqadigan dasturchilar. Ko'pincha
adabiyotda siz yangi dasturlash usulini tavsiflashga bag'ishlangan
maqolalarni topishingiz mumkin. - bu modellashtirish tili
tahlili va loyihalash yondashuvlarining kombinatsiyasi. Dunyodagi eng
mashhur uchta metodolog - Buch metodini yaratgan Grady Booch,
obyektga yo'naltirilgan dasturlash yondashuvlarini ishlab chiqqan Iver
Jakobson va obyektni modellashtirish texnologiyasini yaratgan Jeyms
Rambaugh.
Ushbu darsda keltirilgan material taxminan objectory metodlariga
amal qiladi.
Dasturlarni loyihalash jarayoni iterativdir. Bu shuni anglatadiki,
dasturni ishlab chiqarishda biz vaqti-vaqti bilan butun jarayonni
takrorlaymiz, chunki talablarni tushunish kuchayadi.
Iterativ rivojlanishni kaskadli rivojlanishdan ajratish kerak, bunda
bir bosqichdan chiqarish keyingi bosqichga kirish bo'ladi va orqaga yo'l
yo'q (15.3-rasm).
Loyiha ustida ishlash loyiha talablarini rasmlantirishdan
boshlanadi, ular rivojlanish jarayonida o'zgarishi mumkin, bu esa
allaqachon yaratilgan dasturiy ta'minot bloklariga o'zgartirishlar
kiritishni talab qiladi. Katta loyiha alohida bloklarga bo'linadi, ular
uchun avval prototip lar, so'ngra ularni bajarish tartiblari yaratiladi.
Alohida modullarning bajarilishini sinab ko'rish ularning prototiplariga
o'zgartirishlar kiritish zarurligiga olib kelishi mumkin va alohida
bloklardagi o'zgarishlar ularni vaqti-vaqti bilan butun loyihada o'zaro
ta'sir qilish tamoyillarini qayta ko'rib chiqarishga majbur qiladi.
179
15.3-rasm. Loyihalash jarayoni
Ishlar ketma-ketligini yana bir bor takrorlaymiz:
1. Kontsepsiyani ishlab chiqarish.
2. Tahlil qilish.
3. Loyihalash.
4. Amalga oshirish.
5. Sinov.
6. Qaytish.
- afsuski, haqiqiy hayotdan uzoq bo'lgan
sof g'oyani ko'tarishdir;
-bu loyiha talablarini anglash jarayoni;
-bu kod yaratiladigan sinf modelini rasmlantirish jarayoni;
-kod yozish (masalan, C++ da);
- hamma narsa yaxshi yoki yo'qligini tekshirish;
-bu sizning mahsulotingizni mijozga berilishi mumkin bo'lgan
holatga keltirishdir.
Bularning barchasini amalda qo'llash qoladi.
DOMEN MODELINI YARATISH
- bu domen (dasturiy mahsulotdan foydalanish
sohasi) haqida ma'lum bo'lgan hamma narsani yozib oladigan hujjat.
Domen modeli domen obyektlaridan iborat bo'lib, ularning har biri
tizimdan foydalanish holatlarini tavsiflashda aytib o'tilgan ma'lum bir
elementga mos keladi.
Biz dasturiy obyektlar bilan emas, balki loyihani ishlab chiqarishda
hisobga olinishi kerak bo'lgan haqiqiy ishtirokchilar bilan
shug'ullanayotganimizni tushunish muhimdir. Hech kim bizni har bir
domen obyekti uchun dasturda obyektlar yaratishga majburlamaydi.
UML konvensiyalaridan foydalanib, diagramma yaratish
mumkin, unda domen obyektlari o'rtasidagi munosabatlar xuddi
180
dasturdagi sinflar o'rtasidagi munosabatlar tasvirlanganidek aks
ettiriladi. Bu UMLning kuchli tomonlaridan biri: loyihalashning barcha
bosqichlarida bir xil vositalardan foydalanish mumkin.
Masalan, hisob-kitob va depozit hisobvaraqlari bank
hisobvarag'ining umumiy tushunchasiga aniqlik kiritilganligini qayd
etish mumkin. UMLda olingan sinflarning umumlashtirilishi asosiy
o'qlar yordamida ko'rsatiladi (15.4-rasm)
Ushbu rasmda ko'rsatilgan diagrammada to'rtburchaklar turli xil
domen obyektlarini, yuqoriga yo'naltirilgan o'qlar esa xususiy
obyektlarni umumlashtirishni anglatadi. Shunday qilib, C++ tili nuqtai
nazaridan aytish mumkinki, domen obyektlari joriy hisob va depozit
hisobvarag'i obyektdan olingan bank hisobvarag'i.
181
UMUMLASHTIRISH
ko'pincha merosning sinonimi sifatida qaraladi,
ammo ular o'rtasida sezilarli farq bor. Umumlashtirish munosabatlar
turini tavsiflaydi, meros esa dasturlash orqali umumlashtirishni amalga
oshirishdir.
Umumlashtirish shuni anglatadiki, olingan obyekt bazaning pastki
turi hisoblanadi.
Shunday qilib, joriy hisob-bu bank hisobining bir turi. O'z
navbatida, bank hisobvarag'i hisob-kitob va depozit hisobvaraqlarining
atributlari va xususiyatlarini umumlashtiradi.
Ko'pincha bitta obyekt ko'plab kichik obyektlardan iborat.
Masalan, mashina rul, shinalar, eshiklar, Vites qutisi va boshqalardan
iborat. Joriy hisob qoldiqdan, tranzaktsiyalar yozuvidan, mijoz kodidan
va boshqalardan iborat. UML yordamida o'z-o'zidan joylashtirish yoki
tarkib tashqi obyektdan ichki obyektga yo'naltirilgan uchida olmosli o'q
bilan ko'rsatiladi (15.5-rasm).
184
15.8-rasm. Foydalanish holati diagrammasi
185
prototipini ishlab chiqarish foydali bo‘lishi mumkin. Ko'pincha,
hujjatlarga grafik dastur loyihaga qo'yiladigan talablarni aniqlash
funksiyasi bilan eng yaxshi ishlaydi, chunki bu tizim qanday bo‘lishi
kerakligini va uning yakuniy versiyada qanday ishlashini aniq ko'rish
imkonini beradi.
Tahlil va loyihalashning har bir bosqichi oxiriga kelib,
deb nomlangan bir qator hujjatlar to'planadi. Bunday hujjatlarning
taxminiy to'plami 15.1-jadvalda ko'rsatilgan.
Artefakt Tavsif
Foydalanuvchi interfeysini vizualizatsiya
Foydalanish qilish bilan tizimdan foydalanishning barcha
holatlarining holatlari, senariylar, stereotoqimlar, dastlabki
tavsifi shartlar va bajarilish natijalari to'g'risida
batafsil hujjat
Loyiha ishlab chiqilayotgan domen
Domen modeli obyektlarining munosabatlar diagrammasi
186
LOYIHALASH
Tahlil davomida asosiy e'tibor domenni ko'rib chiqarish va loyiha
vazifalari va talablarini aniqlashga qaratilgan bo'lsa, loyihalash
yechimlarni topishga qaratilgan. - bu dasturlash orqali
bizning ideal modelimizni amaliy amalga oshirishni rejalashtirish.
Ushbu jarayonning natijasi dastur loyihasi hujjatini yaratishdir.
Loyiha hujjati ikki qismdan iborat: sinf loyihasi va dastur
arxitekturasi. Birinchi bo'lim, o'z navbatida, statik (turli sinflarning
tavsifi, ularning tuzilishi va xususiyatlari) va dinamik (sinflarning
o'zaro ta'sirining tavsifi) bo'limlarni o'z ichiga oladi.
Sinflarning dastlabki to'plami yaratilganda, ularning munosabatlari
va o'zaro munosabatlarini modellashtirishni boshlash vaqti keldi.
Aniqroq bo‘lish uchun avval statik modelni, so'ngra dinamik modelni
tushuntiramiz. Haqiqiy loyihalash jarayonida bir modeldan
ikkinchisiga erkin o'tish mumkin, ikkalasini ham tafsilotlar bilan
to‘ldirish, aslida yangi sinflarni qo'shish va ularni oldinga siljish bilan
tavsiflash mumkin.
Statik model uchta sohaga qaratilgan: javobgarlikni taqsimlash,
atributlar va o'zaro ta'sir. Ulardan eng muhimi sinflar o'rtasida
javobgarlikni taqsimlashdir. Har bir sinf oldida bitta aniq vazifa
qo'yilishi kerak, uning bajarilishi uchun u javobgardir.
Bu har bir sinfda faqat bitta metod mavjud degani emas. Sinf o'nlab
metodlarni o'z ichiga olishi mumkin. Biroq, ularning barchasi izchil va
o'zaro bog'liq bo‘lishi kerak, ya'ni.bitta vazifani bajarilishini ta'minlashi
kerak.
Xulosa qilib aytganda, to'liqroq loyiha modelini yaratish uchun
UMLga o'tish kerak.
Qanday qilib bir xil markadagi turli xil avtomobil modellarini
ishlab chiqarishni loyihalash mumkin? Aytaylik, sizni beshta avtomobil
ishlab chiqaradigan Acme Motors firmasi yollagan: Pluto (xarid qilish
uchun sayohat qilish uchun ixcham kichik avtomobil), Venera (o'rta
quvvatli dvigatelga ega to'rt eshikli "sedan"), Mars (eng kuchli
dvigatelga ega "kupe" tipidagi sport avtomobili, maksimal tezlikka
mo'ljallangan), Yupiter (mini furgon sport kupesi kabi majburiy
dvigatel bilan, ammo u kamroq tezlikda, ammo kuchliroq) va yer (kam
quvvatli, ammo tezkor furgon).
187
Ammo keling, modellar orasidagi farqlarni batafsilroq tahlil
qilaylik. Shubhasiz, ular dvigatel kuchi, tana turlari va ixtisosligi bilan
farq qiladi. Ushbu asosiy xususiyatlarni birlashtirib, biz turli xil
modellarning xususiyatlarini olamiz.
Shunday qilib, bizning misolimizda modellarning nomlariga emas,
balki ularning asosiy xususiyatlariga e'tibor qaratish muhimroqdir.
Bunday belgilar deb ataladi va UMLda maxsus tarzda
ko'rsatiladi.
188
misolimizda Car sinfi (loyiha sinfiga mos keladigan mashina)
PerformanceCharacteristics sinf obyektiga ko'rsatgichni o'z ichiga oladi
(15.11-rasm).
Agar siz mashq qilmoqchi bo'lsangiz, diskriminatorlar uchun
o'zingizning kuch sinflaringizni yarating tana (tana) va dvigatel
(dvigatel).
Class Car : public Vehicle
public:
Car();
-Car();
// boshqa ochiq usullar chiqarib tashlandi
private:
PerformanceCharacteristics*pPerformance;
};
DINAMIK MODEL
Loyiha modelida nafaqat sinflar o'rtasidagi munosabatlarni, balki
ularning o'zaro ta'sir tamoyillarini ham ko'rsatish muhimdir. Masalan,
sinflar joriy hisob, ATM va kvitansiya sinf bilan o'zaro ta'sir qiladi
mijoz vaziyatda hisobdan chiqarish. Tahlil boshida ishlatilgan ketma-
ket diagrammalar turiga qaytish (15.10-rasm), endi 15.20-rasmda
ko'rsatilgandek, ular uchun belgilangan usullar asosida sinflarning
o'zaro ta'sirini ko'rib chiqing.
189
15.12-rasm. Sinf obyekti o'rtasidagi munosabatlar
Ushbu oddiy diagramma dasturdan foydalanishning ma'lum bir
holatida loyihaning bir nechta sinflari o'rtasidagi o'zaro ta'sirni
ko'rsatadi. U erdagi sinf sinfga topshirishi kerak joriy hisob hisobdagi
pul qoldig'ini hisobga olish uchun javobgarlik, joriy hisob esa ATM
sinfiga ushbu ma'lumotni foydalanuvchiga etkazish uchun
javobgarlikni beradi.
C++ obyektga yo'naltirilgan dasturlash tamoyillarini to'liq qo'llab-
quvvatlaydi: inkapsulyatsiya, meros va polimorfizm.
INKAPSULYATSIYA
Muhandis o'z rivojlanishida rezistordan foydalanganda, uni qayta
ixtiro qilmaydi, balki omborga boradi (do'konga, hamkasbiga -
variantlar mumkin) va belgilangan parametrlarga muvofiq o'zi uchun
kerakli qismni tanlaydi. Shu bilan birga, agar u zavod xususiyatlariga
muvofiq ishlasa, bu aniq rezistorning qanday ishlashi haqida unchalik
tashvishlanmaydi.
Aynan tashqi tuzilmalarda ishlatiladigan obyektlarning yashirinligi
yoki avtonomiyasining bu xususiyati inkapsulyatsiya deb ataladi.
Inkapsulyatsiya yordamida ma'lumotlarni yashirishni ta'minlash
mumkin. Bu juda muhim xususiyatdir, buning natijasida foydalanuvchi
ishlatilgan obyektning ichki ishi haqida o'ylamasligi mumkin.
Sovutgichdan foydalanish muzlatgichning ishlash tamoyillari
to'g'risida bilimlarni talab qilmagani kabi, yaxshi ishlab chiqilgan
dasturiy ta'minot obyektidan foydalanish uning ichki a'zo
190
o'zgaruvchilari o'rtasidagi munosabatlar haqida qayg'urmaslikka imkon
beradi.
C++ tilida inkapsulyatsiya xususiyati sinflar deb nomlangan
nostandart (maxsus) ma'lumotlar turlarini yaratish orqali qo'llab-
quvvatlanadi. Sinflar qanday yaratilganligi haqida siz 6-darsda bilib
olasiz. Yaratilgandan so'ng, yaxshi belgilangan sinf to'liq kapsulali
obyekt vazifasini bajaradi, ya'ni u butun dastur moduli sifatida
ishlatilishi mumkin. Sinfning haqiqiy ichki ishi yashirin bo‘lishi kerak.
Yaxshi belgilangan sinf foydalanuvchilari ushbu sinf qanday ishlashini
bilishlari shart emas; ular faqat bitta narsani bilishlari kerak - uni
qanday qilib yopishtirish kerak.
MEROS
C++ tili merosni qo'llab-quvvatlaydi. Bu shuni anglatadiki, mavjud
ma'lumotlarning kengaytmasi bo'lgan yangi ma'lumotlar turini (sinfini)
e'lon qilish mumkin. Ushbu yangi subklassa mavjud sinfdan meros
bo'lib o'tganligi va uning hosilasi deb nomlanganligi aytiladi.
POLIMORFIZM
C++ tili funksiyalar va sinflarning polimorfizmi deb ataladigan
narsa tufayli turli xil obyektlar uchun bir xil nomdagi funksiyalarni
bajarishda o'zgarishlar kiritish qobiliyatini qo'llab-quvvatlaydi. Poli
ko'p, morfe - rasm degan ma'noni anglatadi, shuning uchun
polimorfizm rasmlarning xilma-xilligini anglatadi.
192
16-MAVZU. SINFLAR VA OBYEKTLAR
Sinflar va obyektlar
Yangi sinfni aniqlash va ushbu sinf obyektlarini yaratish
A'zo funksiyalari va a'zo o'zgaruvchilar
Konstruktor va uni ishlatish
193
turlarni yaratish mumkin bo'lsa, yechimlar ancha sodda ko'rinadi. Bu
o'zgaruvchilar rostga qanchalik yaqin bo'lsa, bunday dasturni yozish
osonroq bo'ladi.
SINFLAR VA SINF A'ZOLARI
Sinfni e'lon qilish orqali yangi tur yaratiladi. Sinf shunchaki bog'liq
funksiyalar to'plami bilan birlashtirilgan o'zgaruvchilar to'plamidir (va
ko'pincha har xil tipdagi).
Avtomobilni turli yo'llar bilan tasavvur qilish mumkin, masalan,
g'ildiraklar, eshiklar, o'rindiqlar, derazalar va boshqalardan iborat
to'plam sifatida yoki mashina haqida o'ylab, siz uning harakatlanish,
tezlikni oshirish, tormozlash, to'xtash va hokazolarni tasavvur
qilishingiz mumkin bu obyekt deb ataladi. Avtomobil haqida biz bilgan
hamma narsani bitta sinfga kiritish dasturchi uchun bir qator
afzalliklarga ega. Axir, barcha ma'lumotlar bitta obyektda to'plangan,
unga murojaat qilish, nusxalash va uning ma'lumotlarini boshqarish
oson. Sizning sinfingiz mijozlari, ya'ni dasturning ushbu sinf bilan
ishlaydigan qismlari sizning obyektingizdan unda nima borligi yoki u
qanday ishlashi haqida tashvishlanmasdan foydalanishi mumkin.
Sinf o'zgaruvchan turlarning har qanday kombinatsiyasidan,
shuningdek boshqa sinflarning turlaridan iborat bo‘lishi mumkin.
Sinfdagi o'zgaruvchilar a'zo o'zgaruvchilar yoki berilgan a'zolar deb
ataladi.
A'zo ma'lumotlar sifatida ham tanilgan a'zo o'zgaruvchilar faqat o'z
sinfiga tegishli. A'zo o'zgaruvchilar sinfning g'ildiraklar va dvigatel
bilan bir xil tarkibiy qismlari - avtomobilning tarkibiy qismlari.
Sinfdagi funksiyalar odatda a'zo o'zgaruvchilar bo'yicha
harakatlarni bajaradi. Ular a'zo funksiyalar yoki sinf usullari deb
ataladi. Car sinfining usullari Start() va Break () ni o'z ichiga olishi
mumkin. Cat sinfida hayvonning yoshi va vaznini ifodalovchi bunday
a'zo ma'lumotlar bo‘lishi mumkin va bu sinfning funktsional qismi
Sleep (), Meow() va ChaseMice () usullari bilan ifodalanishi mumkin.
A'zo funksiyalari a'zo o'zgaruvchilar kabi o'z sinfiga tegishli. Ular
a'zo o'zgaruvchilar bilan ishlaydi va sinfning funktsional
imkoniyatlarini aniqlaydi.
SINF PROTOTIPI
Sinfni e'lon qilish uchun class kalit so'zidan foydalaning, so'ngra
ochiladigan figurali qavs va undan keyin sinf a'zolari ma'lumotlari va
usullari Listingi.
194
Prototip yopiq figurali qavs va nuqta-vergul bilan tugaydi. Bu
yerda, masalan, Cat class prototipi qanday ko'rinishga ega:
class Cat
unsigned int itsAge;
unsigned int itsWeight;
void Meow();
Cat sinfini e'lon qilishda xotira saqlanmaydi. Ushbu e'lon
shunchaki kompilyatorga Cat sinfining mavjudligi, unda qanday
ma'lumotlar borligi (itsAge va itsWeight) va nima qila olishi (meow ()
usuli) haqida xabar beradi. Bundan tashqari, ushbu prototip
kompilyatorga Cat sinfining kattaligi haqida xabar beradi, ya'ni.har bir
Cat sinf obyekti uchun kompilyator qancha joy ajratishi kerak. Ushbu
misolda butun qiymat to'rt baytni talab qilganligi sababli, Cat
obyektining hajmi sakkiz baytni tashkil qiladi (itsage o'zgaruvchisi
uchun to'rt bayt va itsweight uchun to'rt bayt). Meow () usuli obyektda
xotira ajratishni talab qilmaydi.
Dasturchiga o'zgaruvchan a'zolar, a'zo funksiyalar va sinflarga
nom berish vazifasi yuklatilgan. Har doim tushunarli va mazmunli
ismlar berilishi kerak. Masalan, mushuk (mushuk), to'rtburchaklar
(to'rtburchak) va xodimlar (xizmatchi) sinflar uchun juda mos nomlar,
A Meow() (meow), ChaseMice() (qo'lga olish) va StopEngine()
(to'xtash motori) usullar uchun ajoyib nomlardir chunki ularning
nomlaridan nima qilishlari aniq. Ko'pgina dasturchilar o'zlarining a'zo
o'zgaruvchilarining nomlarini its prefikslari bilan birga olib boradilar
(masalan, itsAge, itsWeight, itsSpeed). Bu a'zo o'zgaruvchilarni sinf
a'zosi bo'lmagan o'zgaruvchilardan ajratishga yordam beradi.
C++ tilida harflarning katta-kichikligi muhim va barcha sinf
nomlari bitta naqshga amal qilishi kerak. Shunga asoslanib, siz hech
qachon sinfingiz nomi qanday yozilganligini eslashingiz shart emas:
to'rtburchaklar, to'rtburchaklar yoki to'rtburchaklar. Ba'zi dasturchilar
har bir sinf nomiga bitta harfli prefiks qo'shishni yaxshi ko'radilar (sinf
so'zidan) masalan, cCat yoki cPerson, boshqalari esa ism uchun faqat
katta yoki kichik harflardan foydalanadilar. Men sinf nomlarini mushuk
yoki shaxs kabi katta harf bilan boshlashni afzal ko'raman.
Bundan tashqari, ko'plab dasturchilar funksiya nomlarini katta
harflar bilan boshlaydilar va boshqa barcha o'zgaruvchilar nomlari
uchun faqat kichik harflardan foydalanadilar. Ismlarning tarkibiy
qismlari bo'lgan so'zlar odatda pastki chiziq belgilari bilan bo'linadi
195
(masalan, Chase_Mice) yoki har bir so'zni katta harf bilan boshlaydi
(masalan, ChaseMice yoki DrawCircle).
Dastur davomida bitta uslubga rioya qilish muhimdir. Dasturlash
tajribasini orttirganingizda, o'zingizning yozish uslubingiz nafaqat
nomlash, balki to‘ldirish, figurali qavslarni tekislash va izohlarni tuzish
bo'yicha konventsiyalarni ham o'z ichiga oladi.
ESLATMA: Odatda dasturiy mahsulotlarni ishlab chiqaradigan
nufuzli kompaniyalar dasturlarning uslub xususiyatlarini qamrab
oladigan standartlashtirish masalalari bilan shug'ullanadigan maxsus
bo'limlarga ega. Bu barcha ishlab chiquvchilar hamkasblari tomonidan
yaratilgan dasturlarni osongina o'qishlarini ta'minlaydi.
OBYEKTNI ANIQLASH
Yangi turdagi obyekt har qanday butun o'zgaruvchisi bilan bir xil
tarzda aniqlanadi:
unsigned int GrossWeight;
Cat Frisky;
// Cat obyektini aniqlang
Ushbu dasturiy ta'minot satrlarida unsigned int tipiga ega bo'lgan
grossweight nomli o'zgaruvchi aniqlanadi va mushuk sinfining obyekti
(yoki turi) bo'lgan Frisky obyekti ham aniqlanadi.
OBYEKTLAR BILAN TAQQOSLAGANDA SINFLAR
Siz hech qachon mushuk bilan mavhum tushuncha sifatida
o'ynashni xayolingizga ham keltirmaysiz. Muayyan mavhumlik bo'lgan
Cat sinfi va Cat sinfining alohida obyekti o'rtasidagi farq aynan bir xil.
Shuning uchun Frisky - bu Grossweight - ishorasiz int tipidagi
o'zgaruvchi bo'lgan ma'noda mushuk tipidagi obyekt. Shunday qilib,
biz obyekt ma'lum bir sinfning alohida namunasi ekanligiga keldik.
SINF A'ZOLARIGA KIRISH
Frisky kabi Cat sinfining haqiqiy obyektini aniqlagandan so'ng, biz
ushbu obyekt a'zolariga kirish huquqiga ega bo‘lishimiz kerak bo‘lishi
mumkin. Buning uchun to'g'ridan-to'g'ri kirish operatori ishlatiladi (.).
Shuning uchun, Frisky obyektining weight a'zo o'zgaruvchisiga 50
sonini berish uchun siz yozishingiz mumkin
Frisky. Weight = 50;
Xuddi shunday, meow () usulini chaqirish uchun quyidagi
yozuvdan foydalanish kifoya:
Frisky. Meow();
196
Ba'zi bir sinf usulidan foydalanish kerak bo'lganda, ushbu usul
chaqiriladi. Ushbu misolda Frisky obyektining Meow () usuli
chaqiriladi.
QIYMATLAR SINFLARGA EMAS, BALKI
OBYEKTLARGA BERILADI
C++ tilida ma'lumotlar turlariga qiymatlarni o‘zlashtirish mumkin
emas, ular faqat o'zgaruvchilarga beriladi. Masalan, bunday yozuv
noto'g'ri:
int = 5; // noto'g'ri
Kompilyator buni xato deb hisoblaydi, chunki siz int tipiga son
berolmaysiz. Buning o'rniga siz butun sonli o'zgaruvchini aniqlab,
ushbu o'zgaruvchiga 5 sonini o‘zlashtirishingiz kerak. Masalan:
int x; // x ni int tipidagi o'zgaruvchi sifatida aniqlang
x = 5; //x o'zgaruvchiga 5 qiymatini berish
Shunday qilib, 5 soni int tipiga ega bo'lgan x o'zgaruvchiga
beriladi. Xuddi shu sabablarga ko'ra quyidagi yozuv qabul qilinishi
mumkin emas:
Cat.itsAge=5; / / noto'g'ri
Agar Cat obyekt emas, balki sinf bo'lsa, kompilyator bu ifodani
noto'g'ri deb belgilaydi, chunki Cat sinfining (ya'ni turi) itsage
o'zgaruvchisiga 5 sonini o‘zlashtirish mumkin emas. Buning o'rniga,
Cat sinfining obyektini aniqlash va ushbu obyektning tegishli a'zo
o'zgaruvchisiga 5 sonini berish kerak. Masalan:
Cat Frisky; // ushbu ta'rif int x ga o'xshaydi;
Frisky.itsAge = 5; / / ushbu topshiriq = 5 ga o'xshash;
Tasavvur qiling-a, siz uch yoshli bolangiz bilan yurib, unga
mushukni ko'rsatasiz va "bu Frisky, ajoyib mushuk, Frisky, hura"deb
aytasiz. Hatto kichkina bola ham kulib: "yo'q, Mushuklar hurishni
bilmaydi", deb aytadi.
Agar yozsangiz:
Cat Frisky;// Frisky ismli mushukni (obyektni) yarating
Frisky. Bark();// Friskiga baqirishni ayting.
Keyin kompilyator sizga hatto virtual Mushuklar ham
hurishni bilmasligini aytadi, chunki ular uchun bunday usul e'lon
qilinmagan.
Cat sinfida meow() (miyovlash) usuli mavjud. Agar siz mushuk
sinfida Meow () usulini aniqlamasangiz, unda kompilyator sizning
mushukingizni hatto miyovlashiga yo'l qo'ymaydi.
197
Tavsiya etiladi!
Sinfni e'lon qilish uchun class kalit so'zidan foydalaning.
To'g'ridan-to'g'ri kirish operatoridan foydalaning (.) a'zo
o'zgaruvchilar va sinf usullariga kirish uchun.
Tavsiya etilmaydi!
Prototipni ta'rif bilan aralashtirmang.
Prototip sinf mavjudligini e'lon qiladi va ta'rif obyekt uchun
xotirani saqlaydi.
Sinfni obyekt bilan aralashtirmang.
Sinfga qiymatlarni tayinlamang. Obyektning a'zo
o'zgaruvchilariga qiymatlarni belgilang.
SINF A'ZOLARIGA KIRISHNI CHEKLASH
Sinf prototipida boshqa kalit so'zlar ham qo'llaniladi. Ulardan eng
muhimi, sinf a'zolariga kirishni belgilaydigan public (ochiq) va private
(yopiq).
Sinfning barcha a'zolari-ma'lumotlar va usullar sukut bo'yicha
yopiq.Yopiq a'zolarga faqat sinfning o'zi funksiyalari orqali kirish
mumkin.
Ochiq a'zolar dasturning boshqa barcha funksiyalari uchun mavjud.
Sinf a'zolariga kirishni aniqlash juda muhimdir va aynan shu
muammoni hal qilishda boshlang'ich dasturchilar ko'pincha
qiyinchiliklarga duch kelishadi. Vaziyatni aniqlashtirish uchun ushbu
bobda quyida keltirilgan misolni ko'rib chiqing:
class Cat
{
unsigned int itsAge;
unsigned int itsWeight;
void Meow();
};
Ushbu e'londa itsAge va itsWeight o'zgaruvchilari, shuningdek
Meow() funksiyasi yopiq, chunki sinfning barcha a'zolari sukut
bo'yicha private. Agar sinf a'zolariga kirishni o'zgartirish zarur bo'lsa,
unda bu aniq bajarilishi kerak.
Agar dastur yuqorida ko'rsatilgandek Cat sinfini tavsiflasa, u holda
main () funksiyasidan itsage a'zo o'zgaruvchisiga murojaat qilish
kompilyatsiya xatosiga olib keladi:
Cat Boots;
Boots.itsAge = 5; / / xato!
198
Shuningdek, ishning o'zida, birinchi navbatda, kompilyator itsage,
itsweight va Meow () atamalarini faqat Cat sinfida ishlatish
mumkinligini ko'rsatadi, keyin tashqi funksiyada Cat sinfining Boots
obyektiga tegishli bo'lgan itsage a'zosi o'zgaruvchisidan foydalanishga
harakat qilinadi. Boots obyekti dasturda rostan ham mavjud bo‘lsada,
bu qiziquvchan ko'z uchun yopiq bo'lgan ushbu obyekt a'zolariga kirish
mumkin degani emas.
Gap shundaki, Cat sinfining e'lonida sizning ushbu sinf a'zolariga
murojaat qilish huquqlaringiz haqida hech narsa aytilmagan, ya'ni sizda
bunday huquqlar yo'q. Faqat Boots obyektining o'ziga xos funksiyalari
har doim public va private bo'lgan barcha sinf ma'lumotlariga kirish
huquqiga ega. Siz o'zingiz Cat sinfini yaratgan bo'lsangiz ham, bu sizga
dasturda yopiq bo'lgan ma'lumotlarni qaytarish yoki o'zgartirish
huquqini bermaydi.
Biroq, har qanday pozitsiyadan chiqarish yo'li mavjud. Cat
sinfidagi o'zgaruvchilarga kirish uchun ularni quyidagi tarzda oching:
class Cat
public:
unsigned int itsAge;
unsigned int itsWeight;
void Meow();
Endi Public kalit so'zi tufayli sinfning barcha a'zolari (itsAge,
itsWeight va Meow()) ochiq. 16.1 Listingida ochiq o'zgaruvchan a'zolar
bilan Cat sinfining prototipi ko'rsatilgan.
Listing 16.1. Oddiy classning ochiq a'zosiga kirish
#include <iostream>
using namespace std;
class Cat / / sinfni e'lon qilish
{
public: / / quyidagi a'zolar ochiq
int itsAge;
int itsWeight;
};
int main()
{
Cat Frisky;
Frisky.itsAge =5;
cout << "Frisky is a cat who is ";
cout << Frisky.itsAge << " years old.\n";
return 0;
}
Natija:
Frisky is a cat who is 5 years old.
199
Tahlil:
3-qatorda class kalit so'zi mavjud. Bu kompilyatorga keyingi blok
sinf prototipi ekanligini aytadi. Yangi sinf nomi class kalit so'zidan
keyin darhol keladi. Bunday holda, biz Cat sinfini e'lon qilamiz.
Sinf prototipining tanasi 4-qatorda ochiladigan figurali qavs bilan
boshlanadi va 8-qatorda yopiq figurali qavs va nuqta-vergul bilan
tugaydi. 5-qatorda public kalit so'z mavjud bo'lib, u xususiy kalit so'z
yoki sinf e'lonining oxiriga qadar barcha keyingi a'zolar ochiq deb e'lon
qilinishini anglatadi.
6 va 7-qatorlar itsAge va itsWeight a'zo o'zgaruvchilarini e'lon
qiladi.
9-qatorda dasturning main () funksiyasi boshlanadi. Frisky 11-
qatorda Cat sinfining misoli, ya'ni Cat sinfining obyekti sifatida
aniqlanadi. 12-qatorda Frisky obyektining itsAge maydoniga 5
o'rnatiladi. 13 va 14-qatorlarda ma'lumotlarni ekranga chiqarish uchun
itsAge a'zosi o'zgaruvchisi ishlatiladi.
SINF MA'LUMOTLARINING PRIVATE HOLATI
Sinflardan foydalanishning umumiy strategiyasiga ko'ra, sinf
a'zolari o'zgaruvchilari yopiq holda qoldirilishi kerak. Buning
yordamida sinf ichidagi ma'lumotlarni inkapsulyatsiya qilishga
erishiladi. Kirish faqat sinfning yopiq ma'lumotlariga kirishni
ta'minlaydigan a'zo funksiyalariga ochilishi kerak (bu funksiyalar kirish
usullari deb ham ataladi). Ushbu usullarni dasturning istalgan joyidan
yopiq a'zo o'zgaruvchilarning qiymatlarini qaytarish yoki o'rnatish
uchun chaqirish mumkin.
Nima uchun dasturda yopiq sinf a'zolari va dasturning qolgan qismi
o'rtasida bunday vositalar ishlatiladi? Kirish usullari bilan ishlash
o'rniga, sinf ma'lumotlarini tashqi kirish uchun ochish osonroq emasmi?
Kirish usullaridan foydalanish obyektlarda ma'lumotlarni saqlash
tafsilotlarini foydalanuvchidan yashirishga imkon beradi, shu bilan
birga ularni ushbu ma'lumotlardan foydalanish usullari bilan
ta'minlaydi. Natijada, tashqi dastur kodida kirish usullari va
murojaatlarini qayta yozmasdan, sinf ichidagi ma'lumotlarni saqlash va
qayta ishlash usullarini yangilash mumkin.
Agar Cat obyektining yoshini qaytaradigan dasturdagi ba'zi bir
tashqi funksiyalar uchun itsage o'zgaruvchisiga to'g'ridan-to'g'ri
kirishni ochsangiz, Cat sinf muallifi ushbu ma'lumot komponentini
saqlash usulini o'zgartirishga qaror qilsa, ushbu funksiyani qayta yozish
200
kerak bo'ladi. Ammo, agar tashqi funksiya va sinf ma'lumotlari o'rtasida
getage () a'zo funksiyasi bo'lsa, u holda Cat sinfi xohlagancha
yangilanishi mumkin, bu dasturning asosiy kodidagi GetAge()
funksiyasini chaqirish usuliga ta'sir qilmaydi. Dasturga kirish usulini
chaqirganda, kerakli qiymat unsigned integer yoki long turidagi
o'zgaruvchida saqlanganligini yoki so'ralganda hisoblanganligini
bilishingiz shart emas.
Ushbu yondashuv sizning dasturingizdan foydalanishni va
kelajakda uni qo'llab-quvvatlashni osonlashtiradi. Aytishimiz
mumkinki, bu dasturning umrini uzaytiradi, chunki sinflarni o'zgartirish
orqali siz asosiy kodga ta'sir qilmasdan dasturning bajarilishini sezilarli
darajada modernizatsiya qilishingiz mumkin.
16.2 Listingida bu safar yopiq a'zo o'zgaruvchilar va yopiq
ma'lumotlarga kirishning ochiq usullari e'lon qilingan Cat sinfi
ko'rsatilgan.
Listing 16.2. Sinf ma'lumotlariga kirish usullarini e'lon qilish
class Cat
{
public:
unsigned int GetAge():
void SetAge(unsigned int Age);
unsigned int GetWeight();
void SetWeight(unsigned int Weight);
void Meow();
private:
unsigned int itsAge;
unsigned int itsWeight;
};
Ushbu sinfda beshta public funksiyasi mavjud.
Frisky mushukining yoshini aniqlash uchun tegishli qiymatni
setAge() usuliga o'tkazish kerak:
Cat Frisky;
Frisky. SetAge (5); / / Frisky yoshini ochiq kirish usuli bilan
o'rnating
Usullar yoki ma'lumotlarni yopiq deb e'lon qilish kompilyatorga
dasturlash xatolarini oldindan topishga imkon beradi. Ajam dasturchilar
ko'pincha ma'lumotlarni yopiq deb e'lon qilish va shu bilan tegishli
kirish huquqiga ega bo'lmagan foydalanuvchilardan ba'zi maxfiy
ma'lumotlarni yashirish deb noto'g'ri ishonishadi. Aslida, bunday emas.
201
Shu munosabat bilan C++ tilining ixtirochisi Straustrap (Stroustrup)
shunday dedi: "C++ ga kirishni boshqarish mexanizmlari baxtsiz
hodisalardan himoya qiladi, ammo firibgarlardan emas" (ARM, 1990).
Tavsiya etiladi!
Sinfning a'zo o'zgaruvchilarini yopiq deb e'lon qiling (private kalit
so'z bilan).
Yopiq sinf a'zolari ma'lumotlariga kirish usullarini ochiq deb e'lon
qiling.
A'zo ma'lumotlarini qayta ishlash uchun yopiq sinf a'zo
funksiyalaridan foydalaning.
Tavsiya etilmaydi!
Sinfdan tashqarida yopiq a'zo o'zgaruvchilardan
foydalanishga urinmang.
CLASS KALIT SO'ZI
Class kalit so'zi quyidagi sintaksisga ega:
sinf nomi
// bu yerda kirishni boshqarish kalit so'zlari mavjud
Class kalit so'zi yangi turlarni e'lon qilish uchun ishlatiladi. Sinf-
bu har xil tipdagi o'zgaruvchilar, shu gapdan boshqa sinflar bo'lgan
sinfga a'zo ma'lumotlar to'plami. Sinf shuningdek, sinf funksiyalari
yoki sinf ma'lumotlari bo'yicha harakatlarni amalga oshirish uchun
ishlatiladigan usullarni, shuningdek sinf ichidagi boshqa xizmat
turlarini o'z ichiga oladi;
Yangi turdagi obyektlarni aniqlash har qanday o'zgaruvchini
aniqlashga o'xshaydi. Avval turi (sinf), so'ngra o'zgaruvchining nomi
(obyekt) ko'rsatiladi. Sinf a'zolariga (ma'lumotlar va funksiyalar)
murojaat qilish uchun nuqta operatori (.)ga murojaat qiling.
Sinfning ochiq yoki yopiq bo'limlarini e'lon qilish uchun public
yoki private kirishni boshqarish kalit so'zlari ishlatiladi. Har bir kalit
so'z kirishni boshqarish rejimini ushbu asosiy spovdan foydalangan
paytdan boshlab sinf e'lonining oxirigacha yoki keyingi kirishni
boshqarish kalit so'zi paydo bo'lguncha o'zgartiradi. Barcha sinf
prototiplari yopiq figurali qavs va nuqta-vergul bilan tugaydi.
1-misol:
class Cat
{
public:
unsigned int Age;
unsigned int Weight:
202
void Meow();
};
Cat Frisky;
Frisky. Age = 8;
Frisky Weight = 18:
Frisky. Meow();
SINF METODLARINI (USUL, FUNKSIYA) ANIQLASH
Yuqorida aytib o'tilganidek, kirish usullari yopiq sinf a'zolari
o'zgaruvchilari bilan ishlash uchun interfeysni ta'minlaydi. Kirish
usullari uchun, boshqa barcha e'lon qilingan sinf usullari kabi,
bajarilishini aniqlash kerak. Shunday qilib, usullar sinfda e'lon qilinadi
va aniqlanadi.
A'zo funksiyasining ta'rifi sinf nomi bilan boshlanadi, so'ngra
ikkita nuqta, funksiya nomi va uning parametrlari. 16.3 Listingi oddiy
Cat sinfining e'lonini ko'rsatadi, unda ilgari e'lon qilingan
ma'lumotlarga kirish usullari va bitta oddiy a'zo funksiyasining ta'riflari
mavjud.
Listing 16.3. Oddiy sinf usullarini aniqlash
1 #include <iostream>
2 using namespace std;
3 class Cat// sinf e'lonini boshlash
4{
5 public:// Public bo'limining boshlanishi
6 int GetAge;// kirish usuli
7 void SetAge (int age); / / kirish usuli
8 void Meow();// oddiy usul
9 private:// xususiy bo'limning boshlanishi
10 int itsAge; // atama o'zgaruvchisi
11 };
12 int Cat::GetAge()
13 {
14 return itsAge;
15 }
16 void Cat::SetAge(int age)
17 {
18 itsAge = age;
19 }
20 void Cat::Meow()
21 {
22 cout << "Meow.\n";
23 }
24 int main()
25 {
26 Cat Frisky;
27 Frisky. SetAge(5);
28 Frisky. Meow();
203
29 cout << "Frisky is a cat who is "
30 cout << Frisky.QetAge() << " years old.\n";
31 Frisky. Meow();
32 return 0;
33 }
Natija:
Meow.
Frisky is a cat who is 5 years old.
Meow.
Tahlil:
3-11 qatorlar Cat sinfining ta'rifini o'z ichiga oladi. 5-qatorni Public
kalit so'zi mavjud, bu kompilyatorga undan keyin sinfning ochiq
a'zolari to'plami kelishini aytadi. 6-qatorda 10-qatorda e'lon qilingan
private itsAge a'zo o'zgaruvchisiga kirishni ta'minlaydigan GetAge ()
public usul prototipi mavjud. 7-qatorda public SetAge() kirish
funksiyasi e'lon qilinadi, u argument sifatida butun sonni oladi va
itsAge o'zgaruvchisiga ushbu argumentning qiymatini beradi.
8-qatorda Meow () usuli e'lon qilinadi. Ushbu usul Meow so'zini
ekranga chiqarish uchun ishlatiladigan sinf a'zosi ma'lumotlariga kirish
funksiyasi emas.
9-qatorda private bo'lim boshlanadi, unda faqat bitta private itsAge
a'zo o'zgaruvchisi prototipi (10-qator) mavjud. Sinf prototipi 11-
qatorda yopiq figurali qavs va nuqta-vergul bilan tugaydi.
12-15 qatorlar GetAge () a'zo funksiyasining ta'rifini o'z ichiga
oladi. Ushbu usul hech qanday parametrlarni qabul qilmaydi va butun
qiymatni qaytaradi.
E'tibor bering, sinf usullarini aniqlashda sinf nomi, so'ngra ikkita
ikki nuqta va funksiya nomi ishlatiladi. Ushbu sintaksis tufayli
kompilyator bu yerda aniqlangan GetAge () funksiyasi Cat sinfida e'lon
qilingan funksiya ekanligini bilib oladi. Sarlavha satridan tashqari,
GetAge() boshqa funksiyalar bilan bir xil tarzda yaratilgan.
GetAge () funksiyasining ta'rifi faqat bitta qatorni oladi, bu
funksiya itsAge a'zosi o'zgaruvchisining qiymatini qaytarishini
bildiradi. E'tibor bering, main() funksiyasi ushbu o'zgaruvchiga kira
olmaydi, chunki u Cat sinfining yopiq qismida e'lon qilingan. Bunday
holda, main() funksiyasidan ochiq GetAge () usuliga murojaat
qilishingiz mumkin. GetAge () usuli Cat sinfining a'zo funksiyasi
bo'lganligi sababli, u itsage a'zo o'zgaruvchisiga barcha kirish
204
huquqlariga ega. Natijada GetAge () funksiyasi itsage
o'zgaruvchisining qiymatini main() funksiyasiga qaytaradi.
16-qatorda SetAge () a'zo funksiyasining ta'rifi boshlanadi. U
butun sonli parametrni oladi va itsAge o'zgaruvchisiga ushbu
parametrning qiymatini beradi (27-qator). Cat sinfining a'zosi sifatida
SetAge() funksiyasi itsAge a'zo o'zgaruvchisiga to'g'ridan-to'g'ri kirish
huquqiga ega.
KONSTRUKTORLAR VA DESTRUKTORLAR
Butun o'zgaruvchisini aniqlashning ikkita usuli mavjud.
Birinchidan, o'zgaruvchini aniqlash mumkin, so'ngra (dasturda biroz
pastroq) unga ba'zi qiymatlarni berish mumkin, masalan:
int Weight; // o'zgaruvchini aniqlang
…. // bu yerda boshqa ifodalar keladi
Weight=7; // o'zgaruvchiga qiymat bering
O'zgaruvchini aniqlash va uni darhol ishga tushirish ham mumkin,
masalan:
int Weight=7;
Ishga tushirish jarayoni o'zgaruvchining ta'rifini boshlang'ich
qiymatni o‘zlashtirish bilan birlashtiradi. Bundan tashqari, keyinchalik
bu qiymatni o'zgartirishga hech narsa to'sqinlik qila olmaydi. Bundan
tashqari, ta'rif bilan bir vaqtda amalga oshirilgan initsializatsiya
o'zgaruvchining ajratilgan o'zgaruvchan xotira katakchalarida qolgan
qoldiqlarni o'z ichiga olmaydi.
Sinf a'zolari o'zgaruvchilarini qanday boshlash kerak? Buning
uchun sinf deb nomlangan maxsus a'zo funksiyasidan
foydalanadi. Agar kerak bo'lsa, konstruktor parametrlarni qabul qilishi
mumkin, lekin hatto void turidagi qiymatlarni ham qaytara olmaydi.
Konstruktor-bu sinfning o'zi bilan bir xil nomga ega bo'lgan sinf usuli.
Konstruktorni e'lon qilgandan so'ng, siz destruktorni ham e'lon
qilishingiz kerak. Agar konstruktorlar sinf obyektlarini yaratish va
ishga tushirish uchun xizmat qilsa, destruktorlar ishlatilgan obyektlarni
xotiradan olib tashlaydi va ular uchun ajratilgan xotirani bo'shatadi.
Destruktorga har doim boshida tilda (") belgisi bo'lgan sinf nomi
beriladi. Destruktorlar hech qanday dalillarni qabul qilmaydi va hech
qanday qiymatni qaytarmaydi. Cat class prototipi
quyidagicha ko'rinadi:
Cat();
205
Agar siz konstruktor yoki destruktorni e'lon qilmasangiz,
kompilyator buni siz uchun qiladi. Standart konstruktor va destruktor
argumentlarni qabul qilmaydi yoki hech qanday harakat qilmaydi.
Hech narsa vazifa bajarmaydigan loyihalashdan nima foyda?
Ko'pincha bu faqat protokol uchun kerak. Barcha obyektlar dasturda
lokalizatsiya qilinishi kerak, shuning uchun ularni yaratish va o'chirish
tegishli funksiyani chaqirish bilan birga keladi, bu esa hech narsa qila
olmaydi. Shunday qilib, parametrlarni uzatmasdan obyektni e'lon qilish
uchun, masalan
Cat Rags; / / Rags hech qanday parametr olmaydi
quyidagi konstruktorga ega bo‘lishingiz kerak:
Cat();
Konstruktor sinf obyektini aniqlashda chaqiriladi. Agar Cat
sinfining obyektini yaratish uchun ikkita parametr o'tkazilishi kerak
bo'lsa, u holda Cat sinfining konstruktori quyidagicha aniqlanadi:
Cat Frisky (5,7);
Agar konstruktor bitta parametrni qabul qilsa, obyekt ta'rifi
quyidagicha bo'ladi:
Cat Frisky (3);
Agar konstruktor parametrlarni umuman qabul qilmasa (ya'ni
standart bo'lsa), qavslardan foydalanishga hojat qolmaydi:
Cat Frisky;
Ushbu holat barcha funksiyalar parametrlarni umuman qabul
qilmasa ham, qavs kerak degan qoidadan istisno hisoblanadi. Shuning
uchun siz ushbu ta'rifni xavfsiz yozishingiz mumkin:
Cat Frisky;
Ushbu yozuv standart konstruktorga murojaat sifatida talqin
etiladi. Unda parametrlarning uzatilishi va natijada qavslar mavjud
emas.
Shuni esda tutingki, siz kompilyator tomonidan taqdim etilgan
standart konstruktordan o‘zgarmas ravishda foydalanishingiz shart
emas. Siz har doim o'zingizning standart konstruktoringizni yozishingiz
mumkin, ya'ni.parametrlarsiz konstruktor. Siz o'zingizning standart
konstruktoringizga sinfni boshlash amalga oshiriladigan funksiya
tanasini berishingiz mumkin.
16.4 Listingida siz allaqachon tanish bo'lgan Cat sinfiga
konstruktor va destruktor qo'shildi. Konstruktor Cat obyektini ishga
tushirish va uning yoshini siz taqdim etgan qiymatga tenglashtirish
206
uchun ishlatiladi. Dasturning qaysi joyida destruktor chaqirilganiga
e'tibor bering.
Listing 16.4. Konstruktorlar va destruktorlardan foydalanish
1 #include <iostream>
2 using namespace std;
3 class Cat// sinf e'lonini boshlash
4{
5 public: // ochiq bo'limning boshlanishi
6 Cat(int initialAge); // konstruktor
7 "Cat(); / buzuvchi
8 int GetAge();// kirish usuli
9 void SetAge(int age); //kirish usuli
10 void Meow();
11 private: // yopiq bo'limning boshlanishi
12 int itsAge; // atama o'zgaruvchisi
13 };
14 Cat::Cat(int initialAge)
15 {
16 itsAge = initialAge;
17 }
18 Cat::"Cat() / harakatlarni bajarmaydigan destruktor
19 {}
20 int Cat::GetAge()
21 {return itsAge;}
22 void Cat::SetAge(int age)
23 { itsAge = age; }
24 void Cat::Meow()
25 { cout << "Meow.\n";}
26 int main()
27 {
28 Cat Frisky(5);
29 Frisky. Meow();
30 cout << "Frisky is a cat who is "
31 cout << Frisky.QetAge() << " years old.\n";
32 Frisky. Meow();
33 Frisky. SetAge(7);
34 cout << "Now Frisky is " ;
35 cout << Frisky.GetAge() << " years old.\n";
36 return 0;
37 }
Natija:
Meow.
Frisky is a cat who is 5 years old.
207
Meow.
Now Frisky is 7 years old.
Tahlil:
16.4 Listingi 16.3 Listingiga o'xshaydi, faqat 9-qatorga parametr
sifatida butun son qiymatini oladigan konstruktor qo'shiladi. 10-qatorda
hech qanday parametrlarni qabul qilmaydigan destruktor e'lon qilinadi.
Esingizda bo'lsin, destruktorlar hech qachon parametrlarni qabul
qilmaydi; bundan tashqari, na konstruktorlar, na destruktorlar hech
qanday qiymatni, hatto void tipidagi qiymatni ham qaytarmaydi.
19-22-qatorlarda setage () kirish funksiyasiga o'xshash
konstruktorning bajarilishi aniqlanadi, bu ham hech qanday qiymatni
qaytarmaydi.
24-26-qatorlarda "Cat ()" destruktori aniqlanadi. Ushbu funksiya
hech qanday harakatni amalga oshirmaydi, lekin agar siz uni sinfda
e'lon qilsangiz, uning ta'rifini ham kiritishingiz kerak.
Tavsiya etiladi!
Obyektlarni ishga tushirish uchun konstruktorlardan
foydalaning.
C++ tilida sinf usulini shunday e'lon qilish imkoniyati mavjudki,
bunday usulga sinf a'zolari o'zgaruvchilarining qiymatlarini o'zgartirish
taqiqlanadi. Buning uchun funksiya prototipida qavslardan keyin, lekin
nuqta-verguldan oldin const kalit so'zi ishlatiladi. Masalan,
argumentlarni qabul qilmaydigan va void tipidagi qiymatni
qaytaradigan SomeFunction () a'zosi funksiyasini shu tarzda e'lon
qilamiz:
void SomeFunction() const;
Ma'lumotlarga kirish funksiyalari ko'pincha const spetsifikatori
bilan e'lon qilinadi. Cat sinfida ikkita kirish funksiyasi mavjud:
void SetAge(int anAge);
int GetAge();
Setage () funksiyasini const spetsifikatori bilan e'lon qilish mumkin
emas, chunki u itsage a'zosi o'zgaruvchisining qiymatini o'zgartiradi.
Va GetAge () funksiyasini e'lon qilishda const spetsifikatoridan
foydalanish mumkin va hatto kerak, chunki u sinfda hech narsani
o'zgartirmasligi kerak. GetAge () funksiyasi shunchaki itsage a'zosi
o'zgaruvchisining joriy qiymatini qaytaradi. Shuning uchun ushbu
funksiyalarning prototipi ushbu rasmda yozilishi kerak:
void SetAge(int anAge);
208
int GetAge() const;
Agar biror bir funksiya const spetsifikatori yordamida e'lon
qilingan bo'lsa va uning bajarilishida obyektning biror bir a'zosi
o'zgarsa, kompilyator xato xabarini ko'rsatadi. Masalan, Agar siz
GetAge() funksiyasini Cat obyektining yoshi necha marta
so'ralganligini hisoblaydigan tarzda yozsangiz, kompilyatsiya xatosi
albatta hosil bo'ladi, chunki bunday hisoblash bilan (ya'ni GetAge ()
funksiyasini chaqirganda) Cat obyekti o'zgaradi.
ESLATMA:Agar obyektni o'zgartirmasa, a'zo funksiyalari
prototiplarida const spetsifikatoridan foydalaning. Bu kompilyatorga
xatolarni yaxshiroq kuzatish imkonini beradi va dasturni disk
raskadrovka qilishda sizga yordam beradi.
Obyektni o'zgartirmaydigan usul prototiplarida const-dan
foydalanish yaxshi dasturlash uslubi hisoblanadi. Bu kompilyatorga
dasturni ishga tushirishdan oldin xatolarni yaxshiroq kuzatish imkonini
beradi.
Yuqorida aytib o'tilganidek, mijozlar sizning sinfingiz obyektlarini
yaratadigan va ulardan foydalanadigan dasturning tarkibiy qismidir.
Ochiq sinf interfeysi (sinf prototipi) ushbu mijozlar bilan shartnoma
sifatida tasavvur qilinishi mumkin, bu mijozlarning sinf bilan o'zaro
munosabatlari usullarini ko'rsatadi.
Masalan, Cat sinfining e'lonida mijoz dasturi setage() kirish
funksiyasidan foydalangan holda ushbu sinf obyektining har qanday
yoshini boshlashi va GetAge () kirish funksiyasidan foydalanib ushbu
qiymatni qaytarishi mumkinligi ko'rsatilgan. Shu bilan birga, har bir
Cat sinfidagi obyekt meow () a'zo funksiyasidan foydalangan holda
meow xabarini ekranga chiqarishi kafolatlanadi. E'tibor bering, ochiq
sinf interfeysida sinfni bajarishda ishlatiladigan va mijozlarni
qiziqtirmasligi kerak bo'lgan yopiq itsage a'zo o'zgaruvchisi haqida
hech narsa aytilmagan. Yosh qiymati GetAge() yordamida obyektdan
qaytarilishi va SetAge () yordamida o'rnatilishi mumkin, ammo bu
qiymat saqlanadigan itsage
C++ tilida ma'lumotlar turlarini qat'iy nazorat qilish amalga
oshiriladi, shuning uchun sinf va mijozlar o'rtasidagi bunday kelishuv
kompilyator uchun qonun bo'lib, ushbu shartnoma buzilgan taqdirda
kompilyatsiya xatosini keltirib chiqaradi. Listing 16.5 ushbu
kelishuvlarni buzganligi sababli kompilyatsiya qilinmaydigan
dasturning namunasini ko'rsatadi.
209
ESLATMA: Listing 16.5 kompilyatsiya qilinmaydi!
Listing 16.5. Interfey kelishuvlarini buzish misoli
1 #include <iostream>
2 using namespace std;
3 class Cat
4{
5 public:
6 Cat(int initialAge);
7 Cat();
8 int GetAge() const;
9 void SetAge (int age);
10 void Meow();
11 private:
12 int itsAge;
13 };
14 Cat::Cat(int initialAge)
15 {
16 itsAge = initialAge;
17 cout << "Cat constructor\n";
18 }
19 Cat:: Cat ()
20 {
21 cout << "Cat destructor\n";
22 }
23 int Cat::GetAge() const
24 {
25 return (itsAge++);
26 }
27 void Cat::SetAge(int age)
28 {
29 ItsAge = age;
30 }
31 void Cat::Meow()
32 {
33 cout << "Meow.\n";
34 }
35 int main()
36 {
37 mushuk Frisky;
38 Frisky. Meow();
39 Frisky.Bark ();
40 Frisky.itsAge = 7;
41 return 0;
42 }
Tahlil:
Yuqorida aytib o'tilganidek, ushbu dastur kompilyatsiya
qilinmaydi. Shuning uchun uning ishining natijalari yo'q.
210
Ushbu dasturni yozish juda qiziqarli edi, chunki unda xatolar
maxsus joylashtirilgan edi.
8-qatorda GetAge () const spetsifikatori ko'rsatganidek, ularni
o'zgartirish huquqisiz sinf a'zolari ma'lumotlariga kirish funksiyasi
sifatida e'lon qilinadi. Biroq, GetAge () funksiyasining tanasida, ya'ni
29-qatorda, itsAge a'zosi o'zgaruvchisi ko'payadi, bu usul const deb
e'lon qilinganligi sababli, itsAge o'zgaruvchisining qiymatini
o'zgartirish huquqiga ega emas. Shuning uchun, dasturni kompilyatsiya
qilish paytida ushbu satrda xato qayd etiladi.
10-qatorda Meow () usuli e'lon qilinadi, bu safar const kalit
so'zidan foydalanmasdan, bunday kamchilik xato bo'lmasa-da, bu eng
yaxshi dasturlash uslubidan uzoqdir. Agar ushbu usul Cat sinfining a'zo
o'zgaruvchilarining qiymatlarini nomlamasligi kerak deb hisoblasak, u
const spetsifikatori bilan aniqlanishi kerak.
ESLATMA: Agar biror-bir konstruktor sinfda e'lon qilinsa, bu
holda kompilyator o'z navbatida boshqa biror bir konsgruktorani taklif
qilmaydi, hatto obyektning rasmi bo'yicha ta'rifi e'lon qilingan
konstruktorga mos kelmasa ham. Bunday hollarda kompilyatsiya xato
xabarini ko'rsatadi.
Hech qanday xato qilmasdan dastur yozish aql bovar qilmaydigan
ko'rinadi. Shunga qaramay, ba'zi dasturchilar bunday mo " jizalarga
qodir, garchi, albatta, bunday sehrgarlar juda kam. Ularning aksariyati,
barcha oddiy odamlar kabi, xato qilishadi. Shu sababli, dasturlarni
yaratishning dastlabki bosqichida ularni ushlab qolish va tuzatish orqali
xatolarni kuzatishda yordam beradigan tizimni ishlab chiqqan
dasturchilar mavjud edi.
Kompilyator tomonidan aniqlangan xato xabarlari asablarga ta'sir
qilsa-da, bu dasturni bajarishda xatolar paydo bo‘lishiga qaraganda
ancha yaxshi. Agar kompilyator kamroq sinchkovlik bilan ishlagan
bo'lsa, unda sizning dasturingiz eng noo'rin daqiqada, masalan,
taqdimot paytida ishlamay qolishi ehtimoli katta.
Kompilyatsiya xatolari, ya'ni kompilyatsiya bosqichida aniqlangan
xatolar dasturni ishga tushirgandan so'ng paydo bo'ladigan ijro
xatolariga qaraganda ancha zararsizdir. Kompilyator aniqlangan xato
haqida ehtiyotkorlik bilan va Bir xil tipdagi xabar beradi. Aksincha, ish
vaqti xatosi hozircha o'zini aniqlay olmasligi mumkin, ammo keyin eng
noo'rin daqiqada o'zini namoyon qiladi. Kompilyatsiya xatolari har bir
kompilyatsiya seansida o'zini namoyon qilganligi sababli, ularni
211
aniqlash va tuzatish oson, shuning uchun ular endi esga olinmaydi. Vaqt
o'tishi bilan sehrli fokuslarni tashlamaydigan dasturlarni yaratishga
erishish uchun dasturchi kompilyatorga xatolarni kuzatishda yordam
berishi kerak, bu mumkin bo'lgan nosozliklarning oldini olish uchun
e`lonlardagi spetsifikatorlardan foydalanadi.
Sinfda e'lon qilingan har bir funksiya ta'rifga ega bo‘lishi kerak.
Ta'rif funksiyani bajarish deb ham ataladi. Boshqa funksiyalar kabi, sinf
usulining ta'rifi funksiya sarlavhasi va tanasidan iborat.
Ta'rif kompilyator osongina topishi mumkin bo'lgan faylda bo‘lishi
kerak. Ko'pgina C++ kompilyatorlari bunday fayl C yoki cpp
kengaytmasiga ega bo‘lishini afzal ko'rishadi. Ushbu kitob
kengaytmadan foydalanadi .cpp, lekin siz o'zingizning
kompilyatoringizning afzalliklarini bilib olishingiz kerak.
ESLATMA: Ko'pgina kompilyatorlar fayl kengaytma haqida deb
hisoblashadi. C C tilida yozilgan dasturlarni o'z ichiga oladi va SRP
kengaytmali fayllar C++ dasturlaridir. Siz har qanday kengaytmadan
foydalanishingiz mumkin, ammo C++dasturlarida yuzaga kelishi
mumkin bo'lgan tushunmovchiliklarni minimallashtiradigan cpp.
Sinf e'lonlari dastur bilan bitta faylga joylashtirilishi mumkin,
ammo bu yaxshi dasturlash uslubi deb hisoblanmaydi. Ko'pgina
dasturchilar tomonidan tuzilgan shartnomada, odatda, nomi dastur
faylining nomi bilan bir xil bo'lgan sarlavha fayliga e`lon qo'yish
tavsiya etiladi, ammo kengaytma sifatida quyidagi variantlardan
foydalaniladi .h, .hp yoki .hpp. Ushbu kitob sarlavhali fayl nomlari
uchun .hpp kengaytmadan foydalanadi, lekin siz o'zingizning
kompilyatoringizning afzalliklarini bilib olishingiz kerak.
Masalan, Cat class prototipini CAT, hpp deb nomlangan faylga va
sinf usullarining ta'rifini Cat.srr deb nomlangan faylga qo'yish mumkin.
Keyin sarlavha faylini kengaytmali fayl kodiga kiritishingiz kerak .srr.
Buning uchun CAT faylidagi dastur kodining boshida. cpp quyidagi
buyruqdan foydalanadi:
#include "Cat. hpp"
Ushbu buyruq kompilyatorga dasturning ma'lum bir joyida HPP sat
faylining tarkibini kiritishni buyuradi. Include buyrug'ini bajarish
natijasi klaviaturadan dasturning ushbu joyiga tegishli sarlavha
faylining to'liq tarkibini qayta yozganingiz bilan bir xil. Shuni yodda
tutingki, ba'zi kompilyatorlar harflarning katta-kichikligiga sezgir va
212
#include E’lonida va diskda fayl nomlarining yozilishi aniq mos
kelishini talab qiladi.
Nima uchun sarlavha faylini kengaytma bilan ajratish kerak .
kengaytmali dastur faylidan hpp.SRP, agar biz hali ham dastur fayliga
sarlavha faylining tarkibini kiritmoqchi bo'lsak? Amaliyot shuni
ko'rsatadiki, ko'pincha sizning sinfingiz mijozlari uni amalga oshirish
tafsilotlari haqida qayg'urmaydilar. Kichik sarlavha faylini
o'qiyotganda, ular barcha kerakli ma'lumotlarni olishadi va ushbu
sinfning ishlash tafsilotlari bilan faylni e'tiborsiz qoldirishlari mumkin.
Bundan tashqari, kengaytmali sarlavha faylining tarkibi bo‘lishi
mumkin . hpp-ni bitta emas, balki bir nechta dastur fayllariga qo'shishni
xohlaysiz.
ESLATMA:Sinf prototipi kompilyatorga ushbu sinf nima
ekanligini, unda qanday ma'lumotlar borligini va qanday funksiyalarga
ega ekanligini aytadi. Sinf prototipi uning interfeysi deb ataladi, chunki
u foydalanuvchiga sinf bilan qanday munosabatda bo‘lishni aytadi.
Interfeys odatda kengaytmali faylda saqlanadi .sarlavha fayli deb
nomlangan hpp.
Funksiya ta'rifidan kompilyator uning qanday ishlashini bilib oladi.
Funksiyaning ta'rifi sinf usulini bajarish deb ataladi va kengaytma bilan
faylda saqlanadi .srr. Sinfning bajarilishi tafsilotlari faqat sinf
muallifiga tegishli. Sinf mijozlari, ya'ni. ushbu sinfdan foydalanadigan
dasturning qismlari funksiyalar qanday bajarilishini bilishlari shart
emas.
Oddiy funksiyalar bilan bo'lgani kabi, inline kalit so'zi yordamida
usullarni almashtirish mumkin. Buning uchun inline kalit so'zi
qaytariladigan qiymat turidan oldin joylashtirilishi kerak. Masalan,
almashtirilayotgan getweight () a'zo funksiyasining ta'rifi quyidagi
rasmga ega:
inline int Cat::GetWeight()
{
return itsweight;
}
Bundan tashqari, funksiya ta'rifini sinf prototipiga
joylashtirishingiz mumkin, bu esa avtomatik ravishda bunday
funksiyani almashtiradi:
class Cat
{
public:
int GetWeight () {return itsWeight;}
213
void SetWeight(int aWeight);
};
GetWeight () funksiyasini aniqlash sintaksisiga e'tibor bering.
O'zgartirilgan funksiyaning tanasi sinf usuli e'lon qilingandan so'ng
darhol boshlanadi va qavslardan keyin nuqta-vergul yo'q. Oddiy
funksiyani aniqlashga o'xshab, usulning ta'rifi ochiladigan figurali qavs
bilan boshlanadi va yopuvchi figurali qavs bilan tugaydi. Odatdagidek,
bo‘sh joylar muhim emas va xuddi shu ta'rifni biroz boshqacha yozish
mumkin:
class Cat {
public:
int GetWeight() const
{ return itsWeight; // almashtirish funksiyasi }
void SetWeight(int aWeight);};
16.6 va 16.7 Listinglarida Cat sinfi yana yaratiladi, ammo bu holda
sinf prototipi Cat.hpp faylida, bajarilishi esa Cat.cpp faylida mavjud.
Bundan tashqari, 6.7 Listingida sinf ma'lumotlariga kirish usuli va
Meow() usuli almashtiriladi.
Listing 16.6. Cat.cpp faylida e'lon qilingan Cat
1 #include <iostream>
2 using namespace std;
3 class Cat {
4 public:
5 Cat (int initialAge);
6 ~Cat();
7 int GetAge() const { return itsAge; }
8 void SetAge (int age) { itsAge = age; }
9 void Meow () const { cout << "meow.\n";}
10 private:
11 int itsAge;
12 };
Listing 16.7. Cat.cpp faylida Cat sinfini bajarish
1 #include <iostream>
2 #include "cat.hpp "
3 using namespace std;
4 Cat:: Cat (int initialAge) / / konstruktor
5{
6 itsAge = initialAge;
7}
8 Cat:: Cat()
9 {}
10 int main()
11 {
12 Cat Frisky(5);
13 Frisky. Meow();
214
14 cout << "Frisky is a cat who is ";
15 cout << Frisky.QetAge() << " years old.\n";
16 Frisky. Meow();
17 Frisky. SetAge(7);
18 cout << "Now Frisky is "
19 cout << Frisky.GetAge() << " years old.\n";
20 return 0;
21 }
Natija:
Meow.
Frisky is a cat who is 5 years old.
Meow.
Now Frisky is 7 years old.
Tahlil:
16.6 va 16.7-Listinglarda taqdim etilgan dastur 16.4-Listingdagi
dasturga o'xshaydi, faqat uchta sinf usuli almashtirilgan deb e'lon
qilinadi va sinf prototipining o'zi Cat.hpp sarlavha fayliga
joylashtiriladi.
7-qatorda GetAge () funksiyasi e'lon qilinadi va darhol uning
bajarilishini aniqlash kerak. 8 va 9-qatorlar yana ikkita o'rnatilgan
funksiyalarning e'lonlarini egallaydi, ammo ularning ta'riflari boshqa
faylda mavjud.
16.7 Listingining 4-qatorida #include "cat.hpp " dasturi Cat.hpp
faylining tarkibini o'z ichiga oladi. Kompilyator cat.hpp faylining
tarkibini hisoblash va uni 5-qatordan boshlab berilgan faylga kiritish
buyrug'ini oladi.
Fayllarni boshqa fayllarga joylashtirish qobiliyati sinf e'lonlarini
ularni bajarishdan alohida saqlashga va kerak bo'lganda foydalanishga
imkon beradi. Bu C++dasturlarini yaratishda standart usul. Odatda, sinf
prototiplari hpp kengaytmasi bo'lgan faylda saqlanadi, so'ngra #include
e’loni yordamida tegishli cpp fayliga kiritiladi.
Oddiy sinflarni e'lon qilish va keyinchalik ularni murakkab sinf
prototipiga kiritish orqali murakkab sinf qurish odatiy hol emas.
Masalan, siz g'ildirak sinfini, dvigatel sinfini, Vites qutisi sinfini va
boshqalarni e'lon qilishingiz va keyin ularni avtomobil sinfiga
birlashtirishingiz mumkin. Shunday qilib, sinflar o'rtasidagi o'zaro
munosabatlar e'lon qilinadi. Avtomobilda dvigatel, g'ildiraklar va Vites
qutisi mavjud.
Ikkinchi misolni ko'rib chiqing. To'rtburchak chiziqlardan iborat.
Chiziq ikki nuqta bilan belgilanadi. Har bir nuqta x va y koordinatalari
215
bilan belgilanadi. 16.8 Listingida RECTANGLE faylida joylashgan
Rektangle sinfining prototipi ko'rsatilgan. hpp. To'rtburchak to'rtta
nuqtani bog'laydigan to'rtta chiziq bilan aniqlanganligi va har bir nuqta
grafikada koordinatalarga ega bo'lganligi sababli, avval har bir nuqta
uchun x koordinatalarini saqlash uchun nuqta sinfi e'lon qilinadi.
Listing 16.9 ikkala sinfning e'lonlarini o'z ichiga oladi.
216
Listing 16.9. Rect.cpp faylining tarkibi
1 #include "rect.hpp"
2 Rectangle::Rectangle(int top, int left, int bottom, int right)
3{
4 itsTop = top;
5 itsLeft = left;
6 itsBottom = bottom;
7 itsRight = right;
8 itsUpperLeft.SetX(left);
9 itsUpperLeft. SetY(top);
10 itsUpperRight.SetX(right);
11 itsUpperRight.SetY(top);
12 itsLowerLeft.SetX(left);
13 itsLowerLeft.SetY(bottom);
14 itsLowerRight.SetX(right);
15 itsLowerRight. SetY(bottom);
16 }
17 int Rectangle::GetArea() const
18 {
19 int Width = itsRignt - itsLeft;
20 int Height = itsTop - itsBottom;
21 return (Width • Height);
22 }
23 using namespace std;
24 int main()
25 {
26 Rectangle MyRectangle (100, 20, 50, 80 );
27 int Area = MyRectangle.GetArea();
28 cout << "Area: "<< Area << "\n";
29 cout << "Upper Left X Coordinate:";
30 cout << MyRectangle.GetUpperLeft().GetX();
31 return 0;
32 }
Natija:
Area: 3000
Upper Left X Coordinate: 20
Tahlil:
16.8 Listingining 3-12-qatorlarida grafikada x, y aniq
koordinatalarini saqlash uchun ishlatiladigan nuqta sinfi e'lon qilinadi.
Ushbu dasturda Point sinfi deyarli ishlatilmaydi. Biroq, boshqa chizish
usullarida bu ajralmas hisoblanadi.
Point class prototipida (10 va 11-qatorlarda) ikkita o'zgaruvchi
e'lon qilinadi (itsX va itsY). Ushbu o'zgaruvchilar nuqta koordinatalari
qiymatlarini saqlaydi. X koordinatasining oshishi bilan biz grafikada
o'ngga siljiymiz. Y koordinatasining oshishi bilan biz grafikda yuqoriga
ko'tarilamiz. Boshqa grafikalar boshqa koordinatali tizimlardan
foydalanishi mumkin (boshqa yo'nalishda). Masalan, ba'zi oyna qurish
217
dasturlarida koordinataning qiymati y deraza maydonini pastga
siljitganda ortadi.
Point sinfi x va y nuqtalarining koordinatalarini o'qish va o'rnatish
uchun mo'ljallangan inline-ga kiritilgan kirish funksiyalaridan
foydalanadi, bu funksiyalar 7-8 qatorlarda e'lon qilinadi. Point sinfidagi
obyektlar standart kompilyator tomonidan taqdim etilgan standart
konstruktor va destruktordan foydalanadi. Shuning uchun nuqta
koordinatalari dasturda o'rnatilishi kerak.
13-qatorda to'rtburchakning burchaklarini ifodalovchi to'rtta
nuqtani o'z ichiga olgan to'rtburchaklar sinfining prototipi boshlanadi.
To'rtburchaklar sinf konstruktori top (yuqori), left (chap), bottom
(pastki) va right (o'ng) deb nomlangan to'rtta butun sonli parametrlarni
oladi.
Konstruktorga berilgan ushbu to'rtta parametr tegishli to'rtta a'zo
o'zgaruvchiga ko'chiriladi (16.9-Listingga qarang), so'ngra to'rtta nuqta
(to'rtta nuqta sinf obyektlari) o'rnatiladi.
Oddiy sinf a'zolari ma'lumotlariga kirish funksiyalaridan tashqari,
to'rtburchaklar sinfida 17-qatorda e'lon qilingan GetArea () funksiyasi
mavjud. Maydon qiymatini o'zgaruvchi sifatida saqlash o'rniga, bu
funksiya 16.9 Listingining 19 va 20 qatorlaridagi maydonni hisoblab
chiqadi. Buning uchun avval to'rtburchakning uzunligi va kengligi
qiymatlari hisoblab chiqiladi, so'ngra olingan natijalar ko'paytiriladi.
To'rtburchakning yuqori chap burchagining koordinatasini olish
uchun siz UpperLeft nuqtasiga kirishingiz va uning x qiymatini
so'rashingiz kerak. GetUpperLeft() funksiyasi Rectangle sinfining usuli
bo'lganligi sababli, u to'g'ridan-to'g'ri ushbu sinfning yopiq
ma'lumotlariga, shu gapdan itsupperleft o'zgaruvchisiga ham kirishi
mumkin. Itsupperleft o'zgaruvchisi Point sinfining obyekti va ushbu
obyektning itsX o'zgaruvchisi yopiq bo'lganligi sababli,
GetUpperLeft() funksiyasi ushbu o'zgaruvchiga to'g'ridan-to'g'ri
murojaat qila olmaydi. Buning o'rniga, itsx o'zgaruvchisining qiymatini
olish uchun u GetX () ochiq kirish funksiyasidan foydalanishi kerak.
16.9 Listingining 24-qatorida dasturning asosiy qismi boshlanadi.
Hozirgacha qilingan hamma narsa kompilyatorga nuqta qanday
yaratilganligi va to'rtburchak qanday yaratilganligi to'g'risida xabar
berish uchun bitta maqsadga xizmat qildi (agar kerak bo'lsa).
218
26-qatorda Thor, Left, Bottom va Right parametrlari uchun haqiqiy
qiymatlarni uzatish orqali to'rtburchak (to'rtburchaklar sinf obyekti)
aniqlanadi.
27-qatorda int tipidagi local maydon o'zgaruvchisi yaratiladi.
Yaratilgan to'rtburchakning maydonini saqlash uchun mo'ljallangan.
Maydon o'zgaruvchisiga Rectangle sinfining GetArea() a'zosi
funksiyasi tomonidan qaytarilgan qiymat beriladi.
Rectangle class Client Rectangle obyektini yaratishi va GetArea ()
funksiyasini bajarish nuanslari haqida qayg'urmasdan uning maydonini
qaytarishi mumkin.
Listing 16.8 Rect sarlavha .hpp faylining tarkibini ko'rsatadi. Faqat
Rectangle sinfining prototipini o'z ichiga olgan sarlavha faylini ko'rib
chiqqandan so'ng, dasturchi GetArea() funksiyasi int tipidagi qiymatni
qaytarishini biladi. Rectangle sinf foydalanuvchisi GetArea ()
funksiyasining "ishlab chiqarish" sirlari haqida qayg'urmaydi.
Rectangle sinfining muallifi GetArea () funksiyasining bajarilishini
o'zgartirishi mumkin va bu Rectangle sinfidan foydalanadigan
dasturlarga ta'sir qilmaydi.
TUZILMALAR
Class kalit so'zining juda yaqin qarindoshi strukturani e'lon qilish
uchun ishlatiladigan struct kalit so'zidir. C++ tilida struktura bir xil sinf,
lekin sukut bo'yicha ochiq a'zolar bilan.Strukturani sinf e'lon
qilinganidek e'lon qilish mumkin, unga bir xil a'zo o'zgaruvchilar va
funksiyalar beriladi.
Ikki xil kalit so'zlar deyarli bir xil e`lonlarni yaratayotganidan
hayron bo‘lishingiz mumkin. Bu tarixan shunday bo'lgan. C++ tili C
kengaytma sifatida qurilgan . C tilida tuzilmalar mavjud edi, ammo bu
tuzilmalar sinf usullariga ega emas edi. C++ yaratuvchisi Byorn
Stroustrap tuzilmalarga tayangan, ammo struct ma'lumotlar turi nomini
sinf turi bilan almashtirgan va shu bilan ushbu yangi ta'limning yangi
rivojlangan funktsional imkoniyatlarini e'lon qilgan.
Tavsiya etiladi!
Sinf prototipini hpp kengaytmasi bo'lgan faylga va uning bajarilishini
cpp kengaytmasi bo'lgan faylga joylashtiring.
Iloji bo'lsa, const spetsifikatoridan foydalaning.
Keyingi darsga o'tishdan oldin darslar haqida to'liq ma'lumotga ega
ekanligingizga ishonch hosil qiling.
219
Nazorat savollari va topshiriqlar:
1. To'g'ridan-to'g'ri kirish operatori nima va u nima uchun ishlatiladi?
2. Sinf prototipi uning interfeysi yoki bajarilishimi?
3. Ochiq (Public) va yopiq (Private) a'zo ma'lumotlar o'rtasidagi farq
nima?
4. A'zo funksiyalar yopiq bo‘lishi mumkinmi?
5. A'zo o'zgaruvchilar ochiq bo‘lishi mumkinmi?
6. Agar Cat sinfining ikkita obyekti e'lon qilinsa, ular itsAge a'zo
o'zgaruvchilarining turli qiymatlariga ega bo‘lishi mumkinmi?
7. Sinf e'lonlarini nuqta-vergul bilan to‘ldirish kerakmi? Sinf
usullarining ta'riflari?
8. Hech qanday parametrlarni qabul qilmaydigan va void tipidagi
qiymatni qaytaradigan Cat sinfining meow a'zosi funksiyasining
sarlavhasi qanday ko'rinishga ega bo'lar edi?
9. Sinfni ishga tushirish uchun qanday funksiya chaqiriladi?
10. Bunday a'zo o'zgaruvchilar bilan ishchi (xodimlar) deb nomlangan
sinfni e'lon qiladigan dasturni yozing: age (yosh), years0fService (ish
staji) va ish haqi (ish haqi).
11. A'zo ma'lumotlarini yopiq qilish va barcha a'zo ma'lumotlarni o'qish
va o'rnatish uchun ochiq kirish usullarini ta'minlash uchun Employee
sinfini qayta yozing.
12. Ikkita Employee sinf obyektlarini yaratadigan Employee sinfidan
foydalanib dastur yozing; age, Years0fService va Salary a'zo
ma'lumotlarini o'rnatadi va keyin ularning qiymatlarini chiqaradi.
13. 12-mashqdan olingan dasturga asoslanib, xodim javobni 1000
dollarga yaxlitlash orqali qancha ming dollar ishlab topishini
bildiruvchi employee sinf usulini yarating.
14. Xodimni "yaratish" jarayonida age, YearsOfService va Salary
a'zolari ma'lumotlarini ishga tushirish uchun xodimlar sinfini
o'zgartiring.
15. Keyingi e'londa nima noto'g'ri?
class Square
{
public:
int Side;
}
220
17-MAVZU. C++ DA MODIFIKATOR BILAN ISHLASH
Public modifikatori
Private modifikatori
Protected modifikatori
Inkapsulyatsiya
Do’st sinflari va funksiyalari
221
Listing 17.2. Modifikatorlar bilan ishlash
#include <iostream>
#include <string>
using namespace std;
class Person
{
public:
Person(string n, int a)
{
name = n; age = a;
}
void setAge(int a)
{
if (a > 0 && a < 100) age = a;
}
string getName()
{
return name;
}
int getAge()
{
return age;
}
private:
string name;
int age;
};
int main()
{
Person tom("Tom", 22);
// string personName = tom.name; // xato-name
o‘zgaruvchisi yopiq
cout << "Name: " << tom.getName() << "\tAge: " <<
tom.getAge() << endl;
tom.setAge(31);
cout << "Name: " << tom.getName() << "\tAge: " <<
tom.getAge() << endl;
tom.setAge(291);
cout << "Name: " << tom.getName() << "\tAge: " <<
tom.getAge() << endl;
return 0;
}
Endi Person sinfidagi name va age o'zgaruvchilari yopiq, shuning
uchun biz ularga to'g'ridan-to'g'ri murojaat qila olmaymiz. Biz ularga
faqat sinf ichida murojaat qilishimiz mumkin.
222
Shunday bo'lsada, tashqi tomondan name va age
o'zgaruvchilarining qiymatlarini olish uchun getAge va getName
qo'shimcha funksiyalari aniqlanadi.
Name o'zgaruvchisining qiymatini to'g'ridan - to'g'ri faqat
konstruktor orqali, age o'zgaruvchisining qiymatini esa konstruktor
yoki setAge funksiyasi orqali o'rnatish mumkin.
Shunday qilib, sinf holati tashqi tomondan yashiringan, unga faqat
sinf interfeysi taqdim etadigan qo'shimcha funksiyalar orqali kirish
mumkin.
Shuni ham ta'kidlash joizki, agar sinfda kirish spetsifikatori
bo'lmasa yoki ba'zi sinf a'zolari uchun aniqlanmagan bo'lsa, u holda
private kirish spetsifikatori sukut bo'yicha ishlatiladi:
Listing 17.3. Person sinfi
1 class Person{
2 string name;
3 int age;
4 public:
5 Person(string n, int a)
6 {name = n; age = a;}
7 void move()
8 {cout << name << " is moving" << endl;}
9 void setAge(int a)
10 { if (a > 0 && a < 100) age = a; }
11 string getName()
12 { return name;}
13 int getAge()
14 { return age;}};
Name va age o'zgaruvchilari uchun bu yerda kirish spetsifikatori
aniqlanmagan, shuning uchun ular sukut bo'yicha
ga ega.
Kirish turi Qiymati
223
ular ma'lum bir sinfning olingan sinflari tomonidan
ishlatilishi mumkin.
224
Albatta, itsPart ni ochiq yoki hech bo'lmaganda himoyalangan a'zo
o'zgaruvchisi deb e'lon qilish mumkin, ammo bu sinflardan foydalanish
g'oyasiga zid bo'lgan yo'ldan uzoq. Itspart ko'rsatgichi PartNode
sinfining o'ziga xos a'zosi bo'lganligi sababli, uni tashqi sinflarga kirish
imkoni bo'lmasligi kerak.
Ammo, agar siz boshqa sinfga ma'lumot yoki yopiq usullarni
taqdim qilmoqchi bo'lsangiz, bu sinfni do'st deb e'lon qilish kerak. Bu
sizning sinf interfeysingizni do'st sinfining imkoniyatlari bilan
kengaytiradi.
Shuni ta'kidlash kerakki, sinfning do'stligi boshqa sinflarga
o'tkazilmaydi. Boshqacha qilib aytganda, Agar siz mening do'stim
bo'lsangiz va Vanya sizning do'stingiz bo'lsa, bu Vanya ham mening
do'stim degani emas.
Sinflarning do'stligi bir tomonlama. Bir sinfni boshqa sinfning
do'sti deb e'lon qilish, ikkinchisini birinchisining do'stiga
aylantirmaydi. Agar xohlasangiz, sirlaringizni men bilan baham
ko'rishingiz mumkin, ammo bu sizga sirlarimni aytib berishim kerak
degani emas.
Boshlang'ich C++ dasturchilaridan do'stlar sinflarini e'lon qilish
obyektga yo'naltirilgan dasturlash asosidagi inkapsulyatsiya prinsipiga
zid ekanligini tez-tez eshitishingiz mumkin. Rostini aytsam, bu juda
keng tarqalgan be’manilik. Do'st-sinf prototipi shunchaki boshqa sinf
interfeysini kengaytiradi.
DO'STONA SINF
Ikkinchi sinf e'lonidagi kalit so'zidan foydalanib, bitta sinfni
boshqa birovning do'sti deb e'lon qilish birinchi sinfga ikkinchi sinf
a'zolariga kirish huquqini beradi.
Listing 17.6.
class PartNode()
public:
friend class PartsList;
DO’ST FUNKSIYALARI
Ba'zan butun sinfga emas, balki faqat bitta yoki bir nechta a'zo
funksiyalarga ruxsat berish kerak bo'ladi. Bu do'stlar tomonidan boshqa
sinf a'zolari funksiyalarini e'lon qilish orqali amalga oshiriladi. Bundan
tashqari, butun sinfni do'st deb e'lon qilish shart emas. Aslida, har
qanday funksiya boshqa sinfning a'zosi yoki yo'qligidan qat'i nazar,
do'st deb e'lon qilinishi mumkin.
225
C va C++ satrlari oxirgi belgisi nol bilan tugaydigan belgilar
massividir. Bunday satrga misol:
myString [] = "Salom dunyo".
Ammo String sinfida amalga oshirib bo'lmaydigan narsa bu sinf
obyektini belgilar qatori bilan qo'shish natijasida yangi qatorni hosil
qilish:
char cString[] = { "Hello"} ;
String string(" World");
String string = cString + sstring; // xato!
Satrlarni qo‘shimcha yuklangan operator funksiyasi bilan ishlatib
bo'lmaydi. Qo‘shimcha yuklangan operator funksiyasini belgilar
qatoriga chaqirish mumkin emasligi sababli, ushbu urinish
kompilyatsiya xatosiga olib keladi.
Ushbu muammoni operator + ni ikkita string obyektini
jamlaydigan tarzda yuklaydigan string sinfidagi do'st funksiyasini e'lon
qilish orqali hal qilish mumkin. Tegishli string sinf konstruktori
satrlarni string obyektlariga o'zgartiradi, shundan so'ng operator + do'st
funksiyasi chaqiriladi, u ikkita obyektni birlashtiradi.
DO'STLAR FUNKSIYALARI
Funksiyani sinf do'sti sifatida e'lon qilish uchun do'st kalit so'zidan
keyin funksiya prototipi ishlatiladi. Bu funksiyani ta'minlamaydi. Bu
ko'rsatgichga kirish, lekin barcha yopiq va himoyalangan ma'lumotlar
va a'zo funksiyalarga kirishni ta'minlaydi.
Listing 17.7.
class PartNode
{
friend void PartsList::Insert(Part +);
friend int SomeFunction();
};
CHIQARISH OPERATORINING QO‘SHIMCHA
YUKLANISHI
Endi bizning String sinfimizni cout obyektidan foydalanib, asosiy
tipdagi ma'lumotlarni chiqarishda bo'lgani kabi ma'lumotlarni chiqarish
uchun imkoniyat bilan ta'minlash vaqti keldi. Hozirgacha a'zo
o'zgaruvchining qiymatini chiqarish uchun quyidagi ifodadan
foydalanish kerak edi:
cout << theString.GetString();
yoki
cout << theString;
226
Buning uchun operator funksiyasini qo‘shimcha yuklash kerak.
Ma'lumotlarni chiqarish uchun iostream operatorlaridan foydalanish
mumkin.
227
18-MAVZU. STATIK BERILGANLAR, STATIK SINFLAR
Statik a'zo o'zgaruvchilar va a'zo funksiyalar
Statik a'zo o'zgaruvchilar va a'zo funksiyalardan foydalanish
Funksiyalar va a'zo funksiyalarga ko'rsatgichlarni yaratish va
qo'llash
Funksiya ko'rsatgichlari qatori bilan ishlash
C++ dasturlash tili ko'lamni cheklash va o'zgaruvchilar va
ko'rsatgichlardan foydalanishning bir necha usullarini taklif etadi.
Oldingi boblarda siz butun dasturda ishlatiladigan global
o'zgaruvchilarni va alohida funksiyalarda ishlatiladigan lokal
o'zgaruvchilarni yaratishni o'rgandingiz. Siz sinf o'zgaruvchilari va a'zo
o'zgaruvchilarga ko'rsatgichlar nima ekanligini bilib oldingiz.
STATIK A'ZO O'ZGARUVCHILAR
Hozirgacha siz har qanday obyekt ma'lumotlari ishlatiladigan
obyektga xos va bir nechta sinf obyektlari tomonidan birgalikda
qo'llanilmasligi mumkinligiga ishongansiz. Boshqacha qilib aytganda,
agar beshta mushuk obyekti yaratilgan bo'lsa, unda ularning har biri o'z
hayoti, hajmi va boshqalar bilan ajralib turadi.
Biroq, ba'zida dastur tomonidan ma'lumotlarning to'planishini
nazorat qilish kerak bo'ladi. Ma'lum bir sinfdagi jami qancha obyektlar
yaratilganligi va hozirda qancha obyektlar mavjudligi haqida ma'lumot
talab qilinishi mumkin.
Statik a'zo o'zgaruvchilar sinfning barcha obyektlari tomonidan
taqsimlanadi. Ular dasturning barcha qismlari uchun mavjud bo'lgan
global ma'lumotlar va odatda faqat bitta obyekt uchun mavjud bo'lgan
a'zolar ma'lumotlari o'rtasidagi "oltin markaz" ga o'xshaydi.
Statik a'zolar obyektga emas, balki sinfga tegishli deb taxmin qilish
mumkin. Agar oddiy a'zolarning ma'lumotlari bitta obyekt uchun
mavjud bo'lsa, unda statik atamalar butun sinf tomonidan ishlatilishi
mumkin. 18.1-Listing howmanycats statik a'zosi bo'lgan Cat obyektini
e'lon qiladi. Ushbu o'zgaruvchi konstruktor chaqirilganda statik
HowManyCats o'zgaruvchisi ko'payishi yoki destruktor chaqirilganda
manfiy o'sish bilan amalga oshiriladigan yaratilgan Cat obyektlari
sonini hisobga oladi.
Listing 18.1. Statik a'zo o'zgaruvchilar
1 #include <iostream>
2 using namespace std;
3 class Cat
228
4{
5 public:
6 Cat(int age):itsAge(age) {HowManyCats++; }
7 virtual ~Cat() { HowManyCats--; }
8 virtual int GetAge() { return itsAge; }
9 virtual void SetAge(int age) { itsAge = age;}
10 static int HowManyCats;
11 private:
12 int itsAge;
13 };
14 int Cat::HowManyCats = 0;
15 int main(){
16 const int MaxCats = 5; int i;
17 Cat *CatHouse[MaxCats];
18 for (i = 0; i<MaxCats; i++)
19 CatHouse[i] = new Cat(i);
20 for (i = 0; i<MaxCats; i++)
21 {cout << "There are ";
22 cout << Cat:: HowManyCats;
23 cout << " cats left!\n";
24 cout<<"Deleting the one which is ";
25 cout << CatHouse[i]->GetAge();
26 cout << " years old\n";
27 delete CatHouse[i];
28 CatHouse[i] = 0;}
29 return 0;}
Natija:
There are 5 cats left!
Deleting the one which is 0 years old
There are 4 cats left!
Deleting the one which is 1 years old
There are 3 cats left!
Deleting the one which is 2 years old
Listing 18.2. Obyektlardan foydalanmasdan statik a'zolarga kirish
#include<iostream>
using namespace std;
class Cat{
public:
Cat(int age):itsAge(age){ HowManyCats++; }
virtual ~Cat() { HowManyCats--; }
virtual int GetAge() { return itsAge; }
virtual void SetAge(int age) {itsAge = age;}
static int HowManyCats;
private:
int itsAge;
};
int Cat::HowManyCats = 0;
void TelepathicFunction();
int main()
229
{
const int MaxCats = 5; int i;
Cat * CatHouse[MaxCats];
for (i = 0; i<MaxCats; i++)
CatHouse[i] = new Cat(i);
TelepathicFunction();
for ( i = 0; i<MaxCats; i++)
{delete CatHouse[i];
TelepathicFunction();}
return 0;}
void TelepathicFunction()
{cout << "There are ";
cout << Cat::HowManyCats << " cats alive!\n";}
Natija:
There are 1 cats alive!
There are 2 cats alive!
There are 3 cats alive!
There are 4 cats alive!
There are 5 cats alive!
There are 4 cats alive!
There are 3 cats alive!
There are 2 cats alive!
There are 1 cats alive!
There are 0 cats alive!
Listing 18.3. statik a'zoga kirish
1 #include <iostream>
2 using namespace std;
3 class Cat
4{
5 public:
6 Cat(int age):itsAge(age){ HowManyCats++; }
7 virtual ~Cat() { HowManyCats--; }
8 virtual int GetAge() { return itsAge;}
9 virtual void SetAge(int age) { itsAge = age; }
10 virtual int GetHowMany() { return HowManyCats; }
11 private:
12 int itsAge;
13 static int HowManyCats;
14 };
15 int Cat:: HowManyCats = 0;
16 int main()
17 {
18 const int MaxCats = 5; int i;
19 Cat *CatHouse[MaxCats];
20 for (i = 0; i<MaxCats; i++)
21 CatHouse[i] = new Cat(i);
22 for (i = 0; i<MaxCats; i++)
23 {cout << "There are ";
24 cout << CatHouse[i]->GetHowMany();
25 cout << " cats left!\n";
230
26 cout << "Deleting the one which is ";
27 cout << CatHouse[i]->GetAge()+2;
28 cout << " years old\n";
29 delete CatHouse[i];
30 CatHouse[i] = 0;
31 }
32 return 0;
33 }
Tavsiya etiladi!
Bir nechta sinf obyektlari tomonidan ma'lumotlarni
almashish uchun statik a'zo o'zgaruvchilarni qo'llang.
Statik a'zo o'zgaruvchilarga kirishni shaxsiy yoki
himoyalangan deb e'lon qilish orqali cheklang.
Tavsiya etilmaydi!
Bitta obyekt ma'lumotlarini saqlash uchun statik a'zo
o'zgaruvchilardan foydalanmang. Ushbu o'zgaruvchilar obyektlar
o'rtasida ma'lumot almashish uchun mo'ljallangan.
STATIK A'ZO FUNKSIYALARI
Statik a'zo funksiyalari statik a'zo o'zgaruvchilarga o'xshaydi: ular
bitta obyektga tegishli emas, balki butun sinf doirasiga kiradi. Shuning
uchun ularni 18.4-Listingda ko'rsatilgandek, bitta sinf obyekti
yaratilmagan hollarda ham chaqirish mumkin.
Listing 18.4. Statik a'zo funksiyalari
1 #include <iostream>
2 using namespace std;
3 class Cat
4{
5 public:
6 Cat(int age):itsAge(age){ HowManyCats++; }
7 virtual ~Cat() { HowManyCats--; }
8 virtual int GetAge() { return itsAge; }
9 virtual void SetAge(int age) { itsAge = age; }
10 static int GetHowMany() { return HowManyCats; }
11 private:
12 int itsAge;
13 static int HowManyCats;
14 };
15 int Cat::HowManyCats = 0;
16 void TelepathicFunction();
17 int main()
18 {
19 const int MaxCats = 5;
20 Cat * CatHouse[MaxCats]; int i;
21 for (i = 0; i<MaxCats; i++)
22 {CatHouse[i] = new Cat(i);
231
23 TelepathicFunction();}
24 for ( i = 0; i<MaxCats; i++)
25 {delete CatHouse[i];
26 TelepathicFunction();}
27 return 0;}
28 void TelepathicFunction()
29 {cout << "There are " << Cat::GetHowMany() << " cats
alive!\n";}
Natija:
There are 1 cats alive!
There are 2 cats alive!
There are 3 cats alive!
There are 4 cats alive!
There are 5 cats alive!
There are 4 cats alive!
There are 3 cats alive!
There are 2 cats alive!
There are 1 cats alive!
There are 0 cats alive!
Statik a'zo funksiyalari bu ko'rsatgichni o'z ichiga olmaydi.
Shuning uchun ular const spetsifikatori bilan e'lon qilinishi mumkin
emas. Bundan tashqari, a'zo funksiyalar ushbu ko'rsatgich yordamida
a'zo o'zgaruvchilarga kirish huquqiga ega bo'lganligi sababli, statik a'zo
funksiyalar odatdagi statik bo'lmagan a'zo o'zgaruvchilardan foydalana
olmaydi.
STATIK FUNKSIYALAR
Statik a'zo funksiyalarga ularni sinf obyektlaridan oddiy a'zo
funksiyalari sifatida chaqirish yoki ularni obyektlarsiz chaqirish orqali
kirish mumkin, bu holda sinf nomini aniq ko'rsatib beradi.
Listing 18.5
class Cat
{public:
static int GetHowMany() { return HowManyCats; }
private:
static int HowManyCats;};
int Cat: : HowManyCats = 0;
int main()
{int howMany;
Cat theCat// obyektni aniqlash
howMany-theCat GetHowMany (); / / obyekt orqali kirish
howMany = Cat:: GetHowMany (): - / / obyektsiz kirish}
FUNKSIYA KO'RSATKICHLARI
Massiv nomi o‘zgarmas ravishda uning birinchi elementini
ko'rsatganidek, funksiya nomi ham funksiyaning o'ziga ishora qiladi.
Siz funksiya ko'rsatgichi o'zgaruvchisini e'lon qilishingiz va
232
keyinchalik ushbu ko'rsatgich yordamida uni chaqirishingiz mumkin.
Ushbu imkoniyat juda foydali bo‘lishi mumkin, chunki u klaviaturadan
kiritilgan foydalanuvchi buyruqlari orqali funksiyalar chaqiriladigan
dasturlarni yaratishga imkon beradi.
Funksiya ko'rsatgichini aniqlash uchun yagona muhim tafsilot - bu
ko'rsatgich murojaat qiladigan obyekt turini bilishdir. Int tipidagi
ko'rsatgich, albatta, butun son o'zgaruvchisi bilan bog'liq. Xuddi
shunday, funksiya ko'rsatgichi faqat berilgan imzo va qaytish turiga ega
funksiyalarni chaqirishi mumkin.
E'londa
long (+ funcPtr) (int);
funcptr funksiyasi uchun ko'rsatgich yaratiladi (ko'rsatgich nomidan
oldin * belgisiga e'tibor bering), u butun sonli parametrni oladi va Long
turidagi qiymatni qaytaradi. (* FuncPtr) atrofidagi qavslar majburiydir,
chunki (int) atrofidagi qavslar bilvosita (*) operatoridan ustun turadi.
Agar siz birinchi qavslarni olib tashlasangiz, unda bu ifoda butun sonli
parametrni qabul qiladigan va ko'rsatgichni Long turidagi qiymatga
qaytaradigan funcPtr funksiyasini e'lon qiladi. (Esda tutingki, C++ dagi
barcha bo‘sh joylar e'tiborga olinmaydi.)
Quyidagi ikkita misolni ko'rib chiqing:
long Function (int);
long (* funcPtr) (int);
Birinchi qatorda Function() - bu butun sonli parametrni qabul
qiladigan va ko'rsatgichni Long turidagi o'zgaruvchiga qaytaradigan
funksiya. Ikkinchi misolda funcPtr butun sonli parametrni qabul
qiladigan va 1ong turidagi o'zgaruvchini qaytaradigan funksiyaga
ko'rsatgichdir.
Funksiya uchun ko'rsatgichni e'lon qilish har doim qaytariladigan
o'zgaruvchining turini va agar mavjud bo'lsa, qavs ichida rasmiy
parametr turlarining Listingini o'z ichiga oladi.
FUNKSIYAGA KO'RSATGICH
Ko'rsatgich orqali funksiyaga kirish, u ko'rsatadigan funksiyaning
odatiy chaqiruvi bilan bir xil tarzda yoziladi. Faqat funksiya nomi
o'rniga ushbu funksiyaga ko'rsatgich nomi ishlatiladi.
Funksiyaga ko'rsatgichni ma'lum bir funksiya bilan bog'lash uchun
unga hech qanday qavssiz funksiya nomini berish kifoya. Funksiya
nomi, siz allaqachon bilganingizdek, funksiyaning o'ziga o‘zgarmas
ko'rsatgichdir. Shuning uchun funksiyaga ko'rsatgich uning nomi bilan
233
bir xil ishlatiladi. Funksiyani ko'rsatgich orqali chaqirganda, joriy
funksiya uchun o'rnatilgan barcha parametrlarni o'rnatishingiz kerak.
Listing 18.6
long(+pFuncOne) (int, int);
long SomeFunction (int, int):
pFuncOne - SomeFunction;
pFuncOne (5,7);
Listing 18.7. Funksiya ko'rsatgichlaridan foydalanmaslik
1 #include <iostream>
2 using namespace std;
3 void Square (int&,int&);
4 void Cube (int&, int&);
5 void Swap (int&, int &);
6 void Getvals(int&, int&);
7 void PrintVals(int, int);
8 int main(){
9 bool fQuit = false;
10 int valOne=1, valTwo=2;
11 int choice;
12 while (fQuit == false)
13 {cout << "(0)Quit (1)Change Values (2)Square (3)Cube (4)Swap:";
14 cin >> choice;
15 switch (choice){
16 case 1:
17 PrintVals(valOne, valTwo);
18 Getvals(valOne, valTwo);
19 PrintVals(valOne, valTwo); break;
20 case 2:
21 PrintVals(valOne, valTwo);
22 Square(valOne, valTwo);
23 PrintVals(valOne, valTwo); break;
24 case 3:
25 PrintVals(valOne, valTwo);
26 Cube(valOne, valTwo);
27 PrintVals(valOne, valTwo); break;
28 case 4:
29 PrintVals(valOne, valTwo);
30 Swap(valOne, valTwo);
31 PrintVals(valOne, valTwo); break;
32 default: fQuit = true; break;}
33 if (fQuit) break;}
34 return 0;}
35 void PrintVals(int x, int y)
36 {cout << "x: " << x << " y: " << y << endl;}
37 void Square (int& rX, int& rY)
38 {rX *= rX; rY *= rY;}
39 void Cube (int& rX, int& rY)
40 {int tmp;
41 tmp = rX; rX *= rX; rX = rX * tmp;
234
42 tmp = rY; rY*=rY; rY = rY * tmp;}
43 void Swap(int& rX, int& rY)
44 {int temp;
45 temp = rX; rX = rY; rY = temp;}
46 void Getvals(int& rValOne, int& rValTwo)
47 {cout << "New value for ValOne: "; cin >> rValOne;
48 cout << "New value for ValTwo: "; cin >> rValTwo;}
Natija:
(0)Quit (1)Change Values (2)Square (3)Cube (4)Swap: 1
x: 1 y: 2
New value for Val0ne: 2
New value for ValTwo: 3
x: 2 y: 3
(0)Quit (1)Change Values (2)Square (3)Cube (4)Swap: 3
x: 2 y: 3
?: 8 y: 27
(0)Quit (1)Change Values (2)Square (3)Cube (4)Swap: 2
x: 8 y: 27
?: 64 y: 729
(0)Quit (1)Change Values (2)Square (3)Cube (4)Swap: 4
x: 64 y: 729
? : 729 y: 64
(0)Quit (1)Change Values (2)Square (3)Cube (4)Swap: 0
FUNKSIYANI CHAQIRISH UCHUN SO'RALGAN
VARIANT
Funksiya uchun ko'rsatgichning nomi funksiyaning o'zi nomini
umuman takrorlamasligi kerak, garchi siz buni qilishga haqlisiz.
Masalan, pFunc butun son qiymatini qabul qiladigan va Long turidagi
o'zgaruvchini qaytaradigan funksiyaga ko'rsatgich bo'lsin va bu
funksiyaning nomi pFunc bo'lsin. Sizda ikkita murojaatdan birini
chaqirish imkoniyati mavjud:
pFunc(x);
yoki
(*pFunc) (x);
Ikkala ifoda ham bir xil natijaga olib keladi. Birinchi ifoda qisqaroq
bo‘lsada, ikkinchisi dasturga ko'proq moslashuvchanlikni beradi.
Xuddi shu funksiyaning takroriy murojaatlari orqali kod hajmini
oshirish dasturning o'qilishini yomonlashtiradi. Ushbu parametr
funksiyalar uchun ko'rsatgichlardan foydalanish samaradorligini
ko'rsatish uchun maxsus berilgan. Haqiqiy sharoitda funksiya
ko'rsatgichlarini qo'llashning afzalliklari yanada ravshanroq, chunki
ular kodning takrorlanishini yo'q qilishga imkon beradi va dasturni
yanada aniqroq qiladi. Masalan, funksiya ko'rsatgichlari mavjud
235
vaziyatga qarab bitta qatorga to'planishi va undan funksiyalarni
chaqirishi mumkin.
FUNKSIYA KO'RSATGICHLARI MASSIVLARI
Butun son ko'rsatgichlari qatorini e'lon qilishga o'xshab, ma'lum bir
turdagi qiymatlarni qaytaradigan ma'lum bir imzoga ega bo'lgan
funksiyalar uchun ko'rsatgichlar qatorini e'lon qilish mumkin. Listing
18.8-bu listing 18.7 dasturining yana bir variantidir, unda
funksiyalarning barcha ko'rsatkichlari bir qatorga birlashtirilgan.
Listing. 18.8. Funktsiya ko'rsatgichlari qatoridan foydalanish
1 #include <iostream>
2 using namespace std;
3 void Square (int&, int&);
4 void Cube (int&, int&);
5 void Swap (int&, int &);
6 void GetVals(int&, int&);
7 void PrintVals(int, int);
8 int main()
9 {int valOne=1, valTwo=2;
10 int choice, i;
11 const int MaxArray = 5;
12 void (*pFuncArray[MaxArray])(int&, int&);
13 for (i=0; i<MaxArray; i++)
14 {cout << "(1)Change Values (2)Square (3)Cube (4)Swap: ";
15 cin >> choice;
16 switch (choice)
17 {case 1:pFuncArray[i] = GetVals; break;
18 case 2:pFuncArray[i] = Square; break;
19 case 3:pFuncArray[i] = Cube; break;
20 case 4:pFuncArray[i] = Swap; break;
21 default:pFuncArray[i] = 0;}}
22 for (i=0; i<MaxArray; i++)
23 {if ( pFuncArray[i] == 0 ) continue;
24 pFuncArray[i](valOne, valTwo);
25 PrintVals(valOne, valTwo);}
26 return 0;}
27 void PrintVals(int x, int y)
28 {cout << "x: " << x << " y: " << y << endl;}
29 void Square (int & rX, int & rY)
30 {rX *= rX; rY *= rY;}
31 void Cube (int & rX, int & rY)
32 {int tmp;
33 tmp = rX; rX *= rX; rX = rX * tmp;
34 tmp = rY; rY *= rY; rY = rY * tmp;}
35 void Swap(int & rX, int & rY)
36 {int temp;
37 temp = rX; rX = rY; rY = temp;}
38 void GetVals (int & rValOne, int & rValTwo)
236
39 {cout << "New value for ValOne: "; cin >> rValOne;
40 cout << "New value for ValTwo: "; cin >> rValTwo;}
Natija:
(1)Change Values (2)Square (3)Cube (4)Swap: 1
(1)Change Values (2)Square (3)Cube (4)Swap: 2
(1)Change Values (2)Square (3)Cube (4)Swap: 3
(1)Change Values (2)Square (3)Cube (4)Swap: 4
(1)Change Values (2)Square (3)Cube (4)Swap: 2
New Value for Val0ne: 2
New Value for ValTwo: 3
x: 2 y: 3
x: 4 y: 9
x: 64 y: 729
x: 729 y: 64
x: 531441 y: 4096
FUNKSIYA KO'RSATGICHLARINI BOSHQA
FUNKSIYALARGA O'TKAZISH
Funksiya ko'rsatgichlari (yoki ko'rsatgich massivlari) kerakli
funksiya ko'rsatgichi yordamida ularga murojaat qilish uchun boshqa
funksiyalarga o'tkazilishi mumkin. 18.7 Listingi tanlangan funksiyaga
ko'rsatgichni boshqa funksiyaga o'tkazish orqali yaxshilanishi mumkin
(main () dan tashqari), bu asl qiymatlarni chop etish uchun chiqaradi,
funksiyani chaqiradi va o'zgartirilgan qiymatlarni qayta chop etadi.
Void (+)(int&, int&) loyihalashi juda katta. Uni soddalashtirish
uchun siz voidni qaytaradigan va int tipidagi qiymatlarga ikkita
havolani qabul qiladigan funksiyalarga ko'rsatgichlarning yangi turini
(uni VPF deb ataymiz) e'lon qilish orqali typedef kalit so'zidan
foydalanishingiz mumkin.
Hozirgacha yaratilgan barcha funksiyalar ko'rsatkichlari biror bir
sinfga tegishli bo'lmagan umumiy funksiyalar uchun ishlatilgan. Shu
bilan birga, sinflarga (usullarga) a'zo bo'lgan funksiyalar uchun
ko'rsatkichlar yaratishga ruxsat beriladi.
Bunday ko'rsatgichni yaratish uchun oddiy funksiyaga ko'rsatgich
bilan bir xil sintaksis ishlatiladi, lekin sinf nomi va qamrov doirasi
operatori (::) qo'shiladi.
Shunday qilib, pFunc ko'rsatgichini ikkita butun parametrini qabul
qiladigan va voidni qaytaradigan Shape sinfining a'zo funksiyalariga
e'lon qilish quyidagicha:
void (Shape::*pFunc) (int,int);
A'zo funksiyalari ko'rsatkichlari ilgari ko'rib chiqilgan oddiy
funksiyalar ko'rsatkichlari bilan bir xil tarzda qo'llaniladi. Faqatgina
237
farq shundaki, funksiyani chaqirish uchun funksiyalar chaqiriladigan
tegishli sinf obyekti bo‘lishi kerak. Listing 18.11 sinf usuli uchun
ko'rsatgichdan foydalanishni ko'rsatadi.
A'ZO FUNKSIYALARI UCHUN KO'RSATGICH
MASSIVLARI
Oddiy funksiyalar belgilariga o'xshab, a'zo funksiyalar
ko'rsatkichlari massivda saqlanishi mumkin. Bunday massivni ishga
tushirish uchun siz turli xil a'zo funksiyalarning manzillaridan
foydalanishingiz mumkin.
Tavsiya etiladi!
Sinf obyektlarida usullarni chaqirish uchun a'zo
funksiyalaridagi ko'rsatgichlardan foydalaning.
A'zo funksiyasiga ko'rsatgichni e'lon qilishni osonlashtirish
uchun typedef-dan foydalaning.
Tavsiya etilmaydi!
Agar siz ularsiz qila olsangiz, a'zo funksiyalari uchun belgilar
yaratishni suiste'mol qilmang.
Nazorat savollari va topshiriqlar:
1. Statik a'zo o'zgaruvchilar yopiq bo‘lishi mumkinmi?
2. Statik a'zo o'zgaruvchini e'lon qiling.
3. Statik funksiyani e'lon qiling.
4. Int tipidagi parametrni qabul qiladigan va Long turidagi qiymatni
qaytaradigan funksiyaga ko'rsatgichni e'lon qiling.
5. 4-topshiriqda yaratilgan ko'rsatgichni Car sinfining a'zo funksiyasi
uchun ko'rsatgichga o'zgartiring.
6. 5-topshiriqda yaratilgan o'nta ko'rsatgich qatorini e'lon qiling.
7. Bitta oddiy a'zo o'zgaruvchisi va bitta statik a'zo o'zgaruvchisi
bo'lgan sinfni e'lon qiladigan qisqa dastur yozing. A'zo o'zgaruvchini
ishga tushiradigan va statik a'zo o'zgaruvchini ko'paytiradigan
konstruktor yarating. Keyin statik o'zgaruvchining qiymatini bittaga
kamaytiradigan destruktorni tavsiflang.
8. 7-mashq dasturini statik a'zo o'zgaruvchiga statik a'zo funksiyasi
orqali kirish uchun o'zgartiring. Statik atama o'zgaruvchisini yopiq
qiling.
9. Statik bo'lmagan a'zo o'zgaruvchining qiymatiga kirish uchun 9-
mashq dasturida a'zo funksiyasi uchun ko'rsatgich yarating va undan
ushbu qiymatlarni chop etish uchun foydalaning.
238
19-MAVZU. OPERATORLARNI QAYTA ANIQLASH.
A'zo funksiyalarini qo‘shimcha yuklash
Operatorlarni qo‘shimcha yuklash
O'zgaruvchilar uchun dinamik xotira ajratish bilan sinflarni
saqlash uchun funksiyalarni yaratish
239
Natija:
DrawShape():
******************************
******************************
******************************
******************************
******************************
DrawShape(40,2):
****************************************
****************************************
STANDART QIYMATLARDAN FOYDALANISH
Sinfning a'zo funksiyalari, odatdagi funksiyalar kabi, sukut
bo'yicha berilgan qiymatlardan foydalanishi mumkin. Standart
argumentlar bilan a'zo funksiyalarni e'lon qilishda, Listing 19.2 da
ko'rsatilgandek, sizga tanish bo'lgan sintaksis ishlatiladi.
19.1 va 19.2 Listinglari bir xil vazifalarni bajaradi, ammo Listing
19.1 dagi qo‘shimcha yuklangan funksiyalardan foydalanish dasturni
yanada o'qilishini soddalashtiradi.
Listing 19.2.
#include <iostream>
using namespace std;
class Rectangle
{ public:
Rectangle(int width, int height);
~Rectangle(){}
void DrawShape
(int aWidth, int aHeight, bool UseCurrentVals = false) const;
private:
int itsWidth;
int itsHeight;};
Rectangle::Rectangle(int width, int height):
itsWidth(width),
itsHeight(height){}
void Rectangle::DrawShape(
int width,
int height,
bool UseCurrentValue )const{
int printWidth;
int printHeight;
if (UseCurrentValue == true)
{printWidth = itsWidth;
printHeight = itsHeight;}
else
{printWidth = width;
printHeight = height;}
for (int i = 0; i<printHeight; i++){
for (int j = 0; j< printWidth; j++)
240
{cout <<"*";}
cout << "\n";}}
int main(){
Rectangle theRect(30,5);
cout << "DrawShape(0,0, true)...\n";
theRect.DrawShape(0,0, true);
cout <<"DrawShape(40,2)...\n";
theRect.DrawShape(40,2);
return 0;}
Natija:
DrawShape():
******************************
******************************
******************************
******************************
******************************
DrawShape(40,2):
****************************************
****************************************
Dasturda qay biri ishlatishini qanday hal qilish kerak – qo‘shimcha
yuklangan funksiyalar yoki standart qiymatlar? Quyidagi qoidalarga
e'tibor bering. Qo‘shimcha yuklangan funksiyalardan foydalanish
afzalroqdir, agar:
1) dasturda vaziyatga qarab turli xil algoritmlardan foydalanish
kerak;
2) funksiyaga uzatiladigan qiymatlar turini o'zgartirish
imkoniyatiga ega bo‘lish kerak.
KONSTRUKTOR
Agar sinf konstruktori aniq e'lon qilinmasa, standart konstruktor
ishlatilishini bilib oldingiz, u parametrlarni o'z ichiga olmaydi va
dasturda o'zini namoyon qilmaydi. Sukut bo'yicha ishlatiladigan
maxsus konstruktorni yaratish qiyin emas, u ham hech qanday
parametrlarni qabul qilmaydi, lekin sinf obyektlarini yaratishni
boshqarishga imkon beradi.
Kompilyator tomonidan taqdim etilgan konstruktor sukut bo'yicha
berilgan deb nomlanadi. Shu bilan birga, standart konstruktor
parametrlarni o'z ichiga olmaydigan har qanday boshqa sinf
konstruktori deb ham ataladi. Bu g'alati tuyulishi mumkin, ammo
vaziyatga ushbu loyihalarni amalda qo'llash nuqtai nazaridan
qarasangiz, vaziyat yanada aniqroq bo'ladi.
241
E'tibor bering, agar dasturda biror bir konstruktor yaratilgan bo'lsa,
unda kompilyator o'zining standart konstruktorini taklif qilmaydi.
Shuning uchun, agar sizga parametrlarsiz konstruktor kerak bo'lsa va
dasturda bitta konstruktor yaratilgan bo'lsa, unda standart konstruktorni
o'zingiz yaratishingiz kerak bo'ladi.
KONSTRUKTORLARNING QO‘SHIMCHA YUKLANISHI
Konstruktor obyektni yaratish uchun mo'ljallangan. Masalan,
to'rtburchaklar konstruktorining maqsadi to'rtburchaklar obyektini
yaratishdir. Konstruktorni ishga tushirishdan oldin dasturda
to'rtburchak yo'q. Faqat u uchun ajratilgan xotira maydoni mavjud.
Konstruktor tugagandan so'ng dasturda foydalanishga tayyor obyekt
paydo bo'ladi.
Konstruktorlar, boshqa barcha funksiyalar kabi, qo‘shimcha
yuklanishi mumkin. Loyihalalarning qo‘shimcha yuklanishi dasturning
samaradorligi va moslashuvchanligini oshirishning kuchli vositasidir.
Masalan, biz ko'rib chiqayotgan to'rtburchaklar obyektida ikkita
konstruktor bo‘lishi mumkin. Birinchisi to'rtburchakning kengligi va
uzunligini belgilaydi, ikkinchisi parametrlarga ega emas va
o'lchamlarni o'rnatish uchun standart qiymatlardan foydalanadi. Ushbu
g'oya Listing 19.3 da amalga oshiriladi.
Listing 19.3. Konstruktorning qo‘shimcha yuklanishi
#include <iostream>
using namespace std;
class Rectangle
{ public:
Rectangle();
Rectangle(int width, int length);
~Rectangle() {}
int GetWidth() const { return itsWidth; }
int GetLength() const { return itsLength; }
private:
int itsWidth;
int itsLength;
};
Rectangle:: Rectangle()
{itsWidth = 5;
itsLength = 10;}
Rectangle::Rectangle (int width, int length)
{itsWidth = width;
itsLength = length;}
int main(){
Rectangle Rect1;
cout << "Rect1 width: " << Rect1.GetWidth() << endl;
cout << "Rect1 length: " << Rect1.GetLength() << endl;
242
int aWidth, aLength;
cout << "Enter a width: "; cin >> aWidth;
cout << "\nEnter a length: "; cin >> aLength;
Rectangle Rect2(aWidth, aLength);
cout << "\nRect2 width: " << Rect2.GetWidth() << endl;
cout << "Rect2 length: " << Rect2.GetLength() << endl;
return 0;}
Natija:
Rect1 width: 5
Rect1 length: 10
Enter a width: 20
Enter a length: 50
Rect2 width: 20
Rect2 length: 50
OBYEKTLARNI ISHGA TUSHIRISH
Hozirgacha obyektlarning a'zo o'zgaruvchilari to'g'ridan-to'g'ri
konstruktor tanasida o'rnatildi. Konstruktorning bajarilishi ikki
bosqichda amalga oshiriladi: konstruktor tanasini ishga tushirish va
bajarish.
Ko'pgina o'zgaruvchilar ushbu bosqichlarning har birida berilishi
mumkin: boshlang'ich paytida ham, konstruktorning ish vaqtida ham.
Ammo konstruktorni ishga tushirish paytida a'zo o'zgaruvchilarni ishga
tushirish mantiqan to'g'ri va ko'pincha samaraliroq. Quyidagi misol a'zo
o'zgaruvchilarni ishga tushirishni ko'rsatadi:
CAT():// konstruktor nomi va parametrlar Listingi
itsAge(5),// Listingni ishga tushirish
itsWeigth(8)
{ } // konstruktor tanasi
Konstruktor parametrlari Listingini yopish uchun qavsdan keyin
figurali qavs qo'yiladi. Keyin a'zo o'zgaruvchilarning nomlari sanab
o'tiladi. Ushbu o'zgaruvchini ishga tushirish uchun o'zgaruvchi
nomidan so‘ng bir juft qavs ishlatiladi. Agar bir vaqtning o'zida bir
nechta o'zgaruvchilar ishga tushirilsa, ular vergul bilan ajratilishi kerak.
Listing 19.4 Listing 19.3 dan olingan o'zgaruvchan konstruktorlarning
ishga tushirilishini ko'rsatadi. Ushbu misolda o'zgaruvchilarni ishga
tushirish konstruktor tanasida ularga qiymatlarni berish o'rniga
ishlatiladi.
Listing 19.4. Dastur kodining bir qismi bilan
1 Rectangle:: Rectangle():
2 itsWidth(5),
243
3 itsLength(10)
4 {}
5 Rectangle::Rectangle (int width, int length):
6 itsWidth(width),
7 itsLength(length)
8 {}
KONSTRUKTOR-NUSXA KO'CHIRUVCHI
Konstruktor va destruktordan tashqari kompilyator sukut bo'yicha
obyektning nusxasini yaratish kerak bo'lganda chaqiriladigan nusxa
ko'chiruvchi konstruktorni ham taqdim etadi.
Obyekt funksiyaga yoki funksiyadan qaytish sifatida qiymat
sifatida uzatilganda, uning vaqtinchalik nusxasi doimo yaratiladi.
Barcha nusxa ko'chiruvchilar faqat bitta parametrni qabul qilishadi.
Ushbu havolani o‘zgarmas qilish kerak, chunki konstruktor unga
uzatiladigan obyektni o'zgartirmasligi kerak. Masalan:
CAT(const CAT & theCat);
Bunday holda, CAT konstruktori sat sinf obyektiga o‘zgarmas
havolani oladi. Nusxa ko'chirish loyihalaridan foydalanishning maqsadi
theCat obyektining nusxasini yaratishdir.
Standart kompilyator tomonidan berilgan nusxa ko'chiruvchi
parametrda ko'rsatilgan obyektdan barcha a'zo o'zgaruvchilarni yangi
obyektning a'zo o'zgaruvchilariga ko'chiradi.
Masalan, CAT sinfida theCat a'zosi o'zgaruvchisi mavjud bo'lib, u
ba'zi bir butun qiymati saqlanadigan dinamik xotira sohasidagi
katakchani ko'rsatadi. Standart nusxa ko'chiruvchi theCat
o'zgaruvchisini eski CAT sinfidan yangi CAT sinfidagi theCat
o'zgaruvchisiga ko'chiradi. Bunday holda, ikkala obyekt ham bir xil
xotira katakchasiga ishora qiladi (19.1-rasm).
244
qilsa, unda dasturiy ta'minot ustida xavf paydo bo'ladi. Ushbu muammo
19.2-rasmda keltirilgan.
245
37 frisky. SetAge(7);
38 cout << "frisky's age: " << frisky.GetAge() << endl;
39 cout << "boot's age: " << boots.GetAge() << endl;
40 return 0;}
Natija:
frisky's age: 5
Setting frisky to 6…
Creating boots from frisky
frisky's age: 6
boots' age: 6
setting frisky to 7…
frisky's age: 7
boots' age: 6
OPERATORLARNING QO‘SHIMCHA YUKLANISHI
C++ tilida int, char va boshqalarni o'z ichiga olgan bir qator
o'rnatilgan ma'lumotlar tiplari mavjud. Operatorlarni qo‘shimcha
yuklash tartibini batafsil ko'rib chiqish uchun Listing 19.6 da yangi
Counter sinfi yaratiladi.
Listing 19.6. Counter sinfi
1 #include <iostream>
2 using namespace std;
3 class Counter{
4 public:
5 Counter();
6 ~Counter(){ }
7 int GetItsVal()const { return itsVal; }
8 void SetItsVal(int x) { itsVal = x; }
9 private:
10 int itsVal;};
11 Counter::Counter():
12 itsVal(0){}
13 int main(){
14 Counter i;
15 cout << "The value of i is " << i.GetItsVal() << endl;
16 return 0;}
Natija:
The value of i is 0
Yuqorida aytib o'tilgan yangi sinf obyektidan foydalanish
cheklovlarini operatorlarni qo‘shimcha yuklash orqali bartaraf etish
mumkin. Ulardan biri funksiyani qo‘shimcha yuklash Listing 19.7 da
ko'rsatilgan.
Listing 19.7. Qo'shimcha operator sinfiga qo'shish
1 #include <iostream>
2 using namespace std;
246
3 class Counter{
4 public:
5 Counter();
6 ~Counter(){ }
7 int GetItsVal()const { return itsVal; }
8 void SetItsVal(int x) { itsVal = x;}
9 void Increment() { ++itsVal; }
10 private:
11 int itsVal;};
12 Counter::Counter():
13 itsVal(0) {}
14 int main()
15 {Counter i;
16 cout << "The value of i is " << i.GetItsVal() << endl;
17 i.Increment();
18 cout << "The value of i is " << i.GetItsVal() << endl;
19 return 0;}
Natija:
The value of i is 0
The value of i is 1
PREFIKS OPERATORLARINING QO‘SHIMCHA
YUKLANISHI
Prefiks operatorini ortiqcha yuklash uchun siz quyidagi turdagi
funksiyadan foydalanishingiz mumkin:
returnType Operator op (parametrlar)
Bunday holda, qo‘shimcha yuklangan operatordir.
void operator++ ()
Ushbu usul Listing 19.8 da ko'rsatilgan.
Listing 19.8. Preincrement operatori
1 #include <iostream>
2 using namespace std;
3 class Counter{
4 public:
5 Counter();
6 ~Counter(){}
7 int GetItsVal()const { return itsVal; }
8 void SetItsVal(int x) { itsVal = x; }
9 void Increment() { ++itsVal; }
10 void operator++ () {++itsVal; }
11 private:
12 int itsVal;};
13 Counter::Counter():
14 itsVal(0) {}
15 int main(){
16 Counter i;
17 cout << "The value of i is " << i.GetItsVal() << endl;
18 i.Increment();
247
19 cout << "The value of i is " << i.GetItsVal() << endl;
20 ++i;
21 cout << "The value of i is " << i.GetItsVal() << endl;
22 return 0;}
Natija:
The value of i is 0
The value of i is 1
The value of i is 2
Listing 19.9. Vaqtinchalik obyektning qaytishi
1 #include <iostream>
2 using namespace std;
3 class Counter
4 { public:
5 Counter();
6 ~Counter(){}
7 int GetItsVal()const { return itsVal; }
8 void SetItsVal(int x) { itsVal = x; }
9 void Increment() { ++itsVal; }
10 Counter operator++ ();
11 private:
12 int itsVal;
13 };
14 Counter::Counter():
15 itsVal(0){}
16 Counter Counter::operator++()
17 {++itsVal;
18 Counter temp;
19 temp. SetItsVal(itsVal);
20 return temp;}
21 int main()
22 {Counter i;
23 cout << "The value of i is " << i.GetItsVal() << endl;
24 i.Increment();
25 cout << "The value of i is " << i.GetItsVal() << endl;
26 ++i;
27 cout << "The value of i is " << i.GetItsVal() << endl;
28 Counter a = ++i;
29 cout << "The value of a: " << a.GetItsVal();
30 cout << " and i: " << i.GetItsVal() << endl;
31 return 0;}
Natija:
The value of i is 0
The value of i is 1
The value of i is 2
The value of a: 3 and i: 3
Agar Counter sinfida qiymatni qabul qiluvchi konstruktor bo'lsa,
unda ushbu konstruktorning parametrlari shunchaki o'sish
248
operatorining qaytish qiymatini qaytarishi mumkin. Ushbu g'oya
Listing 19.10 da amalga oshiriladi.
Listing 19.10. Mavhum vaqtinchalik obyektning qaytishi
1 #include <iostream>
2 using namespace std;
3 class Counter
4 { public:
5 Counter();
6 ~Counter(){}
7 int GetItsVal()const { return itsVal; }
8 void SetItsVal(int x) { itsVal = x; }
9 void Increment() { ++itsVal; }
10 Counter operator++ ();
11 private:
12 int itsVal;
13 };
14 Counter::Counter():
15 itsVal(0){}
16 Counter Counter::operator++()
17 {++itsVal;
18 Counter temp;
19 temp. SetItsVal(itsVal);
20 return temp;}
21 int main()
22 {Counter i;
23 cout << "The value of i is " << i.GetItsVal() << endl;
24 i.Increment();
25 cout << "The value of i is " << i.GetItsVal() << endl;
26 ++i;
27 cout << "The value of i is " << i.GetItsVal() << endl;
28 Counter a = ++i;
29 cout << "The value of a: " << a.GetItsVal();
30 cout << " and i: " << i.GetItsVal() << endl;
31 return 0;}
Natija:
The value of i is 0
The value of i is 1
The value of i is 2
The value of a: 3 and i: 3
249
PREINCREMENT VA POSTINCREMENT O'RTASIDAGI
FARQLAR
Postincrement operatorini ortiqcha yuklashni boshlashdan oldin,
uning preincrement operatoridan qanday farq qilishini aniq
tushunishingiz kerak.
Xuddi shunday, bizning misolimizda preincrement operatori
qiymatni oshiradi, shundan so'ng u obyektni qaytaradi va postincrement
operatori obyektni asl qiymati bilan qaytaradi.
Keling, barchasini yana takrorlaymiz. Quyidagi ifodaga qarang:
a = x++;
Agar dastlab x o'zgaruvchisi 5 ga teng bo'lsa, unda a
o'zgaruvchisining ushbu ifodasida 5 qiymati beriladi, ammo x
o'zgaruvchisi 6 ga teng bo'ladi. Agar x shunchaki o'zgaruvchi emas,
balki obyekt bo'lsa, unda uning postinkrement operatori vaqtinchalik
obyektda 5 ning asl qiymatini saqlab qolishi, x obyektining qiymatini 6
ga oshirishi, so'ngra vaqtinchalik obyektning qiymatini qaytarishi va
uni a obyektiga o‘zlashtirishi kerak.
E'tibor bering, biz vaqtinchalik obyekt haqida gapirayotganimiz
sababli, uni havola sifatida emas, balki qiymat sifatida qaytarish kerak,
chunki vaqtinchalik obyekt funksiyaning qiymatini qaytarishi bilanoq
doiradan chiqib ketadi.
Qo‘shicha yuklangan operatorlarni e'lon qilish funksiyalar bilan bir
xil tarzda amalga oshiriladi. Orerator kalit so'zidan keyin qo‘shimcha
yuklangan operatorning o'zidan foydalaning.
Keling, Counter obyekti argument sifatida ishlaydigan Add ()
funksiyasini yozishdan boshlaylik. Ushbu funksiya ikkita qiymatni
qo'shishi kerak, so'ngra olingan natija bilan qiymatni qaytaring. Ushbu
yondashuv 19.11 Listingida ko'rsatilgan.
Listing 19.11. Qo'shish () funksiyasi
1 #include <iostream>
2 using namespace std;
3 class Counter
4 {public:
5 Counter();
6 Counter(int initialValue);
7 ~Counter(){ }
8 int GetItsVal()const {return itsVal; }
9 void SetItsVal(int x) {itsVal = x;}
10 Counter Add(const Counter &);
11 private:
250
12 int itsVal;
13 };
14 Counter::Counter(int initialValue):
15 itsVal(initialValue){}
16 Counter::Counter():
17 itsVal(0){}
18 Counter Counter::Add(const Counter & rhs)
19 {return Counter(itsVal+ rhs. GetItsVal());}
20 int main(){
21 Counter varOne(2), varTwo(4), varThree;
22 varThree = varOne. Add(varTwo);
23 cout << "var0ne: " << varOne.GetItsVal()<< endl;
24 cout << "varTwo: " << varTwo.GetItsVal() << endl;
25 cout << "varThree: " << varThree.GetItsVal() << endl;
26 return 0;}
Natija:
varOne: 2
varTwo: 4
varThree: 6
IKKI OPERANDLI OPERATORLARNING
QO‘SHIIMCHA YUKLANISHI
Ikki operandli operatorlar bitta operandli operatorlar bilan bir xil
tarzda e'lon qilinadi, faqat ushbu operatorlarning funksiyalari
parametrlarni o'z ichiga oladi. Parametrlar bir xil tipdagi obyektlarga
o‘zgarmas havolalardir.
OPERATORLARNING HADDAN TASHQARI
YUKLANISHI
Siz standart ma'lumotlar turlarining operatorlarini (masalan, int)
ortiqcha yuklay olmaysiz. Shuningdek, operatorlarning belgilangan
ustuvorliklari va assotsiativligini o'zgartirish mumkin emas. Masalan,
bitta operandli operatorni ikkita operand bilan ishlatish uchun
qo‘shimcha yuklay olmaysiz.
Operator tomonidan boshqarilishi mumkin bo'lgan operandlar soni
har bir operatorning muhim xususiyatidir. Bitta operand bilan
ishlatiladigan operatorlar (masalan, inkrement operatori: myValue++)
va ishlashi uchun ikkita operand ko'rsatilishi kerak bo'lgan operatorlar
(masalan, qo‘shish operatori: a+b) o'rtasida farq bor. Bir vaqtning o'zida
faqat shartli operator uchta operandni boshqaradi, foydalanish sintaksisi
quyidagi misolda ko'rsatilgan: (a > b ? x : y).
Tavsiya etiladi!
Agar dastur kodi bundan keyin aniqroq bo'lsa, operatorlarni
qo‘shimcha yuklang.
251
Qo‘shimch yuklangan operatorlardan sinf obyektlarini
qaytaring.
O‘ZLASHTIRISH OPERATORI
To'rtinchi va oxirgi, obyektlar bilan ishlash uchun kompilyator
tomonidan taqdim etilgan funksiya, agar siz qo'shimcha funksiyalarni
o'rnatmagan bo'lsangiz, bu o‘zlashtirish operatori funksiyasi
(operator=()). Ushbu operator obyektga yangi qiymat berish kerak
bo'lganda ishlatiladi, masalan:
CAT catOne(5,7);
CAT catTwo(3,4);
// ... dasturning boshqa satrlari
catTwo = catOne;
Ushbu misolda catOne obyekti yaratilgan bo'lib, uning
o'zgaruvchisi itsage 5 ga, itsweigth o'zgaruvchisi esa 7 ga teng. Keyin
catTwo obyekti mos ravishda 3 va 4 o'zgaruvchilar qiymatlari bilan
yaratiladi.
Biroz vaqt o'tgach, catTwo obyektiga catOne obyekt qiymatlari
beriladi. Agar itsage o'zgaruvchisi ko'rsatgich bo'lsa va catTwo obyekt
o'zgaruvchilarining eski qiymatlari bilan nima sodir bo'ladi?
Dinamik xotira sohasida o'z qiymatlarini saqlaydigan a'zo
o'zgaruvchilar bilan ishlash avval nusxa ko'chirish konstruktoridan
foydalanishni muhokama qilishda ko'rib chiqilgan (shuningdek, rasmga
qarang. 19.1 va 19.2).
C++ da ma'lumotlarni yuzaki va chuqur nusxalash farqlanadi.
Yuzaki nusxalashda faqat manzil bir o'zgaruvchidan ikkinchisiga
o'tkaziladi, natijada ikkala obyekt ham bir xil xotira katakchalariga
ishora qiladi. Chuqur nusxa ko'chirishda o'zgaruvchilar qiymatlari
xotiraning bir maydonidan boshqasiga ko'chiriladi. Ushbu nusxalash
usullari o'rtasidagi farqlar 19.3-rasmda ko'rsatilgan.
253
30 cout << "frisky's age: " << frisky.GetAge() << endl;
31 cout << "Setting frisky to 6...\n";
32 frisky. SetAge(6);
33 CAT whiskers;
34 cout << "whiskers' age: " << whiskers.GetAge() << endl;
35 cout << "copying frisky to whiskers...\n";
36 whiskers = frisky;
37 cout << "whiskers' age: " << whiskers.GetAge() << endl;
38 return 0;}
Natija:
frisky's age: 5
Setting frisky to 6…
whiskers' age: 5
copying frisky to whiskers…
whiskers' age: 6
Nazorat savollari va toshiriqlar:
1. Agar siz a'zo funksiyasini qo‘shimcha yuklagan bo'lsangiz, keyinchalik
funksiyaning turli xil variantlarini qanday ajratish mumkin?
2. Nusxa ko'chirish konstruktori qachon chaqiriladi? This ko'rsatgich nima?
3. Destruktor qachon chaqiriladi?
4. Nusxa ko'chirish konstruktori va o‘zlashtirish operatori (=) o'rtasidagi
farq nima?
5. C++ da operator ++ ni sinfda o'chirish amalini bajaradigan tarzda
qo‘shimcha yuklashga ruxsat beriladimi?
6. Itsradius a'zosi bo'lgan bitta o'zgarish bilan SimpleCircle sinfining e'lonini
taqdim eting. Sinf sukut bo'yicha o'rnatilgan konstruktor va destruktordan,
shuningdek radiusni o'rnatish usulidan foydalanishi kerak.
7. 6-mashqda yaratilgan sinfdan foydalanib, standart konstruktor yordamida
itsradius o'zgaruvchisini 5 qiymati bilan ishga tushiring.
8. Itsradius o'zgaruvchisiga parametr qiymatini belgilaydigan sinfga yangi
konstruktor qo'shing.
9. SimpleCircleni itsradiusni dinamik xotira maydoniga saqlash va mavjud
usullarni yozib olish uchun o'zgartiring.
10. SimpleCircle sinfida nusxa ko'chiruvchi konstruktor yarating.
11. Xatolikni toping.
SQUARE SQUARE :: operator=(const SQUARE & rhs)
{ its Side = new int;
*itsSide = rgs. GetSide();
return *this;
}
254
20-MAVZU. VORISLIK.
Meros
Merosxo‘rlikdan foydalanish
Virtual funksiyalar
255
munosabatlar misolida ko'rib chiqing. Tasavvur qiling, dasturchi
"Farm" bolalar o'yinini yaratish uchun buyurtma oldi. Fermada
yashovchi hayvonlarni, shu gapdan otlar, sigirlar, itlar, mushuklar,
qo'ylar va boshqalarni yaratishni boshlaganingizda, siz ularning har bir
sinfini shunday usullar bilan ta'minlashingiz kerak bo'ladi.
SINF MEROS SINTAKSISI
Yangi lotin sinfini yaratish uchun kalit so'zidan foydalaniladi,
shundan so'ng yangi sinf nomi, figurali qavs, sinf prototipining tipi
(public yoki boshqa), so'ngra quyidagi misolda bo'lgani kabi asosiy sinf
nomi ko'rsatiladi:
class Dog : public Mammal
Mammal sinfidan Dog sinfining merosiga misol Listing 20.1 da
keltirilgan.
Listing 20.1. Oddiy meros
1 #include<iostream>
2 using namespace std;
3 enum BREED { GOLDEN, CAIRN, DANDIE, SHETLAND, DOBERMAN, LAB };
4 class Mammal
5{
6 public:
7 Mammal();
8 ~Mammal();
9 int GetAge()const;
10 void SetAge(int);
11 int GetWeight()const;
12 void SetWeight();
13 void Speak() const;
14 void Sleep() const;
15 protected:
16 int itsAge;
17 int itsWeight;
18 };
19
20 class Dog : public Mammal
21 {
22 public:
23 Dog();
24 ~Dog();
25 BREED GetBreed() const;
26 void SetBreed(BREED);
27 protected:
28 BREED itsBreed;
29 };
Natija:
Ushbu dastur ekranda hech narsani ko'rsatmaydi, chunki u hozircha
faqat e'lonlar va sinflarni o'rnatishni o'z ichiga oladi. Ushbu dastur hali
hech qanday funksiyani bajarmaydi.
256
PRIVATE VA PROTECTED
(YOPIQ YOKI HIMOYALANGAN)
Siz Listing 20.1 ning 15 va 27-qatorlarida yangi protected kalit
so'zdan foydalanilgan. Hozirgacha sinf ma'lumotlari private kalit so'z
bilan aniqlangan. Ammo private deb e'lon qilingan sinf a'zolari meros
uchun mavjud emas. Albatta, oldingi Listingda itsAge va itsWeight a'zo
o'zgaruvchilarini public sifatida aniqlash mumkin edi, chunki
dasturning boshqa barcha sinflari ushbu o'zgaruvchilarga to'g'ridan-
to'g'ri kirish huquqiga ega bo'lar edi.
Protected kalit so'z bilan aniqlangan himoyalangan ma'lumotlar
aynan shunday. Himoyalangan ma'lumotlar barcha meros sinflar uchun
mavjud, ammo barcha tashqi sinflar uchun mavjud emas.
Demak, uchta mavjud - public, protected va
private. Agar sinf obyektlari funksiyaga o'tkazilsa, u
bilan e'lon qilingan barcha a'zo o'zgaruvchilar va a'zo
funksiyalar ma'lumotlaridan foydalanishi mumkin. Sinf a'zosi
funksiyasi, shuningdek, ushbu sinfning barcha yopiq ma'lumotlarini
( deb e'lon qilingan) va ushbu sinfdan ishlab chiqarilgan boshqa
har qanday sinfning himoyalangan ma'lumotlarini ( deb e'lon
qilingan) ishlatishi mumkin.
Shunday qilib, bizning misolimizda Dog::WagTail() funksiyasi
Private itsBreed o'zgaruvchisining qiymatidan va himoyalangan deb
e'lon qilingan barcha Mammal sinf o'zgaruvchilaridan foydalanishi
mumkin.
Agar Dog sinfi Mammal sinfidan to'g'ridan-to'g'ri emas, balki ba'zi
bir oraliq sinfdan (masalan, DomesticAnimals) meros olingan bo'lsin.
Dog sinfi va barcha oraliq sinflar public deb e'lon qilingan bo'lsa,
Mammal sinfining himoyalangan ma'lumotlariga kirish saqlanib qoladi.
Listing 20.2 ushbu tipdagi barcha ma'lumotlar va funksiyalarga kirish
huquqiga ega bo'lgan Dog sinfida obyekt yaratishni ko'rsatadi.
Listing 20.2. Meros obyektlaridan foydalanish
1 #include<iostream>
2 using namespace std;
3 enum BREED { GOLDEN, CAIRN, DANDIE, SHETLAND, DOBERMAN,LAB};
4 class Mammal
5 { public:
6 Mammal():itsAge(2), itsWeight(5){ }
7 ~Mammal(){ }
8 int GetAge()const { return itsAge; }
9 void SetAge(int age) { itsAge = age; }
257
10 int GetWeight()const { return itsWeight; }
11 void SetWeight(int weight) { itsWeight = weight; }
12 void Speak()const { cout << "Mammal sound!\n"; }
13 void Sleep()const { cout << "shhh. I'm sleeping.\n";}
14 protected:
15 int itsAge;
16 int itsWeight; };
17 class Dog : public Mammal
18 {public:
19 Dog():itsBreed(GOLDEN){ }
20 ~Dog(){ }
21 BREED GetBreed() const { return itsBreed; }
22 void SetBreed(BREED breed) { itsBreed = breed; }
23 void WagTail() const { cout << "Tail wagging. . . \n"; }
24 void BegForFood() const { cout << "Begging for food. . . \n"; }
25 private:
26 BREED itsBreed;};
27 int main(){
28 Dog fido;
29 fido.Speak();
30 fido.WagTail();
31 cout << "Fido is " << fido.GetAge() << "years old\n";
32 return 0;}
Natija:
Mammal sound!
Tail wagging. . .
Fido is 2years old
KONSTRUKTORLAR VA DESTRUKTORLAR
Dog sinfidagi obyektlar bir vaqtning o'zida Mammal sinfidagi
obyektlardir. Dog sinfida fido obyekti yaratilganda, Mammal sinfidan
birinchi nomlangan asosiy konstruktor chaqiriladi. Keyin obyektni
yaratishni tugatadigan Dog sinf konstruktori chaqiriladi. Fido obyekti
hech qanday parametr bilan ta'minlanmaganligi sababli, ikkala holatda
ham sukut bo'yicha o'rnatilgan konstruktor chaqiriladi. Fido obyekti
mammal sinfi va Dog sinfining ikkala konstruktori yordamida to'liq
yaratilgunga qadar mavjud emas.
Fido obyektini kompyuter xotirasidan olib tashlaganingizda, avval
Dog class destruktori, so'ngra Mammal class destruktori chaqiriladi.
Har bir destruktor obyektning tegishli merosxo‘r yoki asosiy sinf
konstruktori tomonidan yaratilgan qismini olib tashlaydi.
Listing 20.3. Konstruktor va destruktorni chaqirish
1 #include<iostream>
2 using namespace std;
3 enum BREED { GOLDEN, CAIRN, DANDIE, SHETLAND, DOBERMAN,LAB};
4 class Mammal
5 { public:
6 Mammal();
7 ~Mammal();
258
8 int GetAge()const
9 { return itsAge; }
10 void SetAge(int age)
11 { itsAge = age; }
12 int GetWeight()const
13 { return itsWeight; }
14 void SetWeight(int weight)
15 { itsWeight = weight; }
16 void Speak()const
17 { cout << "Mammal sound!\n"; }
18 void Sleep()const
19 { cout << "shhh. I'm sleeping.\n";}
20 protected:
21 int itsAge;
22 int itsWeight; };
23 class Dog : public Mammal
24 {public:
25 Dog();
26 ~Dog();
27 BREED GetBreed() const
28 { return itsBreed; }
29 void SetBreed(BREED breed)
30 { itsBreed = breed; }
31 void WagTail() const
32 { cout << "Tail wagging. . . \n"; }
33 void BegForFood() const
34 { cout << "Begging for food. . . \n"; }
35 private:
36 BREED itsBreed;};
37 Mammal::Mammal():
38 itsAge(1),
39 itsWeight(5)
40 {cout << "Mammal constructor. . . \n";}
41 Mammal::~Mammal()
42 {cout << "Mammal destructor. . . \n";}
43 Dog::Dog():
44 itsBreed(GOLDEN)
45 {cout << "Dog constructor. . . \n ";}
46 Dog::~Dog()
47 {cout << "Dog destructor. . . \n"; }
48 int main()
49 {Dog fido;
50 fido.Speak();
51 fido.WagTail();
52 cout << "Fido is " << fido.GetAge() << "years old\n";
53 return 0;}
Natija:
Mammal constructor. . .
Dog constructor. . .
Mammal sound!
Tail wagging. . .
Fido is 1years old
Dog destructor. . .
Mammal destructor. . .
259
Aytaylik, siz Mammal va Dog sinflarida sukut bo'yicha o'rnatilgan
konstruktorlarni qo‘shimcha yuklashingiz kerak, shunda ulardan
birinchisi darhol yangi obyektga ma'lum bir yoshni o‘zlashtiradi.
Asosiy sinfni ishga tushirish uchun siz sinf nomini yozishingiz
kerak, so'ngra Listing 20.4 da ko'rsatilganidek, asosiy sinf parametrlarni
ko'rsatishingiz kerak.
Listing 20.4. Merosxo‘r sinflarda konstruktorlarning
qo‘shimcha yuklanishi.
1 #include <iostream>
2 using namespace std;
3 enum BREED { GOLDEN, CAIRN, DANDIE, SHETLAND, DOBERMAN,LAB};
4 class Mammal
5 {public:
6 Mammal();
7 Mammal(int age);
8 ~Mammal();
9 int GetAge() const { return itsAge; }
10 void SetAge(int age) { itsAge = age; }
11 int GetWeight() const { return itsWeight; }
12 void SetWeight(int weight) { itsWeight = weight; }
13 void Speak() const { cout << "Mammal sound!\n"; }
14 void Sleep() const { cout << "shhh. I'm sleeping.\n"; }
15 protected:
16 int itsAge;
17 int itsWeight;
18 };
19 class Dog : public Mammal
20 {public:
21 Dog();
22 Dog(int age);
23 Dog(int age, int weight);
24 Dog(int age, BREED breed);
25 Dog(int age, int weight, BREED breed);
26 ~Dog();
27 BREED GetBreed() const { return itsBreed; }
28 void SetBreed(BREED breed) { itsBreed = breed; }
29 void WagTail() const { cout << "Tail wagging\n"; }
30 void BegForFood() const { cout << "Begging for food\n"; }
31 private:
32 BREED itsBreed;
33 };
34 Mammal::Mammal():
35 itsAge(1),
36 itsWeight(5)
37 {cout << "Mammal constructor...\n";}
38 Mammal::Mammal(int age):
39 itsAge(age),
40 itsWeight(5)
41 { cout << "Mammal(int) constructor...\n";}
42 Mammal::~Mammal()
43 { cout << "Mammal destructor...\n";}
44 Dog:: Dog():
260
45 Mammal(),
46 itsBreed(GOLDEN)
47 { cout << "Dog constructor...\n"; }
48 Dog::Dog(int age):
49 Mammal(age),
50 itsBreed(GOLDEN)
51 { cout << "Dog(init) constructor...\n"; }
52 Dog::Dog(int age, int weight):
53 Mammal(age),
54 itsBreed(GOLDEN)
55 {itsWeight = weight;
56 cout << "Dog(int, int) constructor...\n"; }
57 Dog::Dog(int age, int weight, BREED breed):
58 Mammal(age),
59 itsBreed(breed)
60 {itsWeight = weight;
61 cout << "Dog(int, int, BREED) constructor...\n";}
62 Dog::Dog(int age, BREED breed):
63 Mammal(age),
64 itsBreed(breed)
65 {cout << "Dog(in, BREED) constructor...\n";}
66 Dog:: ~Dog()
67 {cout << "Dog destructor...\n";}
68 int main()
69 {
70 Dog fido;
71 Dog rover(5);
72 Dog buster(6,8);
73 Dog yorkie (3,GOLDEN);
74 Dog dobbie (4, 20, DOBERMAN);
75 fido. Speak();
76 rover.WagTail();
77 cout << "Yorkie is " << yorkie.GetAge() << " years old\n";
78 cout << "Dobbie weighs ";
79 cout << dobbie. GetWeight() << " pounds\n";
80 return 0;}
Natija:
Mammal constructor…
Dog constructor…
Mammal(int) constructor…
Dog(int) constructor…
Mammal(int) constructor…
Dog(int, int) constructor…
Mammal(int) constructor…
Dog(int, BREED) constructor…
Mammal(int) constructor…
Dog(int, int, BREED) constructor…
Mammal sound!
Tail wagging.
Yorkie is 3 years old.
Dobbie weighs 20 pounds.
Dog destructor…
Mammal destructor…
Dog destructor…
Mammal destructor…
261
Dog destructor…
Mammal destructor…
Dog destructor…
Mammal destructor…
Dog destructor…
Mammal destructor…
262
woof!
dog destructor. . .
mammal destructor. . .
mammal destructor. . .
Ushbu o'xshash yondashuvlar deyarli bir xil natijalarga olib keladi.
Oldingi misolda, Dog class obyektidan Speak() usuliga murojaat
qilganda, dastur asosiy sinfda Speak() usulini e'lon qilishda
ko'rsatilgandek bajarilmadi.. Agar mammal sinfida it sinfida
almashtirilgan Move () usuli mavjud bo'lsa, unda it sinfining Move()
usuli asosiy sinfda bir xil nomdagi usulni yashiradi deb aytish mumkin.
Biroq, ba'zi hollarda natija kutilmagan bo‘lishi ham mumkin.
Keling, vaziyatni murakkablashtiraylik. Mammal sinfida Move ()
usuli uch marta qo‘shimcha yuklangan deb taxmin qiling. Bir variantda
usul parametrlarni talab qilmaydi, ikkinchisida bitta butun parametri
(masofa), uchinchisida ikkita butun parametri (tezlik va masofa)
ishlatiladi. Dog sinfida parametrlarsiz Move() usuli almashtiriladi.
Shunga qaramay, Dog sinf obyektidan Mammal sinfining qo‘shimcha
yuklangan usulining boshqa ikkita variantiga murojaat qilishga urinish
muvaffaqiyatsiz bo'ladi. Muammoning mohiyati Listing 20.6 da ochib
berilgan.
Listing 20.6 Funksiyalarni yashirish
1 #include <iostream>
2 using namespace std;
3 class Mammal
4 {public:
5 void Move() const
6 { cout<<"mammal move one step\n";}
7 void Move(int distance) const
8 {cout<<"mammal move";
9 cout<<distance<<"steps.\n";}
10 protected:
11 int itsAge;
12 int itsWeight;};
13 class Dog: public Mammal
14 {public:
15 void Move() const
16 { cout<<"dog";}
17 int main()
18 {Mammal bigAnimal;
19 Dog fido;
20 bigAnimal.Move();
21 bigAnimal.Move(2);
22 fido.Move();
23 return 0;}
263
Natija:
mammal move one step
mammal move2steps.
odg move 5 steps.
ASOSIY FUNKSIYANI CHAQIRISH
Siz asosiy funksiyaga murojaat qilishingiz mumkin. Buning uchun
funksiyaga murojaat qilishda siz asosiy sinf nomini, so'ngra ikkita nuqta
belgisi va funksiya nomini aniq ko'rsatishingiz kerak. Masalan:
Mammal:: Move ().
Listing 20.7 da amalga oshirilgan bunday yozuv asosiy sinf usuliga
aniq kirish deb nomlanadi.
Listing 20.7. Asosiy sinf usuliga aniq murojaat qilish
1 #include <iostream>
2 using namespace std;
3 class Mammal
4 { public:
5 void Move() const
6 {cout<<"mammal move one step\n";}
7 void Move(int distance) const
8 {cout<<"mammal move"<<distance;
9 cout<<"steps.\n";}
10 protected:
11 int itAge;
12 int itsWeght;};
13 class Dog: public Mammal
14 {public:
15 void Move() const;};
16 void Dog:: Move () const
17 {cout<<"in dog move...\n";
18 Mammal::Move(3);}
19 int main()
20 {Mammal bigAnimal;
21 Dog fido;
22 bigAnimal.Move(2);
23 fido.Mammal::Move(6);
24 return 0;}
Natija:
mammal move2steps.
mammal move6steps.
Tavsiya etiladi!
Yangi olingan sinflarni yaratish orqali sinfning funksional
imkoniyatlarini oshiring.
264
VIRTUAL FUNKSIYALAR
C++ dagi polimorfizm shu qadar rivojlanganki, quyidagi misolda
bo'lgani kabi, olingan sinflar obyektlarining manzillarining asosiy
sinfiga belgilar berishga ruxsat beriladi:
Mammal* pMammal = new Dog;
Ushbu ifoda dinamik xotira sohasida Dog sinfining yangi obyektini
yaratadi va ko'rsatgichni mammal sinfining ko'rsatkichi bo'lgan ushbu
obyektga qaytaradi. Bu juda mantiqiy, chunki it sutemizuvchilarning
vakili.
Ushbu ko'rsatgich keyinchalik Mammal sinfining har qanday
usulini chaqirish uchun ishlatilishi mumkin. Bundan tashqari, agar usul
Dog sinfida almashtirilgan bo'lsa, u holda ko'rsatgich orqali usulga
murojaat qilganda, ushbu olingan sinfda ko'rsatilgan variant chaqiriladi.
Bu virtual funksiyalardan foydalanishning mohiyati. Listing 20.8
virtual funksiya qanday ishlashini va virtual bo'lmagan funksiya bilan
nima sodir bo‘lishini ko'rsatadi.
Listing 20.8. Virtual usullardan foydalanish
1 #include <iostream>
2 using namespace std;
3 class Mammal
4 {public:
5 Mammal():itsAge(1) {cout << "Mammal constructor…\n"; }
6 virtual ~Mammal() { cout << "Mammal destructor...\n";}
7 void Move() const { cout << "Mammal move one step\n";}
8 virtual void Speak() const { cout << "Mammal speak!\n"; }
9 protected:
10 int itsAge;
11 };
12 class Dog : public Mammal
13 {public:
14 Dog() { cout << "Dog Constructor...\n"; }
15 virtual ~Dog() { cout << "Dog destructor…\n"; }
16 void WagTail() { cout << "Wagging Tail...\n"; }
17 void Speak()const { cout << "Woof!\n"; }
18 void Move()const {cout << "Dog moves 5 steps...\n"; }
19 };
20 int main(){
21 Mammal *pDog = new Dog;
22 pDog->Move();
23 pDog->Speak();
24 return 0;}
Natija:
Mammal constructor...
Dog Constructor...
265
Mammal move one step
Woof!
ESLATMA: Kompilyatsiya vaqtida foydalanuvchi qaysi sinf
obyektini yaratmoqchi ekanligi va Speak() usulining qaysi versiyasidan
foydalanilishi noma'lum. Ko'rsatgichning obyektga bunday bog'lanishi,
dasturni kompilyatsiya qilish paytida sodir bo'ladigan statik
bog'lanishdan farqli o'laroq, deb ataladi.
VIRTUAL FUNKSIYALAR QANDAY ISHLAYDI
Olingan sinfda, masalan, Dog sinfida obyekt yaratishda, avval
asosiy konstruktor, so'ngra olingan sinf chaqiriladi. Sxematik ravishda
it sinfining obyekti 20.2-rasmda berilgan. E'tibor bering, lotin sinfining
obyekti ikki qismdan iborat bo'lib, ulardan biri asosiy sinf konstruktori
tomonidan, ikkinchisi lotin sinfining konstruktori tomonidan
yaratilgan.
266
20.4-rasm. Dog sinfining virtual funksiyalari jadvali
Shunday qilib, har bir obyektda vptr ko'rsatkichi mavjud bo'lib, u
o'z navbatida barcha virtual funksiyalarga ko'rsatgichlarni o'z ichiga
olgan virtual funksiyalar jadvaliga murojaat qiladi. Dog sinfidagi
obyekt uchun vptr ko'rsatgichi rasmda ko'rsatilgandek, asosiy Mammal
sinfiga tegishli obyekt qismini yaratishda ishga tushiriladi.
Dog class Builderni chaqirgandan so'ng, vptr ko'rsatkichi Dog sinfi
uchun quritilgan virtual funksiyaning (agar mavjud bo'lsa)
almashtirilgan versiyasini ko'rsatadigan tarzda o'rnatiladi (20.4-rasm).
Natijada, Mammal sinfiga ko'rsatgichdan foydalanganda, vptr
ko'rsatgichi obyektning haqiqiy turiga mos keladigan virtual funksiya
variantiga ishora qiladi. Shuning uchun, oldingi misolda Speak()
usuliga murojaat qilganda, tegishli olingan sinfda berilgan funksiya
bajarildi.
Agar asosiy sinf obyektiga ko'rsatgich qo‘yilsa, ko'rsatgichni
meroso‘r sinf obyektiga o'tkazish juda maqbul va ko'pincha amalda
qo'llaniladi. Keyin merosxo‘r sinf destruktori avtomatik ravishda asosiy
sinf destruktorini chaqiradi va ko'rsatilgan obyekt butunlay o'chiriladi.
Bu qoidadan kelib chiqadi: agar sinfda virtual funksiyalar e'lon
qilingan bo'lsa, unda destruktor virtual bo‘lishi kerak.
Konstruktorlar virtual bo‘lishi mumkin emas, bundan xulosa qilish
mumkinki, virtual nusxa ko'chirish konstruktori ham bo‘lishi mumkin
emas. Ammo ba'zida dastur ko'rsatgichni asosiy sinf obyektiga
o'tkazishi va uni olingan sinf obyektiga to'g'ri nusxalashi talab qilinadi.
Bunga erishish uchun asosiy sinfda virtual clone () usulini yaratish
kerak. Clone () usuli joriy sinf obyektining nusxasini yaratishi va
qaytarishi kerak.
Olingan sinflarda clone () usuli almashtirilganligi sababli, uni
chaqirganda tanlangan sinfga mos keladigan obyektlarning nusxalari
267
yaratiladi. Ushbu usuldan foydalanadigan dastur Listing 20.9 da
ko'rsatilgan.
Listing 20.9. Virtual nusxa ko'chirish konstruktori
1 #include <iostream>
2 using namespace std;
3 class Mammal
4 {public:
5 Mammal():itsAge(1) { cout << "Mammal constructor...\n";}
6 virtual ~Mammal() { cout << "Mammal destructor...\n";}
7 Mammal (const Mammal & rhs);
8 virtual void Speak() const { cout << "Mammal speak!\n";}
9 virtual Mammal* Clone() { return new Mammal(*this);}
10 int GetAge()const {return itsAge;}
11 protected:
12 int itsAge;
13 };
14 Mammal::Mammal (const Mammal & rhs):itsAge(rhs.GetAge())
15 {cout << "Mammal Copy Constructor...\n";}
16 class Dog : public Mammal
17 {public:
18 Dog() { cout << "Dog constructor...\n";}
19 virtual ~Dog() { cout << "Dog destructor...\n"; }
20 Dog (const Dog & rhs);
21 void Speak()const { cout << "Woof!\n"; }
22 virtual Mammal* Clone() {return new Dog(*this); }
23 };
24 Dog::Dog(const Dog & rhs):
25 Mammal(rhs)
26 {cout << "Dog copy constructor...\n";}
27 class Cat : public Mammal
28 {public:
29 Cat() { cout << "Cat constructor\n"; }
30 ~Cat() { cout << "Cat destructor\n"; }
31 Cat (const Cat &);
32 void Speak()const { cout << "Meow!\n"; }
33 virtual Mammal* Clone() { return new Cat(*this); }
34 } ;
35 Cat::Cat(const Cat & rhs):
36 Mammal(rhs)
37 {cout << "Cat copy constructor\n";}
38 enum ANIMALS { MAMMAL, DOG, CAT} ;
39 const int NumAnimalTypes = 3;
40 int main()
41 {
42 Mammal *theArray[NumAnimalTypes];
43 Mammal* ptr;
44 int choice, i;
45 for ( i = 0; i<NumAnimalTypes; i++)
46 {
47 cout << "(1)dog (2)cat (3)Mammal: ";
268
48 cin >> choice;
49 switch (choice)
50 {
51 case DOG: ptr = new Dog;
52 break;
53 case CAT: ptr = new Cat;
54 break;
55 default: ptr = new Mammal;
56 break;
57 }
58 theArray[i] = ptr;
59 Mammal *OtherArray[NumAnimalTypes];
60 for (i=0;i<NumAnimalTypes; i++){
61 theArray[i]->Speak();
62 OtherArray[i] = theArray[i]->Clone();
63 }
64 for (i=0;i<NumAnimalTypes; i++)
65 OtherArray[i]->Speak();}
66 return 0;}
Tavsiya etiladi!
Agar dastur asosiy va olingan sinflarni o'z ichiga olgan bo'lsa,
virtual usullardan foydalaning.
Agar dasturda virtual usullar yaratilgan bo'lsa, virtual
destruktordan foydalaning.
269
11. Aytaylik, oldingi misolda Shape sinf obyekti parametrlardan
foydalanmaydi, to'rtburchaklar sinf obyekti ikkita parametrni oladi
(uzunlik va kenglik) va kvadrat sinf obyekti bitta parametr (1 uzunlik);
kvadrat sinf uchun konstruktorni yozing.
12. 11-mashqdan olingan Square sinfi uchun virtual nusxa ko'chirish
konstruktorini yozing.
13. Xatolikni toping.
void SomeFunction(Shape);
Shape pRect = new Rectangle;
SomeFunction(+pRect);
14. Xatolikni toping.
class Shape()
{
public:
Shape();
virtual -Shape();
virtual Shape(const Shape&);};
270
21-MAVZU. ICHMA-ICH JOYLASHGAN SINFLAR
Ichki sinf
Ichki sinf uchun kirish modifikatori
Ichki sinf obyekti
ICHKI SINF
boshqa sinf ichida joylashgan sinf.
Odatda, ichki sinflar faqat tashqi sinf obyekti ichida mavjud bo‘lishi
mumkin bo'lgan obyektlarni tavsiflash uchun ishlatiladi.
Kichik bir misolni ko'rib chiqing. Aytaylik, foydalanuvchi uchun
uning hisobini tavsiflovchi ma'lumotlarni (Login, parol) aniqlashimiz
kerak.
Listing 21.1.
#include <iostream>
class Person
{
private:
std::string name;
271
};
int main()
{
Person tom("Tom", "tom@localhost.com", "qwerty");
tom.print();}
272
Asosiy funksiyada biz bitta person obyektini yaratamiz va
konstruktor orqali ma'lumotlarni, shu gapdan account obyekti uchun
uzatamiz:
Person tom ("Tom", "tom@localhost.com", "qwerty“);
tom.print();
Yuqoridagi misolda Account obyektlarini Person sinfdan
tashqarida yaratish yoki ishlatish mumkin emas, chunki Account sinfi
Private.
Shu bilan birga, biz uni hammaga ochiq qilishimiz va keyin Person
sinfidan tashqarida unga murojaat qilishimiz mumkin:
Listing 21.3.
#include <iostream>
class Person
{public:
class Account // ichki sinf
{
public:
Account(const std::string& p_email, const std::string&
p_password)
{
email = p_email;
password = p_password;
}
std::string email{};
std::string password{};
void print2()
{std::cout<<"salom";
}
};
Person(const std::string& p_name, const Account&
p_account)
{
name = p_name;
account = p_account;
}
void print()
{
std::cout<<"Name: " << name << "\n" << "Email: " <<
account.email << "\n"
<< "Password: " << account.password << std::endl;
}
private:
std::string name;
Account account{"", ""}; // ichki sinfining obyekti
};
int main()
{
Person::Account account("bob@somemail.com", "qwerty");
273
Person bob("Bob", account);
bob.print();
account.print2();
}
Endi ichki sinf Public. Biz ushbu sinfning obyektlarini yaratishimiz
va tashqi sinf nomidan foydalanib uning o'zgaruvchilari va
funksiyalariga murojaat qilishimiz mumkin:
Person::Account account ("bob@somemail.com", "qwerty");
Ichki sinf funksiyalari to'g'ridan-to'g'ri tashqi sinfning statik
a'zolariga, shuningdek tashqi sinfda aniqlangan boshqa turlarga
murojaat qilishi mumkin.
Tashqi sinfning boshqa a'zolariga ichki sinfdan standart usullar
bilan kirish mumkin: sinf obyekti, ko'rsatgich yoki sinf obyektiga
havola orqali.
Bunday holda, ichki sinfning funksiyalari tashqi sinfda aniqlangan
private o'zgaruvchilar va constlarga murojaat qilishi mumkin.
274
22-MAVZU. POLIMORFIZM
Ko'p meros va undan foydalanish
Virtual meros
Mavhum ma'lumotlar turlari
Sof virtual funksiyalar
275
else
gallop(distance);
}
Ammo bu yondashuv bir qator cheklovlarga ega, chunki obyekt
endi qisqa masofalarga ucha olmaydi va uzoq masofalarga yugura
olmaydi.
USULNI IYERARXIK SINFLARIGA O'TKAZISH
Ko'pincha, bunday muammolarni hal qilish uchun usul prototipi
sinflarning ierarxik Listingi bo'ylab yuqoriga ko'tarilib, uni ko'proq
lotin sinflariga taqdim etiladi.
Fly() usuli faqat ko'rsatgich Pegasus obyekti bilan bog'langan
taqdirdagina chaqirilishi mumkin. Buning uchun siz ko'rsatgichga
murojaat qilishingiz va qaysi obyektni ko'rsatayotganini aniqlashingiz
kerak.
Ushbu yondashuv RTTI (Runtime Type Identification bajarilganda
turini aniqlash) deb nomlanadi. Ammo RTTI-ni bajarish qobiliyati
faqat C++ kompilyatorlarining so'nggi versiyalariga qo'shildi.
Agar sizning kompilyatoringiz RTTI-ni qo'llab-quvvatlamasa,
dasturga har bir sinf turlarining Listingini qaytaradigan usul qo'shib, uni
o'zingiz amalga oshirishingiz mumkin. Qaytarilgan qiymat dasturni
bajarish paytida tahlil qilinishi mumkin va Agar Pegasus qiymati
qaytarilsa, Fly() usulini chaqirishga ruxsat beriladi.
Fly () usulini chaqirish uchun ko'rsatgich tipini ish vaqtida
o'zgartirish kerak, bu uning Horse obyekti bilan emas, balki Pegasus
merosxo‘r sinfining obyekti bilan bog'liqligini aniqlaydi. Ushbu
yondashuv C++ da dynamic_cast operatori orqali amalga oshiriladi.
Agar dasturda asosiy Horse sinfidagi obyektlarga ko'rsatgich
yaratilgan bo'lsa va unga Pegasus mersoxo‘r sinf obyektiga ko‘rsatgich
berilgan bo'lsa, unda bu ko'rsatgich polimorfik tarzda ishlatilishi
mumkin. Merosxo‘r sinf usuliga murojaat qilish uchun dynamic_cast
operatoridan foydalanib, asosiy sinf ko'rsatkichini merosxo‘r sinf
ko'rsatkichi bilan dinamik ravishda almashtirish kerak.
Dastur davomida asosiy sinf ko'rsatkichi sinovdan o'tkaziladi. Agar
asosiy sinf ko'rsatkichi ko‘rsatilgan joriy obyekt aslida merosxo‘r sinf
obyekti ekanligi aniqlansa, u holda merosxo‘r sinf ko'rsatkichi ushbu
obyekt bilan bog'lanadi. Aks holda, merosxo‘r sinf ko'rsatkichi nolga
aylanadi. Ushbu misol Listing 22.1 da keltirilgan.
276
Listing 22.1. Pastga tushirish
#include <iostream>
using namespace std;
enum TYPE {HORSE, PEGASUS };
class Horse
{
public:
virtual void Gallop(){ cout << "Galloping…\n"; }
private:
int itsAge;
};
class Pegasus : public Horse
{
public:
virtual void Fly()
{ cout << "I can fly! I can fly! I can fly!\n"; }
};
const int NumberHorse = 5;
int main(){
Horse* Ranch[NumberHorse];
Horse* pHorse;
int choice, l;
for (l=0; l<NumberHorse; l++)
{
cout << "(1)Horse (2)Pegasus: ";
cin >> choice;
if (choice == 2)
pHorse = new Pegasus;
else
pHorse = new Horse;
Ranch[l] = pHorse;
}
cout <<" n";
for (int i=0; i<NumberHorse; i++)
{
Pegasus *pPeg = dynamic_cast< Pegasus *> (Ranch[i]);
if (pPeg)
pPeg->Fly();
else
cout << "Just a horse\n";
delete Ranch[i];
}
return 0;
}
Natija:
(1)Horse (2)Pegasus: 1
(1)Horse (2)Pegasus: 2
(1)Horse (2)Pegasus: 1
(1)Horse (2)Pegasus: 2
277
(1)Horse (2)Pegasus: 1
Just a horse
I can fly! I can fly! I can fly!
Just a horse
I can fly! I can fly! I can fly!
Just a horse
Yana bir muammo shundaki, Pegasus Horse tipidagi obyekt
sifatida e'lon qilinganida, uni Pegasus sinfidagi obyektlar Listingiga
qo'shish imkonsiz bo'lib qoladi.
Shunday qilib, faqat bitta merosga rioya qilgan holda, bu
muammoni hal qilish mumkin emas edi. Siz uchta funksiyani - Fly(),
Whinny() va Gallop() - Bird va Horse ikkita sinflari uchun umumiy
bo'lgan asosiy Animal sinfiga o'tkazishingiz mumkin. Natijada, Bird va
Horse sinflari uchun ikkita obyekt Listingi o'rniga bitta umumiy Animal
sinf obyektlari Listingi paydo bo'ladi. Usulning kamchiligi shundaki,
asosiy sinf juda ko'p funksiyalarni o'z zimmasiga oladi.
Bir nechta asosiy sinflardan yangi sinflarni keltirib chiqarish
imkoniyati mavjud. Bunday jarayon deb ataladi. 22.2-
Listingda Pegasus sinfi ikkita asosiy sinf - Pegasus va Horsening
xususiyatlarini meros qilib oladigan tarzda e'lon qilingan. Keyingi
dastur Pegasus obyektini ikkala sinf obyektlari Listingiga qo'shadi.
Listing 22.2. Ko'p meros
#include <iostream>
using namespace std;
const int DefaultSize = 10;
class Array
{
public:
Array(int size = DefaultSize);
Array(const Array &rhs);
Array() { delete [] pType;}
// operatorlar
Array& operator=(const Array&);
int& operator[](int offSet);
const int& operator[](int offSet) const;
int GetitsSize() const { return itsSize; }
friend ostream& operator<< (ostream&, const Array&);
class xBoundary { }
class xSize { } ;
class xTooBig : public xSize ( } ;
class xTooSmall : public xSize { } ;
class xZero : public xTooSmall
class xNegative : public xSize { }
private:
int *pType;
278
int itsSize;
};
Array::Array(int size);
itsSize(size)
{
if (size == 0)
throw xZero();
if (size > 30000)
throw xTooBig():
if (size <1)
throw xNegative();
if (size < 10)
throw xTooSmall();
pType = new int[size];
for (int i = 0; i<size; i++)
pType[i] = 0;
}
int& Array::operator[](int offSet)
{
int size = GetitsSize();
if (offSet >= 0 && offSet < GetitsSize())
return pType[offSet];
throw xBoundary();
return pType[0]; / / kompilyator talabi
}
const int& Array::operator[](int offSet) const
int mysize = Gettitssize();
if (offSet >= 0 && offSet < Getitssize())
return pType[offSet];
throw xBoundary();
qaytish pType[0]; / / kompilyator talabi
int main()
try
Array intArray(0);
for (int j = 0; j< 100; j++)
intArray[j] = j;
cout << "intArray[" << j << "] okay…\n";
catch (Array::xBoundary)
cout << "Unable to process your input!\n";
catch (Array::xTooBig)
cout << "This array is too big…\n";
catch (Array::xTooSmall)
cout << "This array is too small…\n";
catch (Array: :zero)
cout << "You asked for an array";
cout << " of zero objects!\n";
catch (…)
cout << "Something went wrong!\n";
cout << "Done.\n";
return 0;
}
279
Natija:
This array is too small…
Done
KO'P MEROSNI E'LON QILISH
Yaratilgan obyekt bir nechta asosiy sinfning xususiyatlarini meros
qilib olishini ko'rsatish uchun yaratilgan sinf nomidan keyin “ : ”
qo'yiladi, so'ngra barcha asosiy sinflarning nomlari vergul bilan
ko'rsatiladi.
1-misol:
class Pegasus: public Horse, public Bird
2-misol:
class Schnoodle: public Schnauzer, public Poodle
Ikki asosiy sinf 22.1-rasmda ko'rsatilgandek pegasus obyektini
qurishda ishtirok etadilar.
280
Listing 22.3. Ko'p merosda obyektlarni yaratish
#include <iostream>
using namespace std;
typedef int HANDS;
enum COLOR { Red, Green, Blue, Yellow, White, Black, Brown };
class Horse
{public:
Horse(COLOR color, HANDS height);
virtual ~Horse() { cout << "Horse destructor...\n"; }
virtual void Whinny()const { cout << "Whinny!..."; }
virtual HANDS GetHeight() const { return itsHeight; }
virtual COLOR GetColor() const {return itsColor; }
private:
HANDS itsHeight;
COLOR itsColor;
};
Horse::Horse(COLOR color, HANDS height):
itsColor(color), itsHeight(height)
{cout << "Horse constructor...\n";}
class Bird
{public:
Bird(COLOR color, bool migrates);
virtual ~Bird() { cout << "Bird destructor...\n"; }
virtual void Chirp()const { cout << "Chirp..."; }
virtual void Fly()const
{cout << "I can fly! I can fly! I can fly! ";}
virtual COLOR GetColor()const { return itsColor; }
virtual bool GetMigration() const { return itsMigration; }
private:
COLOR itsColor;
bool itsMigration;
} ;
Bird::Bird(COLOR color, bool migrates):
itsColor(color), itsMigration(migrates)
{cout << "Bird constructor…\n";}
class Pegasus : public Horse, public Bird
{public:
void Chirp()const { Whinny(); }
Pegasus(COLOR, HANDS, bool, long);
~Pegasus() { cout << "Pegasus destructor\n";}
virtual long GetNumberBelievers() const
{return itsNumberBelievers;}
private:
long itsNumberBelievers;
};
Pegasus:: Pegasus(
COLOR aColor,
HANDS height,
bool migrates,
long NumBelieve):
Horse(aColor, height),
281
Bird(aColor, migrates),
itsNumberBelievers(NumBelieve)
{cout << "Pegasus constructor\n";}
int main()
{
Pegasus *pPeg = new Pegasus(Red, 5, true, 10);
pPeg->Fly();
pPeg->Whinny();
cout << "\nYour Pegasus is " << pPeg->GetHeight();
cout << "hands tall and ";
if (pPeg->GetMigration())
cout << "it does migrate.";
else
cout << "it does not migrate.";
cout << " nA total of " << pPeg->GetNumberBelievers();
cout << " people believe it exists.\n";
delete pPeg;
return 0;}
Natija:
Horse constructor…
Bird constructor…
Pegasus constructor…
I can fly! I can fly! I can fly! Whinny!…
Your Pegasus is 5 hands tall and it does migrate.
A total of 10 people believe it exists.
Pegasus destructor…
Bird destructor…
Horse destructor…
282
Agar Pegasus sinfida bu funksiya almashtirilsa, muammo o'z-
o'zidan hal qilinadi, chunki bu holda Pegasus sinfining a'zo funksiyasi
chaqiriladi:
virtual COLOR GetColor()const { return Horse::GetColor(); }
Agar boshqa sinf usulidan foydalanish zarurati tug'ilsa, unda
quyidagi ifoda bilan unga murojaat qilish xato bo'lmaydi.
COLOR currentColor = pPeg->Bird:: GetColor():
283
Animal(int);
virtual ~Animal() { cout << "Animal destructor...\n"; }
virtual int GetAge() const { return itsAge; }
virtual void SetAge(int age) { itsAge = age; }
private:
int itsAge;
};
Animal::Animal(int age):
itsAge(age)
{cout << "Animal constructor...\n";}
class Horse : public Animal
{public:
Horse(COLOR color, HANDS height, int age);
virtual ~Horse() { cout << "Horse destructor...\n"; }
virtual void Whinny()const { cout << "Whinny!..." ;}
virtual HANDS GetHeight() const { return itsHeight; }
virtual COLOR GetColor() const { return itsColor; }
protected:
HANDS itsHeight;
COLOR itsColor;
};
Horse::Horse(COLOR color, HANDS height, int age):
Animal(age),
itsColor(color),itsHeight(height)
{cout << "Horse constructor...\n";}
class Bird : public Animal
{
public:
Bird(COLOR color, bool migrates, int age);
virtual ~Bird() { cout << "Bird destructor...\n"; }
virtual void Chirp()const { cout << "Chirp..."; }
virtual void Fly()const
{ cout << "I can fly! I can fly! I can fly! ";}
virtual COLOR GetColor()const { return itsColor; }
virtual bool GetMigration() const { return itsMigration; }
protected:
COLOR itsColor;
bool itsMigration;
};
Bird::Bird(COLOR color, bool migrates, int age):
Animal(age),
itsColor(color), itsMigration(migrates)
{cout << "Bird constructor\n";}
class Pegasus : public Horse, public Bird
{public:
void Chirp()const { Whinny(); }
Pegasus(COLOR, HANDS, bool, long, int);
virtual ~Pegasus() { cout << "Pegasus destructor\n";}
virtual long GetNumberBelievers() const
{ return itsNumberBelievers; }
virtual COLOR GetColor()const { return Horse::itsColor; }
284
virtual int GetAge() const { return Horse::GetAge(); }
private:
long itsNumberBelievers;
};
Pegasus::Pegasus(
COLOR aColor,
HANDS height,
bool migrates,
long NumBelieve,
int age):
Horse(aColor, height,age),
Bird(aColor, migrates,age),
itsNumberBelievers(NumBelieve)
{cout << "Pegasus constructor...\n";}
int main(){
Pegasus *pPeg = new Pegasus(Red, 5, true, 10, 2);
int age = pPeg->GetAge();
cout << "This pegasus is " << age << " years old.\n";
delete pPeg;
return 0;}
Natija:
Animal constructor…
Horse constructor…
Animal constructor…
Bird constructor…
Pegasus constructor…
This pegasus is 2 years old.
Pegasus destructor…
Bird destructor…
Animal destructor…
Horse destructor...
Animal destructor…
VIRTUAL MEROS
Listing 22.4 noaniqlik muammosini hal qildi, ya'ni Pegasus sinf
obyektida GetAge() funksiyasi qaysi asosiy sinfdan meros bo'lib
o'tganini aniqlab berdi. Ammo, aslida, bu usul bitta umumiy Animal
asosiy sinfidan meros qilib olinadi.
C++ da, rasmda ko'rsatilgandek, biz bir xil nomdagi ikkita sinf
bilan ishlamayotganimizni ko'rsatish imkoniyati mavjud.
285
22.3-rasm Virtual meros
Odatda, sinf konstruktori faqat asosiy sinfning o'ziga xos
o'zgaruvchilari va a'zo o'zgaruvchilarini ishga tushiradi. Agar virtual
meros ishlatilsa, ushbu qoidadan istisno qilinadi. Asosiy asosiy sinf
o'zgaruvchilari undan kelib chiqadigan sinflarning konstruktorlari
tomonidan emas, balki sinflar iyerarxiyasida bo'lganlar tomonidan
ishga tushiriladi. Shuning uchun Animal sinfi Horse va Bird sinflar
tomonidan emas, balki Pegasus sinf obyekti tomonidan ishga
tushiriladi.
Horse va Bird class konstruktorlari, shuningdek, Animal asosiy
sinf initsializatsiya buyruqlarini o'z ichiga oladi, ammo Pegasus
obyektini yaratishda ushbu initsializatsiya ma'lum bir sinf konstruktori
tomonidan amalga oshiriladi.
Listing 22.5-bu 22.4 Listingi dasturiy ta'minot kodi bo'lib, u virtual
merosdan foydalanish mumkin bo'lgan tarzda qayta yozilgan.
Listing 22.5. Virtual merosdan foydalanish misoli
# include<iostream>
using namespace std;
typedef int HANDS;
enum COLOR{ red, green, blue, yellow, white, black, brown };
class Animal
{ public:
Animal(int);
virtual ~Animal() {"animal destructor...\n";}
virtual int GetAge() const{ return itsAge;}
virtual void SetAge(int age) {itsAge=age;}
private:
int itsAge; } ;
Animal::Animal(int age):
itsAge(age)
286
{ cout<<"Animal constructor...\n"; }
class Horse:virtual public Animal
{ public:
Horse (COLOR color, HANDS height, int age);
virtual ~Horse() { cout<<"Horse destructor...\n";}
virtual void Whinny () const { cout<<"Whinny!...";}
virtual HANDS GetHeight()const { return itsHeight;}
virtual COLOR GetColor() const { return itsColor;}
protected:
HANDS itsHeight;
COLOR itsColor; };
Horse::Horse(COLOR color, HANDS height, int age):
Animal(age),itsColor(color),itsHeight(height)
{ cout<<"Horse constructor...\n"; }
class Bird:virtual public Animal
{ public:
Bird(COLOR color, bool migrates, int age);
virtual ~Bird()
{ cout<<"Bird destructor...\n"
}
virtual void Chirp() const{ cout<<"Chirp...";}
virtual void Fly() const
{ cout<<"I can fly! I can fly! ;I can fly!"; }
virtual COLOR GetColor() const { cout<<itsMigration;}
protected:
COLOR itsColor;
bool itsMigration; };
Bird::Bird(COLOR color, bool migrates, int age):
Animal (age),itsColor(color), itsMigration(migrates)
{ cout<<"bird constructor...\n"; }
class Pegasus: public Horse, public Bird
{ public:
void Chirp() const{Whinny(); }
Pegasus(COLOR, HANDS, bool, long, int);
virtual ~Pegasus() { cout <<"Pegasus
destructor...\n";}
virtual long GetNumberBelievers() const
{return itsNumberBelievers;}
virtual COLOR GetColor() const { return Horse::
itsColor;}
private:
long itsNumberBelievers; };
Pegasus::Pegasus(COLOR aColor,HANDS height, bool
migrates,
long NumBelieve,int age):
Horse(aColor, height, age),
Bird(aColor, migrates, age),
Animal(age), itsNumberBelievers(NumBelieve)
{ cout<<"Pegasus constructor...\n"; }
int main()
{ Pegasus *pPeg= new Pegasus(red, 5, true, 10, 2);
287
int age=pPeg->GetAge();
cout<<"This pegasus is"<<age<<"years old.\n";
delete pPeg;
return 0; }
Agar siz dasturingizda bir nechta merosdan foydalanishga qaror
qilsangiz, shuni ta'kidlash kerakki, dasturni disk raskadrovka qilishda
muammolar paydo bo‘lishi mumkin.
Olingan sinflar asosiy sinfni yagona manba sifatida ko'rishiga
ishonch hosil qilish uchun merosning virtualligi barcha oraliq sinflarda
ko'rsatilishi kerak.
1-misol:
class Horse virtual public Animal
class Bird : virtual public Animal
class Pegasus : public Horse, public Bird
2-misol:
class Schnauzer : virtual public Dog
class Poodle : virtual public Dog
class Schnoodle : public Schnauzer, public Poodle
Tavsiya etiladi!
Sinfda turli sinflarda e'lon qilingan ma'lumotlar va usullarni
qo'llash zarur bo'lgan hollarda bir nechta merosdan foydalaning.
Usul yoki ma'lumotlar meros manbasining noaniqligi bilan
bog'liq muammolarni iloji boricha oqlangan tarzda hal qilish uchun
virtual merosdan foydalaning.
ATRIBUTLAR SINFI
-bu bir qator usullarga kirishni ochadigan, ammo
hech qanday ma'lumotni o'z ichiga olmaydigan (yoki hech bo'lmaganda
minimal ma'lumotlar to'plamini o'z ichiga olgan) sinf.
Atribut sinflari funksiyalari meros orqali olingan sinflarga
o'tkaziladi. Sinf atributlari va boshqa sinflar o'rtasidagi yagona farq
shundaki, ular deyarli hech qanday ma'lumotni o'z ichiga olmaydi.
Atribut sinflaridan foydalanish, shuningdek, boshqa asosiy sinflardan
meros bo'lib qolgan ma'lumotlarning merosxo‘r sinfida ishlatilganda
noaniqlik ehtimolini kamaytiradi.
Masalan, Horse sinfi ikkita sinfdan - Animal va Displayabledan
kelib chiqqan deb taxmin qiling, ikkinchisi faqat yangi funksiyalarni
qo'shadi, ammo ma'lumotlarni o'z ichiga olmaydi. Bunday holda, Horse
sinfining barcha meros qilib olingan ma'lumotlari faqat bitta asosiy
288
Animal sinfidan kelib chiqadi va funksiyalar ikkala sinfdan ham meros
bo'lib o'tadi.
(sapability class) ba'zan Mixin (mixin) deb ham
ataladi. n.
MAVHUM MA'LUMOTLAR TURLARI
Obyektni dasturlashda ko'pincha mantiqiy bog'liq sinflarning
iyerarxiyalari yaratiladi. Masalan, Rectangle va Circle sinflaridan kelib
chiqqan rasm sinfini tasavvur qiling. Keyin Square sinf to'rtburchaklar
xususiy turi sifatida to'rtburchaklar sinfidan ishlab chiqariladi.
Har bir olingan sinfda Draw(), GetArea() va boshqa usullar o‘zaro
bog`liq. Shape sinfi va undan olingan Rectangle va Circle bilan dastur
22.6 Listingida ko'rsatilgan.
Listing 22.6. Shape oilasi sinflari
#include<iostream>
using namespace std;
class Shape{
public:
Shape(){ }
virtual ~Shape(){ }
virtual long GetArea() {return -1; }
virtual long GetPerim() {return -1; }
virtual void Draw() { }
private:};
class Circle : public Shape
{ public:
Circle(int radius):itsRadius(radius){}
~Circle(){}
long GetArea(){ return 3* itsRadius*itsRadius;}
long Getperim(){ return 6*itsRadius;}
void Draw();
private:
int itsRadius;
int itsCircumference;};
void Circle::Draw() { cout<<"Circle drawing routine
here!\n";}
class Rectangle:public Shape
{ public:
Rectangle(int len, int width):
itsLength(len),itsWidth(width){}
virtual~Rectangle(){}
long GetArea() {return itsLength+2*itsWidth; }
long GetPerim(){ return 2*itsLength+2*itsWidth;}
virtual int GetLength() { return itsLength;}
virtual int GetWidth() { return itsWidth;}
void Draw();
private:
int itsWidth;
int itsLength;};
void Rectangle::Draw()
289
{ for(int i=0;i<itsLength; i++){
for(int j=0;j<itsWidth; j++)
cout<<"x";
cout<<"\n"; } }
class Square: public Rectangle
{ public:
Square(int len);
Square(int len,int width);
~Square(){}
long GetPerim(){return 4*GetLength();}};
Square::Square(int len):
Rectangle(len,len) {}
Square::Square(int len,int width):
Rectangle(len,width)
{if (GetLength() !=GetWidth())
cout<<"Error, not a square...a Rectangle??\n"; }
int main() {
int choice;
bool fQuit=false;
Shape*sp;
while (! fQuit) {
cout<<"(1)Circle (2)Rectangle (3)Square (0)Quit:";
cin>>choice;
switch (choice) {
case 0: fQuit=true; break;
case 1: sp=new Circle(5); break;
case 2: sp=new Rectangle(4,6); break;
case 3: sp=new Square(5); break;
default: cout<<"Please enter a number between 0 and 3"<<endl;
continue; break; }
if(! fQuit)
sp->Draw();
delete sp;
cout<<"\n"; }
return 0; }
290
Sinfni mavhum ma'lumotlar turi deb e'lon qilish uchun unga bir
yoki bir nechta toza virtual funksiyalarni qo'shish kifoya. Buning uchun
funksiyani e'lon qilgandan so'ng - 0 ni qo'shishingiz kerak, masalan:
class Shape
virtual void Draw () = 0; / / sof virtual funksiya
TEZ-TEZ VIRTUAL FUNKSIYALARNI BAJARISH
Odatda sof virtual funksiyalar mavhum asosiy sinfda e'lon qilinadi
va bajarilmaydi. Mavhum asosiy sinf obyektini yaratish mumkin
emasligi sababli, odatda toza virtual funksiyani bajarishga hojat yo'q.
Funksiya ushbu sinf obyektini yaratish uchun zarur bo'lgan Circle
sinfida almashtiriladi, ammo almashtirilgan funksiya prototipi asosiy
sinfdan sof virtual funksiyani chaqiradi. Ushbu vosita sinf usullarining
qo'shimcha funksiyalariga erishish uchun ishlatiladi.
Ushbu misolda qo'shimcha funksiya oddiy xabarni namoyish
qilishdan iborat. Haqiqiy dasturda sof virtual funksiya juda murakkab
dastur kodini o'z ichiga olishi mumkin.
Shunday qilib, hayvonlar sinfida siz Eat (), Sleep (), Move() va
Reproduce() usullarini sof virtual funksiyalar deb e'lon qilishingiz
mumkin. Keyin Animal sinfidan Mammal va Fish sinflari kelib chiqadi.
Barcha sutemizuvchilar deyarli bir xil tarzda ko'payadi degan
fikrga asoslanib, Mammal sinfida Reproduce() usulini oddiyga
aylantirish mantiqan to'g'ri keladi, shu bilan birga Eat (), Sleep() va
Move() usullarini sof virtual funksiyalar bo‘lib qoladi.
Keyin Mammal sinfidan Dog sinfi kelib chiqadi, unda Dog sinf
obyektlarini yaratish imkoniyatiga ega bo‘lish uchun qolgan uchta sof
virtual funksiyani almashtirish kerak.
Sinfni mavhum deb e'lon qilishni talab qiladigan qoidalar yo'q.
Dasturchi ushbu sinf dasturda qanday rol o'ynashi asosida mavhum
ma'lumotlar turini yaratishga qaror qiladi. Shunday qilib, agar siz
virtual fermani yoki hayvonot bog'ini modellashtirmoqchi bo'lsangiz,
unda hayvonlar sinfini mavhum deb e'lon qilish va obyektlarni yaratish
uchun undan Dog kabi boshqa sinflarni ishlab chiqarish mantiqan to'g'ri
keladi. Agar siz virtual Dogni modellashtirmoqchi bo'lsangiz, endi Dog
sinfi mavhum bo'ladi, undan turli xil Dog zotlarini ifodalovchi kichik
sinflar kelib chiqishi mumkin. Mavhum sinf darajalari soni haqiqiy
obyekt yoki hodisani qanchalik batafsil modellashtirishni
xohlayotganingizga qarab tanlanishi kerak.
291
Tavsiya etiladi!
Barcha olingan sinflar uchun umumiy interfeys yaratish
uchun mavhum ma'lumotlar turlaridan foydalaning.
Olingan sinflarda barcha sof virtual funksiyalarni
almashtirishga ishonch hosil qiling.
Olingan sinflarda almashtirilishi kerak bo'lgan barcha
funksiyalarni sof virtual funksiyalar deb e'lon qiling.
Tavsiya etilmaydi!
Mavhum sinf obyektini yaratishga urinmang.
MAVHUM SINFLARDAN FOYDALANISH
So'nggi paytlarda C++ dasturlashda mavhum mantiqiy tuzilmalarni
yaratish kontsepsiyasi faol qo'llanilmoqda. Bunday loyihalashlar
yordamida siz ko'plab umumiy vazifalar uchun yechimlarni topishingiz
va o'qish va hujjatlashtirish oson bo'lgan dasturlarni yaratishingiz
mumkin. Sinf merosidan foydalangan holda mantiqiy tuzilmani
yaratish misolini ko'rib chiqing.
Tasavvur qiling, soniyalarni hisoblay oladigan taymer sinfini
yaratishingiz kerak. Bunday sinfda itsseconds butun sonli
o'zgaruvchisi, shuningdek itsseconds o'zgaruvchisini ko'paytiradigan
usul bo‘lishi mumkin. Endi dastur itsseconds o'zgaruvchisining har bir
o'zgarishini kuzatishi va xabar qilishi kerak deb taxmin qiling. Birinchi
yechim bu Timer sinfiga a'zo o'zgaruvchining o'zgarishi to'g'risida
xabar berish usulini qo'shish. Ammo mantiqan bu mutlaqo to'g'ri emas,
chunki bildirishnoma dasturi juda murakkab bo‘lishi mumkin va aslida
vaqtni hisoblash dasturining mantiqiy qismi emas.
O'zgaruvchining o'zgarishini kuzatish va xabardor qilish dasturini
mavhum sinf sifatida ko'rib chiqarish mantiqan to'g'ri keladi, bu vaqtni
hisoblash dasturi bilan ham, vaqti-vaqti bilan o'zgarib turadigan
o'zgaruvchilar bilan har qanday boshqa dastur bilan ham teng ravishda
ishlatilishi mumkin.
Shunday qilib, eng yaxshi yechim sof virtual Update () funksiyasi
bilan Observer brauzerining mavhum sinfini yaratishdir. Endi biz
ikkinchi mavhum sinfni yaratamiz. U Observer sinfidagi obyektlar
qatorini o'z ichiga oladi. Bundan tashqari, u ikkita qo'shimcha usulni
e'lon qiladi:
Observer sinfidagi obyektlarni Listingdan o'tkazadigan Register ()
va ko'rsatilgan o'zgaruvchining o'zgarishini kuzatadigan Notify ().
292
Nihoyat, bir vaqtning o'zida ikkita asosiy sinfdan meros bo'lib
o'tgan yangi ObserverTimer sinfini yaratish mumkin - Observer va
Timer bu vaqtni hisoblash va hisobot berish imkoniyatlarini
birlashtiradi.
KO'P MEROS, MAVHUM MA'LUMOTLAR TURLARI
Ko'pgina dasturchilar Java tilining asosi C++ekanligini bilishadi.
Java dasturlash tilida ishlovchilar nuqtai nazaridan, bir nechta meros
tomonidan taqdim etilgan barcha imkoniyatlarning 90 foizini interfeys
orqali olish mumkin. Java terminologiyasidagi interfeys mavhum
ma'lumotlar turiga o'xshash narsadir, chunki u faqat olingan sinflarda
amalga oshirilishi mumkin bo'lgan funksiyalarni ham belgilaydi.
Ammo yangi sinflar to'g'ridan-to'g'ri interfeysdan kelib chiqmaydi.
Sinflar boshqa sinflardan kelib chiqadi va ularda interfeys funksiyalari
uzatiladi, bu ko‘p merosga o'xshaydi. Shunday qilib, mavhum sinflar
va ko'p merosning birlashishi atribut sinflarining analogini keltirib
chiqardi, natijada ko'p merosda bo'lgani kabi dasturiy kodlarning
haddan tashqari murakkablashuvidan qochish mumkin edi. Bundan
tashqari, interfeyslarda bajariladigan funksiyalar yoki a'zo
o'zgaruvchilar mavjud emasligi sababli, virtual merosga ehtiyoj
qolmaydi.
Ushbu o'zgarishlarning qanchalik qulay yoki maqsadga
muvofiqligi ma'lum bir dasturchining odatlariga bog'liq. Qanday
bo'lmasin, Agar siz C++ tilining ko'p meros va mavhum ma'lumotlar
turlarini yaxshi tushunsangiz, bu Javada amalga oshirilgan so'nggi
yutuqlar va dasturlash tendentsiyalarini o'rganish va o'zlashtirishda
yaxshi asos bo'lib xizmat qiladi.
Nazorat savollari va topshiriqlar:
1. Obyekt tipi nima?
2. Aytaylik, qavariq burchakli to'rtburchaklar yaratish uchun ikkita
asosiy sinfdan - Rectangle va Rounddan meros qilib olingan roundrect
sinfidan foydalaniladi, ular o'z navbatida umumiy Shape sinfidan meros
qilib olingan. Bitta roundrect sinf obyektini yaratishda qancha Shape
sinf obyektlari yaratiladi?
3. Agar Horse va Bird sinflari Animal sinfidan public spetsifikator
sifatida meros bo'lib o'tgan bo'lsa, ushbu sinflarning konstruktorlari
Animal sinf konstruktorini ishga tushiradimi? Agar Pegasus sinfi bir
vaqtning o'zida ikkita sinfdan, Horse va Birddan meros bo'lib o'tgan
bo'lsa, unda hayvonlar sinfining konstruktori qanday boshlanadi?
293
4. Jetplane (reaktiv samolyot) sinfini ikkita asosiy sinfdan - Rocket
(raketa) va Airplane (samolyot) dan meros qilib oling.
5. Avtomobil sinfidan yengil avtomobil (yo'lovchi avtomobili) va
avtobus merosxo‘r sinflarini yaratish uchun dastur yozing. Asosiy
Avtomobil sinfini ikkita sof virtual funksiyaga ega mavhum
ma'lumotlar tipi sifatida e'lon qiling. Yengil avtomobil va avtobus
sinflari mavhum bo'lmasligi kerak.
294
23-MAVZU. C++ DA MAVHUM(ABSTRACT) SINFLAR.
Sof virtual funksiyalar
Mavhum ma'lumotlar turlari
Abstraktsiyalarning murakkab iyerarxiyasi
Mavhum sinflardan foydalanish
296
// Class A is an abstract class
// static_cast<A>(b);
}
297
Nazorat savollari va topshiriqlar:
1. C++ da interfeys mavhum sinfidan qanday farq qiladi?
2. Sinf interfeysi nima?
3. Mavhum sinf yoki interfeys, qaysidan foydalanish yaxshiroq?
4. Sinf va mavhum sinf o'rtasidagi farq nima?
5. s fayl nomi va haqiqiy a, d sonlari berilgan. Tashqi faylga 1-hadi
a ga ayirmasi d ga teng bo‘lgan arifmetik progressiyaning dastlabki 10
ta hadining qiymatlari yozilsin.
6. 4 ta faylning nomi berilgan. Joriy katalogda joylashgan shu
nomlar bilan berilgan fayllar soni topilsin.
7. Butun sonli fayl nomi berilgan. Fayldagi elementlar soni
topilsin. Agar bunday nomdagi fayl topilmasa – 1 chiqarilsin.
8. Haqiqiy sonli fayl berilgan. 2 ta yangi fayl tuzilsin: 1-faylga
berilgan fayldagi toq nomerdagi sonlar, 2-faylga esa berilgan fayldagi
juft nomerdagi sonlar chop etilsin.
9. Haqiqiy sonli fayl berilgan. 2 ta yangi fayl tuzilsin: 1-faylga
berilgan fayldagi juft nomerdagi sonlar, 2-faylga esa berilgan fayldagi
toq nomerdagi sonlar chop etilsin.
298
24-MAVZU. C++ DA TRY, CATCH.
Favqulodda vaziyatlar
Istisnolar qanday ushlanadi va qayta ishlanadi
Istisnolarni meros qilib olish
Xatolarni kuzatish va tuzatishning umumiy tuzilmasida
istisnolardan foydalanish
Ushbu kitobda keltirilgan dastur kodi illyustratsion maqsadlarda
yaratilgan. Sizni dasturning ma'lum bir qismida keltirilgan asosiy
dasturlash nuqtalaridan chalg'itmaslik uchun biz mumkin bo'lgan
xatolar haqida gapirmadik. Haqiqiy dasturlar, albatta, mumkin bo'lgan
favqulodda vaziyatlarni ta'minlashi kerak.
XATOLAR VA "ESKI" KOD
Afsuski, barcha dasturchilar xato qilishadi. Dastur qanchalik katta
bo'lsa, unda xatolar paydo bo‘lishi ehtimoli shunchalik yuqori bo'ladi,
ularning aksariyati hozircha e'tiborga olinmaydi va bozorga chiqarilgan
yakuniy dasturiy mahsulotga tushadi. Ushbu haqiqatni qabul qilish
qiyin, shuning uchun ishonchli, xatosiz dasturlarni yaratish har bir
dasturchi uchun birinchi sonli vazifa bo‘lishi kerak.
Dasturiy ta'minot sanoatidagi eng dolzarb muammolardan biri bu
xatolar bo‘lgan dastur kodidir. Odatda dasturlash bilan bog'liq ko'plab
ishlarda eng katta xarajatlar dasturlarni sinovdan o'tkazish va xatolarni
tuzatishdir. Qisqa vaqt ichida va arzon narxlarda mustahkam, ishonchli
va muammosiz dasturlarni yaratish muammosini hal qilgan kishi butun
dasturiy mahsulotlar sanoatida inqilob qiladi.
Dasturlardagi barcha xatolarni bir necha guruhga bo‘lish mumkin.
dasturni bajarish algoritmining yetarli
darajada ishlab chiqilmagan mantig'idan kelib chiqadi.
- sintaktik xatolar, ya'ni noto'g'ri idioma, funksiya yoki
tuzilmadan foydalanish. Ushbu ikki turdagi xatolar eng keng tarqalgan,
shuning uchun ular dasturchilar diqqat markazida.
Nazariya va amaliyot shuni isbotladiki, keyinchalik rivojlanish
jarayonida muammo aniqlansa, uni yo'q qilish shunchalik qimmatga
tushadi. Ma'lum bo‘lishicha, dasturlardagi muammolar yoki xatolar,
agar ularning paydo bo‘lishining oldini olish uchun o'z vaqtida choralar
ko'rilsa, kompaniyaga eng arzon bo'ladi. Kompilyator tomonidan tan
olingan xatolar ham juda qimmatga tushmaydi. C++ tili standartlari
ishlab chiquvchilarni dasturni kompilyatsiya qilish bosqichida iloji
299
boricha ko'proq xatolarni aniqlay oladigan kompilyatorlarni yaratishga
majbur qiladi.
Mantiqiy yoki sintaktik xatolardan ham kattaroq muammo bu
dasturlarning yetarli darajada barqaror emasligi, ya'ni agar
foydalanuvchi taqdim etilgan ma'lumotlarni kiritsa, dastur yaxshi
ishlaydi, ammo xato bilan, masalan, son o'rniga matn kiritilsa, u
ishlamay qoladi.
Dasturlarning barqarorligini oshirish uchun dasturchilar
kutilmagan vaziyatlarning barcha variantlarini oldini olishga
intilishadi. Foydalanuvchi tomonidan kiritilgan nostandart
ma'lumotlarni olishdan tortib, kompyuter xotirasini to‘ldirishgacha
bo'lgan har qanday kutilmagan hodisalarni yengish mumkin bo'lgan
dastur bo‘lib hisoblanadi.
Dasturiy ta'minot kodining noto'g'ri sintaksisidan kelib chiqadigan
xatolarni, dasturchi muammoni noto'g'ri talqin qilgani yoki noto'g'ri hal
qilganligi sababli yuzaga keladigan mantiqiy xatolarni va bashorat
qilinadigan muammolar tufayli yuzaga keladigan favqulodda
vaziyatlarni, masalan, resurslarning ziddiyatlari bilan bog'liq (xotira
yoki disk maydoni yetishmasligini anglatadi).
ISTISNO HOLATLAR
Sintaksis xatolarini aniqlash uchun dasturchilar o'rnatilgan
kompilyator vositalaridan foydalanadilar va dasturlarga turli xil xato
“tuzoq”larini qo'shadilar. Mantiqiy xatolarni aniqlash uchun loyihalash
yechimlarini tanqidiy tahlil qilish va dasturiy mahsulotni har
tomonlama sinovdan o'tkazish amalga oshiriladi.
Biroq, biror bir dasturda istisno holatlar yuzaga kelishi ehtimolini
bartaraf etish mumkin emas. Dasturchi qila oladigan yagona narsa bu
dasturni ularning paydo bo‘lishiga tayyorlashdir. Masalan, dasturni
bajarish paytida kompyuter xotirasining to'lib ketishini oldini olish
uchun dasturlash vositalaridan foydalanish mumkin emas, ammo dastur
ushbu vaziyatda o'zini qanday tutishi dasturchiga bog'liq.
Siz quyidagi dastur javob variantlarini tanlashingiz mumkin:
dasturni favqulodda to'xtashga olib boring;
foydalanuvchini nima bo'lganligi haqida xabardor qiling va
dasturdan to'g'ri chiqing;
foydalanuvchini xabardor qiling va unga dasturning ish
holatini tiklashga va ishlashni davom ettirishga ruxsat bering;
300
vaqtinchalik yechimni tanlang va foydalanuvchini bezovta
qilmasdan dasturni davom ettiring.
Oxirgi variant, ya'ni vaqtinchalik yechimni tanlash, albatta,
dasturning favqulodda to'xtashidan afzalroqdir. Ushbu parametr har bir
dasturda zarur yoki hatto kerakli bo'lmasa-da, shunga qaramay, barcha
favqulodda vaziyatlarni mustaqil ravishda, avtomatik ravishda va
ishlashni davom ettiradigan kodni yozishga arziydi.
C++ tili dastur davomida yuzaga kelishi mumkin bo'lgan barcha
favqulodda vaziyatlarni kuzatish uchun xavfsiz, integratsiyalashgan
usullarni taqdim etadi.
"ESKIRGAN" KOD HAQIDA BIR NECHA SO'Z
Dasturiy mahsulot vaqt o'tishi bilan eskirish mumkinligi
isbotlangan. Buni stolingiz ustida anchadan beri turgan olmaga
qiyoslash mumkin. Bu hodisa deyarli har qanday kodda yashirin ichki
xatolar mavjud bo'lib, ularga eski dasturning yangi kompyuter
dasturlari va dasturiy ta'minot muhitiga mos kelmasligi qo'shiladi.
Mukammal yozilgan va yaxshi dastur juda tez foydalanuvchi e'tiborini
jalb qilmaydigan narsalarga aylanishi mumkin.
Yuzaga kelgan xatolarni tezda tuzatish va dasturni joriy kun
talablariga muvofiq modernizatsiya qilish uchun siz nafaqat siz, balki
boshqa har qanday dasturchi ham bir muncha vaqt o'tgach uni tushunish
uchun dastur kodini yozishingiz kerak.
ESLATMA: "Eskirgan" kod-bu dasturchilar tomonidan yaxshi
dasturlarning to'satdan ishonchsiz va samarasiz bo'lib qolishini
tushuntirish uchun yaratilgan hazil atamasi. Bunday "eski kod" dan
himoya qilish uchun siz kodni yozishingiz kerak, shunda uning
ishlashini o'zingiz saqlab qolish oson bo'ladi.
ISTISNOLAR
C++ da - bu muammo yuzaga kelgan kod maydonidan
ushbu muammo ko'rib chiqiladigan kod qismiga uzatiladigan obyekt.
Istisno turi kodning qaysi sohasi muammoni hal qilishini va agar
mavjud bo'lsa, uzatilgan obyektning tarkibi foydalanuvchi bilan fikr-
mulohaza uchun qanday ishlatilishini aniqlaydi.
Istisnolardan foydalanishning asosiy g'oyasi juda oddiy.
Resurslarning haqiqiy taqsimlanishi (masalan, xotira taqsimoti yoki
faylni yozib olish) odatda dasturda past darajada amalga oshiriladi.
301
ISTISNOLAR QANDAY ISHLATILADI?
Muammoga olib kelishi mumkin bo'lgan kod parchalarini
joylashtirish uchun try bloklari yaratiladi, masalan:
try
{ SomeDangerousFunction(); }
Sinov bloklarida yuzaga keladigan istisnolar catch bloklarida qayta
ishlanadi, masalan:
try SomeDangerousFunction();
catch(OutOfMemory)
// ba'zi harakatlarni amalga oshirish catch (FileNotFound)
// biz boshqa harakatlar qilamiz
Quyida istisnolardan foydalanishning asosiy tamoyillari
keltirilgan.
1. Istisno vaziyatni keltirib chiqarishi mumkin bo'lgan amal
boshlanadigan dastur maydonlarini aniqlang va ularni sinab ko'rish
bloklariga joylashtiring.
2. Istisnolarni ushlab qolish, ajratilgan xotirani tozalash va
foydalanuvchini tegishli ravishda xabardor qilish uchun catch
bloklarini yarating. 24.1 Listingida try va catch bloklaridan foydalanish
ko'rsatilgan.
-bu muammo haqida ma'lumot uzatish uchun
ishlatiladigan obyektlar.
-bu g'ayrioddiy vaziyatlarni keltirib chiqarishi mumkin
bo'lgan dastur qismlarini o'z ichiga olgan figurali qavs ichidagi blok.
-bu sinab ko'rish blokidan keyin keladigan va
istisnolarni qayta ishlash amalga oshiriladigan blok.
Agar favqulodda vaziyat yuzaga kelsa, boshqaruv joriy sinov
blokidan so'ng darhol catch blokiga o'tkaziladi.
ESLATMA: Ba'zi juda eski kompilyatorlar istisnolarni qayta
ishlashni qo'llab-quvvatlamaydi. Biroq, istisnolarni qayta ishlash ANSI
C++standartining bir qismidir. Kompilyatorlarning barcha zamonaviy
versiyalari ushbu imkoniyatni to'liq qo'llab-quvvatlaydi.
302
FAVQULODDA VAZIYATLARNI KUZATISH BLOKI
Ushbu blok kalit so'zidan keyin ochiladigan figurali qavs bilan
boshlanadigan ifodalar to'plamidir, yopuvchi figurali qavs bilan
tugaydi.
Misol:
try
Function();
{
istisno vaziyatlarni qayta ishlash birligi
}
Ushbu blok qatorlar to'plamidir, ularning har biri kalit so'zi
bilan boshlanadi, so'ngra qavs ichida istisno turi beriladi. Keyin
ochiladigan figurali qavs keladi. Catch bloki yopiladigan figurali qavs
bilan tugaydi.
Misol:
try
Function();
catch (OutOfMemory) // harakatni bajarish
{
}
TRY VA CATCH BLOKLARIDAN FOYDALANISH
Blokning joylashuvini aniqlashga urinayotganda, dasturda xotira
yoki boshqa manbalar qayerda taqsimlanishini aniqlang. Agar
qiymatlarni ruxsat etilgan chegaralardan tashqariga chiqarish, noto'g'ri
ma'lumotlarni kiritish va boshqalar bilan bog'liq xatolar bo'lsa, siz
boshqa yondashuvlardan foydalanishingiz kerak.
Istisno yaratilganda, murojaatlar to'plami tekshiriladi. Istisno har
bir ichki blok uchun murojaatlar to'plamiga o'tkaziladi. Stack o'tishi
bilan local obyektlar uchun destruktorlar chaqiriladi va bu
obyektlarning yo'q qilinishiga olib keladi.
Har bir harakat blokidan keyin bir yoki bir nechta catch bloklari
keladi. Agar yaratilgan istisno catch operatorlarining istisnolaridan
biriga to'g'ri kelsa, u holda ushbu operatorning blok kodi bajariladi.
Agar catch operatorlarining hech biri istisnoga mos kelmasa, Stack
o'tishi davom etadi.
Stack istisnosidan o'tishni bir tomonlama ko'chada sayohat qilish
bilan taqqoslash mumkin. Stack o'tishi bilan uning obyektlari yo'q
qilinadi. Orqaga yo'l yo'q. Agar istisno ushlanib qolsa va qayta ishlansa,
dastur ushbu istisnoni ushlab qolgan catch blokidan keyin ham davom
etadi.
303
Esda tutingki, agar favqulodda vaziyat yuzaga kelsa, dasturni
amalga oshirish u paydo bo'lgan joydan keyin emas, balki catch
blokidan keyin davom etadi.
BIR NECHTA CATCH OPERATORLARIDAN
FOYDALANISH
Ba'zi hollarda, bitta ifodani bajarish bir nechta istisno holatlar
bo‘lishi mumkin. Bunday holda, switch operatori bilan loyihalashga
o'xshash bir-birini ta'qib qiladigan bir nechta catch operatorlaridan
foydalanish kerak. Bunday holda, default operatorining ekvivalenti
(...) ifodasi bo'ladi, uni "hamma narsani ushlab turish"deb
tushunish kerak.
304
itsSize(size) {
if (size==0)
throw xZero();
if (size>30000)
throw xTooBig();
if (size<1)
throw xNegative();
if(size<10)
throw xTooSmall();
pType=new int[size];
for (int i=0; i<size; i++)
pType[i]=0; }
int& Array::operator[](int offSet) const {
int size=GetitsSize();
if(offSet>=0&& offSet<GetitsSize())
return pType[offSet];
throw xBoundary();
return pType[0]; }
int main() {
try {
Array intArray(0);
for(int j=0; j<100; j++)
{ intArray[j]=j;
cout<<"intArray["<<j<<"]okay...\n"; } }
catch (Array::xBoundary)
{ cout<<"Unable to process your input!\n"; }
catch (Array::xTooBig)
{ cout<<"This array is too big...\n"; }
catch (Array::xTooSmall)
{ cout<<"This array is too small...\n"; }
catch (Array::xZero)
{ cout<<"You asked for an array";
cout <<"of zero objects!\n"; }
catch(...)
{ cout<<"Somthing went wrong!\n"; }
cout<<"Done.\n";
return 0; }
Ko'pincha, dastur xatoga to'g'ri javob berishi uchun, yuzaga kelgan
istisno turidan ko'ra ko'proq narsani bilish foydalidir. Istisno sinflari
boshqa sinflar bilan bir xil.
ESLATMA: Istisnolar bilan ishlashda ularning mohiyatini yodda
tutish kerak. Agar siz OutOfMemory istisnosini yaratayotgan
bo'lsangiz, unda ushbu sinf konstruktori biror bir obyekt uchun xotira
ajratishga urinmasligi kerak.
Ushbu loyihalashlarning barchasini catch operatorlari bilan qo'lda
yozish juda zerikarli, ularning har biri o'z xabarlarini chiqarishi kerak.
305
Bundan tashqari, dastur hajmining oshishi bilan undagi xatolar ehtimoli
tezda oshadi.
ISTISNOLAR VA SHABLONLAR
Shablonlar bilan ishlashga mo'ljallangan istisnolarni yaratishda
ikkita yechim mavjud. Siz to'g'ridan-to'g'ri shablonda istisno
yaratishingiz mumkin, keyin ular shablonning har bir nusxasi uchun
mavjud bo'ladi yoki shablon prototipidan tashqarida yaratilgan istisno
sinflaridan foydalanishingiz mumkin.
Istisnolardan foydalanish faqat taxmin qilinadigan istisno
vaziyatlarni kuzatish bilan cheklanishi kerak, degan fikr bor, buning
uchun aslida istisnolar yaratilgan.
Istisnolardan foydalanish qanchalik to'g'ri ekanligini hal qilish
uchun quyidagi savollarga javob berishga harakat qiling: natijada dastur
osonlashadimi yoki aksincha, tushunish qiyinlashadimi; xatolar rostan
ham kamayadimi; bunday dasturni qo'llab-quvvatlash qiyinroq yoki
osonlashadimi? Albatta, ushbu savollarga obyektiv javob berish qiyin:
ko'p narsa dasturchining odatlari va subyektiv qarashlariga bog'liq, shu
sababli, ushbu savollar atrofida tortishuvlar paydo bo'ladi.
XATOLAR VA DASTURNI DISK RASKADROVKA
QILISH
Deyarli barcha zamonaviy rivojlanish muhitlari bir yoki bir nechta
o'rnatilgan samarali tuzatuvchilarni o'z ichiga oladi. Nosozliklarni
tuzatuvchidan foydalanishning asosiy g'oyasi quyidagicha: tuzatuvchi
dasturning dastur kodini dasturning alohida satrlari bajarilishini
kuzatish va xatolarni aniqlash uchun qulay rejimda yuklaydi va
bajaradi.
Barcha kompilyatorlar dasturlarni belgilar yordamida yoki ularsiz
kompilyatsiya qilishga imkon beradi. Belgilar bilan kompilyatsiya
qilish kompilyatorga dastur fayllarining dastur kodi va yaratilgan dastur
o'rtasidagi munosabatlarni o'rnatish zarurligini ko'rsatadi, shuning
uchun tuzatuvchi dasturingizdagi keyingi harakatga mos keladigan
dastur kodi qatorini ko'rsatishi mumkin.
Ko'pgina nosozliklarni tuzatuvchilar bilan ishlashda har bir
buyruqning ishlash natijalarini ko'rish uchun dastur kodi va ekran
chiqarishi o'rtasida almashish mumkin. Bundan tashqari, har qanday
o'zgaruvchining joriy qiymatini, shu gapdan sinf a'zolari
o'zgaruvchilarini va dastur ko'rsatgichlari tomonidan havola qilingan
dinamik almashinuv maydoni kataklaridagi qiymatlarni aniqlash,
306
shuningdek murakkab ma'lumotlar tuzilmalarini ko'rish imkoniyati
foydalidir. Nosozliklarni tuzatuvchilar dastur kodida to'xtash
nuqtalarini o'rnatish, o'zgaruvchilarning mos yozuvlar qiymatlarini
chiqarish, xotirani taqsimlash xususiyatlarini o'rganish va assembler
kodini ko'rish imkonini beradigan bir qator yordamchi dasturlarini
taqdim etadi.
TO'XTASH NUQTALARI
- bu tuzatuvchi uchun mo'ljallangan buyruqlar
va dastur belgilangan qatorni bajarishdan oldin to'xtashi kerakligini
anglatadi. Ushbu vosita dasturni to'xtash nuqtasi o'rnatilgan joyga
odatdagidek bajarish orqali disk raskadrovka paytida vaqtni tejashga
imkon beradi. Dasturning bajarilishini to'xtatgandan so'ng, siz
o'zgaruvchilarning joriy qiymatlarini tahlil qilishingiz yoki dasturni
bosqichma-bosqich davom ettirishingiz mumkin.
307
8. Agar ikkita catch operatori ishlatilsa, ulardan biri asosiy xabarga,
ikkinchisi esa hosilaga sozlangan bo'lsa, unda ular qanday tartibda
joylashtirilishi kerak?
9. Catch ( ... ) operatori nimani anglatadi?
10. To'xtash nuqtasi nima?
11. Oddiy istisnoni kuzatish va qayta ishlash uchun try blokini va
catch operatorini yozib oling.
12. 11-mashqda olingan istisnoga a'zo o'zgaruvchisi va kirish
usulini qo'shing va ularni catch operator blokida ishlating.
13. 12-mashqda olingan istisnodan yangi istisnoni meros qilib
oling. Catch operator blokini shunday o'zgartiringki, u ham lotin, ham
asosiy istisnolarni qayta ishlaydi.
14. Uch darajali funksiya chaqiruvini olish uchun 13-mashq kodini
o'zgartiring.
15. Xatolar: quyidagi koddagi xatolikni toping?
#include "string"
// qatorlar sinfi
class xOutOfMemory
{
public:
xOutOfMemory()( theMsg = new char[20];
stropy(theMsg, "error in memory");}
xOutOfMemory(){ delete [] theMsg;
cout<< "Memory restored. " << endl; }
char * Message() { return theMsg;
private:
char * theMsg;
main()
{
try
{
char * var = new char;
if ( var == 0 )
{
x0ut0fMemory * px =
new x0ut0fMemory;
throw px;
}
308
}
catch( x0utOfMemory * theException )
cout << theException->Message() <<endl;
delete theException;
return 0;}
309
NAZORAT UCHUN TEST SAVOLLARI
1. Identifikator nima?
a) katta va kichik lotin harflari, sonlar va tag chiziq (‘_’) belgilaridan
tashkil topgan va sondan boshlanmaydigan belgilar ketma-ketligi
b) katta va kichik lotin harflari, sonlar va tag chiziq (‘_’) belgilaridan
tashkil topgan va faqat sondan boshlanuvchi belgilar ketma-ketligi
c) katta va kichik lotin harflaridan tashkil topgan ketma-ketlik
d) katta va kichik lotin harflari, sonlar va tag chiziq (‘_’) belgilaridan
tashkil topgan va tag chiziq (‘_’) bilan boshlanmaydigan belgilar ketma-
ketligi
2. Blok bu –
a) '{' va '}' belgi oralig’iga olingan operatorlar ketma-ketligi, u
kompilyator
b) '(' va ')' belgi oralig’iga olingan operatorlar ketma-ketligi, u
kompilyator tomonidan yaxlit ir operator deb qabul qilinadi
c) '/*' va '*/' belgi oralig’iga olingan operatorlar ketma-ketligi, u
kompilyator tomonidan yaxlit ir operator deb qabul qilinadi
d) '[' va ']' belgi oralig’iga olingan operatorlar ketma-ketligi, u
kompilyator tomonidan yaxlit ir operator deb qabul qilinadi
310
c) Nuqta vergul “;”
d) Slash “/”
e)
311
Test savollari
1. C++ tilida quyidagi amallar bajarilganda javob nechchi chiqadi?
int c=25/3;
a) 8
b) 9
c) 8.(3)
d) 8.3
312
6. x=13, u=2 va z=11 ga teng bo’lsa, Quyidagi amallar ketma-ketligini
bajarilishi natijasida ekranga nima chiqadi?
cout << (x + z) % y;
a) 0
b) 12
c) 1
d) 2
10. C++ tilidagi quyidagi dastur qismidagi sintaktik xato kodni toping?
int c=25/3, x = 5; z = 3; y = x – z; z = 2 * y + 3;
a) z = 3;
b) y = x – z;
c) z = 2 * y + 3;
d) int c=25/3;
313
Test savollari
1. short turidagi o’zgaruvchining qabul qiladigan qiymatlar oralig’i?
a) -32768...32767
b) 0..65535
c) 0..32767
d) -2147483648.. 2147483647
314
7. 32 razryadli tizimda int tipi kompyuter xotirasidan qancha joy
egallaydi.
a) 4 bayt
b) 2 bayt
c) 6 bayt
d) 8 bayt
8. Qaysi toifa formatdagi qiymat kompyuter xotirasidan eng katta joy
egallaydi.
a) long double
b) double
c) int
d) float
10. C++ tilida belgi turidagi o’zgaruvchilar qaysi kalit so’z yordamida
aniqlanadi?
a) char
b) string
c) double
d) void
Test savollari
1. C++ da quyidagi operatorlar ketma-ketligi bajarinishi natijasida
ekranga nima chiqadi? cout<< "3 / 2 + 5.5 = " << 3 / 2 + 5.5 <<endl;
a) 3 / 2 + 5.5 = 6.5
b) 6.0
c) 2 + 5.5
d) 6.5
315
c) 0.9
d) 7.9
316
num2 = 4 *3 + 7 / 5 – 25.5; cout<< num2 <<endl;
a) -12.5
b) 10.5
c) -12
d) 12
317
Test savollari
1. C++ tilida konsol rejimda ishlash jarayonida berilganlarni standart
oqimdan o’qish formati to’g’ri ko’rsatilgan javobni aniqlang.
a) cin>> <o’zgaruvchi>
b) cout<< <ifoda>
c) cin<< <o’zgaruvchi>
d) cout>><o’zgaruvchi>
318
c) 10
d) 0
5. Quyidagi programma ishlashi natijasida ekranda qanday qiymat aks
etadi?
#include <iostream.h>
int main (){
int a=10, b=23;
switch(a){
case 1: c=a+b; break;
case 2: c=a*b; break;
default: c=(a+b)*b; break;
}
cout<<c;
return 0; }
a) *759
b) 33
c) 230
d) xatolik haqida habar beradi
319
b) -128..127
c) 0..32
d) -32768..32767
10. Agar o’qsih muvafaqiyatli bo’lsa getc() funksiyasi qanday qiymat
qaytaradi?
a) *ishorasiz int ko’rinishidagi qiymatni
b) EOF ni qaytaradi
c) ishorasli int ko’rinishidagi qiymatni
d) Haqiqiy sonni
Test savollari
1. Quyidagi programma qismi ishlashi natijasida ekranga qanday
qiymat chiqadi?
int a=4, b=8, y; y=a>b?a:b; cout<<y;
a) 8
b) 5
c) 12
d) 0.5
320
else
a += b; cout<<a;
a) 16
b) 15
c) 56
d) 1
321
c) 150
d) 300
322
a) 0
b) 1
c) 10
d) 100
323
12. Quyidagi programma qismi ishlashi natijasida ekranga qanday
qiymat chiqadi?
#include <iostream.h>
int main(){
int x=1;
x+=5;
cout<<x;
return 0;
}
a) 6
b) 5
c) 0
d) Xatolik haqidagi habar
324
15. Quyidagi programma qismi ishlashi natijasida ekranga qanday
qiymat chiqadi?
int a;
bool t = true, T = false;
if(t && T)
a = 100;
else
a =200;
cout <<a<<endl;
a) 200
b) 50
c) 150
d) 300
325
d) 1300
a) 660
b) 100
c) 444
d) 290
326
i+=50;
s += i;
if (i > 500)
T = t;
}
cout <<s<<endl;
a) 3300
b) 1200
c) 2000
d) 600
Test savollari:
1. for (<ifoda >1; <ifoda>2;<ifoda>3) uchun noto’g’ri tavsifni
ko’rsating?
a) <ifoda>2 – takrorlash sanagichi vazifasini bajaruvchi o’zgaruvchiga
boshlang’ich qiymat berishga xizmat qiladi
b) <ifoda>2 – takrorlashni bajarish yoki yo’qligini aniqlab beruvchi
mantiqiy ifoda, agar shart rost bo’lsa takrorlash davom etadi
s) <ifoda>3 – odatda takrorlash sanagichi qiymatini oshirish
(kamaytirish) uchun xizmat qiladi yoki bu yerda takrorlash shartiga ta’sir
qiluvchi boshqa amallar bo‘lishi mumkin.
d) <ifoda>1 - takrorlash sanagichi vazifasini bajaruvchi o’zgaruvchiga
boshlang’ich qiymat berishga xizmat qiladi
327
a) for(<ifoda1>;<ifoda2>; <ifoda3>)<operator yoki blok>
b) for(<ifoda>)operator yoki blok>
s) for(<ifoda1>,<ifoda2>, <ifoda3>)<operator yoki blok>
d) for(<ifoda1>;<ifoda2>; <ifoda3>)<operator
5. Quyidagi programma qismi ishlashi natijasida ekranga qanday
qiymat chiqadi?
#include <iostream.h>
int main (){
int s=0,i;
for(i=1;i<10;i++)
s+=i;
cout<<s;
return 0; }
a) 45
b) 55
s) 10
d) 1
328
int s = 1;
for(int i = 0; i <= 6; i += 2)
s+=i;
b) 45
s) 1
d) 10
329
d) 21
330
{ case 0: s += i;
break;
default : C++;
}
cout << s << endl;
a)23
b)43
s)24
d)21
331
while (a != b)
if (a > b) a -= b;
else b -= a;
cout << a << endl;
a)6
b)2
s)12
d)1
Test savollari:
1. Quyidagi dastur qismi ishlashi natijasida ekranga nima chiqadi?
int a[]={10,11,12,13,14};
int s=0;
332
for (int i=0;i<4;i++)
s=s+a[i];
cout << s;
a) 46
b) 55
c) 21
d) 60
333
5. Quyidagi dastur qismi ishlashi natijasida ekranga nima chiqadi?
int a[]={-20,30,-40,43,64};
int s=0;
for (int i=0;i<3;i++)
if (a[i]>0) s=s+a[i];
s=s+a[2];
cout << s;
a) -10
b) 30
c) -70
d) 40
334
cout << s;
a) 17.4
b) 15
c) 16.4
d) 15.4
335
c) 45
d) 6
336
if (a [m] < a [i])
m = i;
cout << m;
a) 1
b) 2
c) 3
d) 0
337
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++)
if (min<a[i][j]) min=a[i][j]
cout << min;
a) 43
b) 2
c) min
d) 0
338
a) 98 98
b) 35 98
c) 98 35
d) 35 35
339
28 << 3 & 22 - 17 | 30 >> 2
a) 7
b) 8
c) 9
d) 10
340
b) 10
c) 6
d) 4
Test savollari:
1. Funksiya e’loni to’g’ri ko’rsatilgan javobni toping.
a) void F(int t=1)
b) void F(int t=1, int s)
c) void F(int t=int q)
d) void F(int t=double)
341
double t=0;
t=t+a[0];
for (int i=1;i<n;i++)t=t+a[i]/a[i-1];
return t;
}
void main()
{
double a[]={7,1,3,5,3},c;
c=SUM(a,3);
cout << c;
}
a) 10
b) 20
c) 30
d) 50
342
{
a=13;
int b=a+41;
}
void main()
{
double b=15;
F(b);
cout << b;
}
a) 13
b) 54
c) 41
d) 22
343
void main()
{
int a=7;
F(a)+F(a+5);
cout << a;
}
A)7
b) 8
c) 5
d) 75
344
return k;
}
a) n niing sonlari sonini
b) n ning sonlari yig’indisini
c) Har doim nol qiymat qaytaradi
d) Qiymat qaytarmaydi
345
int F(int n, int k=15, int t=12)
{
return n*k/t;
}
void main()
{
int n=7, a[]={5,2,-3,2,4}, c=2, k=2;
for (int i=0;i<5;i++)
if (2*F(a[i])-F(n-a[i],c)>F(a[i], a[i], a[i/2])) c=c+F(a[i], n);
cout << c;
}
a) 7
b) 8
c) 15
d) 12
346
void main()
{
int n=8, a[]={5,2,-3,2,4}, c=2, k=2;
for (int i=0;i<5;i++)
if (2*F(a[i])-F(c-a[i],n)>F(a[i], a[i], n)) c=c+F(a[i]);
cout << c;
}
a) 8
b) 9
c) 10
d) 11
347
18. Programma ishlashi natijasida ekranga nima chiqadi?
bool F(int a, int b)
{
return (a+b);
}
void main()
{
int a=3, b=4;
cout << F(a,b);
}
a) 1
b) 7
c) 0
d) 34
348
b) 1
c) 0
d) 7
Test savollari
1. Quyidagi rekursiv funksiya bajarilishi natijasida ekranga nima
chiqadi.
long F(int n)
{ if(!n) return 1;
else return n*F(n-1);
}
int main()
{long s; int n=5;
s=F(n);
cout<<”s=”<<s;
}
a) 120
b) 130
c) 24
d) 620
349
else return x*rec(x,n-1);
} int main()
{ long s; int x=4;
s=rec(x,4);
cout<<”s=”<<s;
}
a) 256
b) 64
c) 16
d) 4
350
6. Quyidagi rekursiv funksiya bajarilishi natijasida ekranga nima
chiqadi.
long F(int n)
{
if(n==1) return 1;
else return n+F(n-1);
}
int main()
{long s; int n=10;
s=F(n);
cout<<”s=”<<s;
}
a) 55
b) 57
c) 56
d) 47
351
{float s; int n=2;
s=F(n);
cout<<”s=”<<s;}
a) 0.5
b) 1.5
c) 1
d) 2
Test savollari
1. |x| C++ da haqiqiy sonlar uchun qanday yoziladi?
352
a) fabs(x)
b) abs(x)
c) labs(x)
d) absf(x)
353
b) malloc()
c) ceil()
d) To’g’ri javob yo’q
Test savollari:
1. Quyidagi dastur qismi ishlashi natijasida ekranga nima chop etiladi?
int f(int a[],int n)
{
int m=a[0];
for(int i=1;i<n;i++)
if(a[i]>m) m=a[i];
return m;
}
int main()
{
int a[]={23,23,45,12,34};
int n=5;
cout<<f(a,n);
}
a) 45
b) 23
c) 12
354
d) 34
355
int a[]={0,1,2,3,4};
int n=5;
cout<<f(a,n);}
a) 4
b) 10
c) 6
d) 0
356
int c[7];
vector(7,a,c);
for(int i=0;i<7;i++) cout<<' '<<c[i];}
a) 1 1 0 1
b) 1 1 1 0
c) 1 0 0 0
d) 1 1 1 1
357
10. Quyidagi dastur qismi ishlashi natijasida ekranga nima chop etiladi?
void vector(int n,int x[])
{ int s=0;
for (int i=0;i<n;i++) if(x[i]<0) s+=x[i];
cout<<s;
}
void main()
{
int a[]={1,2,-4,3,-5,0,4};
vector(7,a);}
a) -9
b) 4
c) 10
d) 11
Test savollari
1. Struktura maydonlariga qanday murojaat qilinadi?
a. ‘.’ belgisi orqali
b. ‘->.’ orqali
c. ‘::’ orqali
d. ‘-’ belgisi orqali
358
Talaba [n]talabalar;
c. const int n=25;
Talaba talabalar*[n];
d. const int n=25;
Talaba talabalar{{n}};
359
void f(int a){a=a*a;};
int main(int argc, char* argv[])
{
A a; a.x=5;
f(a.x); cout<<a.x<<endl;
return 0;
}
a. 5
b. 6
c. 4
d. 8
360
Test savollari:
1. Quyidagi programma qismi ishlashi natijasida ekranga qanday
qiymat chiqadi?
char s1[]="ABBA", s2[]="BC", s3[]="CCBA";
strncat(s2,s3,2);
strcpy(s1,s2);
cout << s2;
a) ABC
b) BCCC
c) CBBB
d) BCCA
361
qiymat chiqadi?
char s1[]="BAB", s2[]="ABC", s3[]="CBA";
if (s1[0]==s1[1] && s3[0])
cout<<s3;
else cout << s2;
a) ABC
b) CBA
c) BAC
d) ACB
362
qiymat chiqadi?
int s=0, m=0 ;
char matn[] = "Programmalash asoslari fani 2015 - yil";
for(int i=0;i<strlen(matn);i++)
if(isdigit(matn[i])) C++;
else if (isalpha(matn[i])) m++;
cout<<s<<"\t"<<m;
a) 4 28
b) 2 31
c) 5 29
d) 6 23
363
char matn[] = "d2as#3!";
for(int i=0;i<strlen(matn)-2;i++)
if(!isdigit(matn[i]) && isalpha(matn[i]))
cout<<matn[i];
a) das
b) asd
c) 2#3
d) 23
Test savollari
1. Formatli yozish uchun qanday funksiya ishlatiladi?
a. scanf()
b. printf()
c. gets()
d. puts()
364
a. ayni paytda fayldan o’qilayotgan yoki unga yozilayotgan joyni
b. fayldan belgi o’qish jarayonini
c. fayldan satr o’qish jarayonini
d. ayni paytda fayldan o’qilayotgan belgining ASCII jadvalidagi kodini
365
b. puts()
c. getc()
d. putc()
Test savollari
1. Fayl oqimi turi to’g’ri berilgan javobni belgilang?
a. fstream
b. int
c. FILE*
d. fopen
366
a. rt+
b. rb+
c. wb+
d. at+
10. Fayldan satr o’qish uchun quyidagi funksiyalarning qaysi biri ishlatiladi?
a. fgets()
b. fputs()
c. fgetc()
d. feof()
367
GLOSSARIY
368
mavjud. Assembler dasturlash tilida odatda bitta mashina ko'rsatmasi
bo'ladi, lekin konstantalar, izohlar, assembler yo'naltirmalari, belgili teglar,
xotira joylari, registerlar va makroslarni ham qo'llab-quvvatlaydi.
12. Fortran - bu umumiy maqsadli kompilyatsiya qilingan imperativ
dasturlash tili bo'lib, u ayniqsa sonli hisoblash va ilmiy hisoblash uchun juda
mos keladi.
13. Paskal (inglizcha: Pascal) —Ushbu dasturlash tili boshqa bir
qator tillar uchun asos boʻlib xizmat qiladi. Paskal imperativ va Protsedurali
dasturlash tili hisoblanadi.
14. C (talaffuzi: si) — kompilyatsiyalanuvchi statik dasturlash
tili boʻlib, 1969—1973-yillarda Bell laboratoriyasi xodimi Dennis
Ritchie tomonidan yaratilgan. Ushbu dasturlash tili B tilining
takomillashgan koʻrinishi sifatida yaratilgan.
15. Kompilyator – bu o‘zgartirish degan ma’noni beradi. Ya’ni
dasturlash tilida yozilgan dastur(C++ bo‘lsa, *.c, *.cpp)ni kompyuter
tushunadigan tilga o‘zgartirib, uni ishlashini ta’minlaydi. Bu degani dastur
kompyuterda to‘liq ishlaydi. Bundan ko‘rinib turibdiki, C++ da dastur
tuzish uchun kompilyator o‘rnatish zarur.
16. Kompilyatsiya – o‘zgaruvchi jarayon, ya’ni yuqori pog‘onali
dastur kodlari(misol uchun C++ da tuzilgan kod)ni quyi pog‘onali
ishlovchi kodga aylantirish jarayoni.
17. Abstraksiya – bu identifikatorlardan farqli bo‘lgan istalgan
dasturlash tili ifodasi
18. Izoh - bu dasturchilar o'rtasida qayta tushuntirish uchun hojat
qolmasligi uchun dastur qismiga sharh sifatida qoldiriladigan izohlar
hisoblanadi.
19. O'zgaruvchi - xotiraning nomlangan qismi bo’lib, o’zida ma’lum
bir toifadagi qiymatlarni saqlaydi. O‘zgaruvchining nomi va qiymatlari
bo’ladi. O‘zgaruvchining nomi orqali qiymat saqlanayotgan xotira qismiga
murojaat qilinadi. Dastur ishlashi jarayonida o‘zgaruvchining qiymatini
o‘zgartirish mumkin. Har qanday o‘zgaruvchini ishlatishdan oldin, uni e’lon
qilish lozim.
20. Xotira manzili - bu kompyuterda saqlanadigan joy nomi
hisoblanadi. Xotira manzilini olish uchun & dan foydalanib olishimiz
mumkin. Bundan tashqari o'zgaruvchi xotira manzilini olish uchun ham
foydalanish mumkin.
21. Enum – yangi ma’lumotlar turlarini yaratish va qiymatlari
o’zgarmas bo‘lgan o’zgaruvchilar to’plami.
369
22. O‘zgarmas - bu konstanta hisoblanadi. C++ dasturlash tilida
o'zgarmaslarni e'lon qilish uchun const kalit so'zidan foydalanib ushbu
o'zgaruvchini o'zgarmas deb e'lon qilinadi.
23. Ifoda - ma’lumotlar bo‘yicha amallarni bajarish tartibini
belgilaydi, ular operatorlardan (o‘zgarmaslar, o‘zgaruvchilar, funksiyalar),
qavslar va amal belgilaridan iborat.
24. Operator -o'zgaruvchilar va qiymatlar bo'yicha amallarni
bajarish uchun ishlatiladi.
25. Encapsulation(Enkapsulatsiya)- ning ma'nosi , "sezgir"
ma'lumotlar foydalanuvchilardan yashirilganligiga ishonch hosil qilishdir.
26. Massiv indekslari - massiv elementlarini bir biridan farqlash va
ularga murojaat qilishda ishlatiladi. Ular 0 dan boshlanadi: [0] birinchi
element. [1] ikkinchi element va boshqalar.
27. Meros - bu odatda bitta sinf dan qayta-qayta foydalanish
imkoniyatini beradi. Yangi sinf yaratishda sinf attributlaridan foydalanish
imkoniyati.
28. Polimorfizm - ko'p shakllar ma`nosini anglatadi. Umuman
olganda, polimorfizm sinflar ierarxiyasi mavjud bo'lganda paydo bo'ladi va
ular meros bilan bog'liq. C ++ polimorfizmi shuni anglatadiki, a'zo
funksiyasini chaqirish ushbu funksiyani chaqiradigan obyekt turiga qarab
boshqa funksiyani bajarishga olib keladi.
29. Global o‘zgaruvchilar - ham asosiy dasturda, ham funksiyada
ishlatish mumkin bo'lgan o‘zgaruvchilar global o'zgaruvchilar deyiladi.
Global o'zgaruvchilar asosiy dasturda e`lon qilishi kerak.
30. Lokal o‘zgaruvchilar - faqat funksiyada ishlatish mumkin
bo'lgan o'zgaruvchilarga lokal o'zgaruvchilar deyiladi. Ular funksiya ichida
e`lon qilinadi.
31. Spetsifikator - sinf a'zolariga (atributlari va usullari) qanday
kirish mumkinligini belgilaydi.
32. Modellashtirish tili - har qanday sun'iy til ifodalash uchun
ishlatilishi mumkin ma`lumot yoki bilim tuzilishi, bu izchil qoidalar
to'plami bilan belgilanadi. Qoidalar tarkibidagi tarkibiy qismlarning
ma'nosini izohlash uchun ishlatiladi.
33. Konstruktor - sinf bilan bir xil nomga ega, u doimo public
bo'ladi va u hech qanday qiymat qaytarmaydi.
34. Konstruktor parametrlari - konstruktorlar parametrlarni
(odatdagi funksiyalar kabi) ham olishi mumkin, bu esa atributlar
uchun boshlang'ich qiymatlarni o‘zlashtirishda foydali bo‘lishi
mumkin.
370
35. Istisnolar – dastur yozish davomida keltirib chiqaradigan
xatoliklarni bartaraf etish ishlatiladi va uch guruhga bo’linadi.
36. try - agar kiritilgan blok kodi to'g'ri bo'lgan holda boshlanishi
kerak bo'ladigan kalit so'zi.
37. throw - maxsus xatolikni kutish uchun ishlatish mumkin
38. catch - agar yuqoridagi kalit so'zlar tarkibidagi blok kod xatolik
yuzaga kelsa ushbu kalit so'zdan foydalaniladi.
39. Interpretator - dasturlash tilida yozilgan kodni bosqichma-
bosqich mashina kodiga aylantirib, tahlil qiladi va berilgan buyruqlarni
ketma-ketlikda bajaradi. Agar xatolik sodir bólsa, ósha zahoti xabar beradi.
40. Preprotsessorlar - ko'rsatmalar bo'lib, ular kompilyatorga
haqiqiy kompilyatsiya boshlanishidan oldin ma'lumotni qayta ishlash
bo'yicha ko'rsatmalar beradi.
41. Return - funksiyani tugatadi va boshqaruvni chaqirilayotgan
funksiyaga qaytaradi (yoki boshqaruv asosiy funksiyadan uzatilsa
operatsion tizimga qaytaradi).
42. RAM (random access memory -tasodifiy kirish xotirasi) - bu
kompyuterning qisqa muddatli xotirasi bo'lib, u yerda protsessor hozirda
foydalanayotgan ma'lumotlar saqlanadi. Sizning kompyuteringiz RAM
xotirasiga qattiq disk, SSD yoki boshqa uzoq muddatli saqlash qurilmasidagi
ma'lumotlarga qaraganda tezroq kirishi mumkin, shuning uchun RAM hajmi
tizim ishlashi uchun juda muhimdir.
43. Ichki sinf (nested class) - boshqa sinf ichida joylashgan sinf.
Odatda, ichki sinflar faqat tashqi sinf obyekti ichida mavjud bo‘lishi
mumkin bo'lgan obyektlarni tavsiflash uchun ishlatiladi.
44. Intellektual tizim – sun’iy intellekt metodlari asosida aniq bir
predmetli sohaga tegishli intellektual masalalarni yechishga mo‘ljallangan
dasturiy yoki texnik tizimlar.
45. Jamiyatni axborotlashtirish – jamiyatning har bir a’zosiga
davlat siridan tashqari istalgan axborot manbalaridan erkin foydalanish
imkoniyatini taqdim etuvchi o‘zaro bog‘liq siyosiy, ijtimoiy-iqtisodiy va
ilmiy omillar to‘plami.
46. Matn muharriri – istalgan maqsaddagi (oddiy hujjat matni,
dastur matni va h.k.) matnni yaratish va tahrirlash uchun mo‘ljallangan
kompyuter dasturi.
47. Matn protsessori – asosan matniy hujjat bilan ishlash dasturlari
bo‘lib, ular matn muharirlari uchun ishni tashkil etuvchi muhit vazifasini
ham bajaradi.
371
XULOSA
373
FOYDALANILGAN ADABIYOTLAR RO‘YXATI
374
Internet resurslari:
17. www.gov.uz – O‘zbekiston Respublikasi hukumat portali.
18. www.lex.uz - O‘zbekiston Respublikasi Qonun hujjatlari milliy
bazasi.
19. www.ziyonet.uz – Axborot ta’lim portali.
20. www.edu.uz – Oliy va o‘rta maxsus ta’lim vazirligi portali.
21. www.buxdu.uz – buxdu rasmiy sayti.
22. http://www.uzbekcoders.uz - bir million o‘zbek dasturchisi loyihasi
23. http://cppstudio.com/
24. www.w3resource.com
25. https://metanit.com/cpp/tutorial/1.1.php
26. https://uzbekdevs.uz/darsliklar/cpp/cpp-da-kirish
27. www.Intuit.ru. Интернет-Университет информационных техно-
логий.
375
M. A. Bobojonova
Muharrir: E.Eshov
Tex. muharrir: D.Abduraxmonova
Musahhih: M.Shodiyeva
Badiiy rahbar: M.Sattorov