Binar amallarni qayta yuklash
Binar funksiya-amal sinf ichida aniqlanadi, parametrli nostatik usul yordamida ifodalanishi lozim, bu yerda uni chaqiruvchi obyekt birinchi operand deb hisoblanadi:
class monstr{
…
bool operator >(const monstr &M){
if( health > M.health) return true;
return false;
}
};
Agar funksiya sinf tashqarisida aniqlansa, u ikkita sinf tipidagi parametrga ega bo’lishi lozim:
bool operator >(const monstr &M1, const monstr &M2){
if( M1.get_health() > M2.get_health()) return true;
return false;
}
Qiymat berish amalini qayta yuklash
Qiymat berish amali jimlik bo’yicha ixtiyoriy sinfda elementlar bo’yicha nusxalash kabi aniqlanadi. Bu amal bir mos keluvchi obyektrga ikkinchisini qiymati berilganda chaqiriladi. Agar sinf xotirasi dinamik ajratiladigan maydonni o’z ichiga olsa, u holda xos qiymat berish amalini aniqlash zarur. Qiymat berish semantikasini saqlash uchun chaqirish atalgan obyektga murojaat-amal qaytarishi va parameter sifatida yagona argumentni-qiymat boriluvchi obyektga murojaatni qabul qilishi lozim.
const monstr& operator = (const monstr &M){
// O’z-o’ziga qiymat berishni tekshirish
if (&М == this) return *this;
if (name) delete [ ] name;
if (M.name){
name = new char [strlen(M.name) + 1];
strcpy(name, M.name);}
else name = 0;
health = M.health; ammo = M.ammo; skin = M.skin;
return *this;
}
Ko’rsatgich funksiyadan obyektga qaytarish qiymat berish amallar zanjiriga imkon beradi:
monstr А(10), В, С;
С = В = А;
Qiymat berish amali nafaqat sinf usuli sifatida aniqlash mumkin. U meros qilinmaydi.
new va delete amallarini qayta yuklash
Xotirani boshqarishning muqobil variantlarini ta’minlash uchun new va new[] amallarning xos variantlarini aniqlash obyektga va obyektlar xossasi mos ravishda dinamik xotirani ajratish uchun hamda delete va delete[] amallarning, uni bo’shatish uchun xos variantlarini aniqlash lozim.
Bu funksiya-amal quyidagi qoidalarga mos bo’lishi lozim:
ularga sinf tipidagi parametrni berish talab etilmaydi;
new va new[] funksiyalarga birinchi parameter qilib size_t tipidagi obyekt o’lchami berilishi lozim (bu tip sizeof amal bilan qaytarilib sarlavha faylda aniqlanishi lozim); chaqirilganda u funksiyalarga oshkormas ravishda beriladi;
ular qaytariluvchi void* qiymat tipi bilan aniqlanishi lozim, xatto agar return ko’rsatgichni boshqa tiplarga qaytaradi (ko’pincha butun sinfga);
delete amali void qaytarish tipiga va void* tipidagi birinchi argumentga ega bo’lishi lozim;
xotirani ajratish va bo’shatish sinfning statik elementlari hisoblanadi.
Qayta yuklangan amallar holati ular jimlik bo’yicha bajaradigan amallarga mos kelishi lozim. new amali uchun bu to’g’ri qiymatni qaytarishi, nol o’lchovli xotirani ajratishga buyurtmani korrekt qayta ishlashi va buyurtma bajarish mumkin bo’lmaganda holatdan chetlanishi lozim. delete amali uchun nol ko’rsatgichni yo’qotish xavfsiz bo’lish shartiga rioya qilish lozim, shuning uchun amal ichida nola ko’rsatgichni va tenglik bo’lgan holda qandaydir amallarning yo’qligini tekshirish lozim.
Xotirani ajratish va bo’shatish standart amallari sinf amal qilish sohasida qayta yuklanganlar bilan bir qatorda foydalanishi mumkin (bu sinfning obyektlari va bevosita – boshqa ixtiyoriy obyektlar uchun :: ko’rinish sohasiga kirish amali yordamda bajariladi).
Xotirani ajratish amalini qayta yuklash xotirani tejash, dasturning tez ishlashi uchun yoki ma’lumotlarni biror konkret sohaga joylashtirish uchun qo’llaniladi. Masalan, biror obyektga ko’rsatgichni saqlovchi sinf tavsiflanayotgan bo’lsin:
class Obj {...};
class pObj{
…
private:
Obj *p;
};
pObj tipidagi obyektga xotirani new standart amali yordamida ajratishda
pObj *р = new pObj;
haqiqatdagi baytlar soni sizeof(pObj) dan oshadi, chunki new ajraluvchi soha o’lchovining boshiga yoziladi (delete amali to’g’ri qayta ishlashi uchun).
Unchalik katta bo’lmagan obyektlar uchun bu qo’shimcha xarajatlar ko’p bo’lib ketishi mumkin. Xotirani tejash uchun xotiraning katta blokini ajratuvchi pObj sinfning new xos amalini yozish mumkin, keyin unda Objga ko’rsatgichni joylashtirish mumkin. Buning uchun pObj obyektga navbatdagi obyektni joylashtirish uchun blokning birinchi ozod yacheykasiga ko’rsatgichi saqlanadigan headOfFree statik maydon kiritiladi.
Foydalanilmaydigan yacheykalar ro’yxat qilinadi. Bog’lanish maydoni xotirasini egallamaslik uchun bitta yacheyka yo obyektga ko’rsatgichni joylashtirish yoki navbatdagi bo’sh yacheyka bilan bog’lanish uchun foydalaniladigan (union) birlashma qo’llaniladi:
class pObj{
public:
static void * operator new(size_t size);
…
private:
union{
Obj *p; // Obyektga ko’rsatgich
pObj *next; // Navbatdagi bo’sh yacheykaga ko’rsatgich
};
static const int BLOCK_SIZE; // Blok o’lchami
// Ozod yacheykalar ro’yxati sarlavhasi:
static pObj *headOfFree;
};
void * pObj::operator new(size_t size){
// Xotira miqdori noto’g’ri bo’lgan buyurtmalarni qaytarish
// new standart amali
if (size != sizeof(pObj)) return ::operator new(size);
pObj *p = headOfFree; // Birinchi bo’sh yacheykaga ko’rsatgich
// Bo’sh yacheykalar ro’yxati ko’rsatgichini ko’chirish:
if (р) headOfFree = р -> next;
// Agar bo’sh xotira bo’lmasa, navbatdagi blok ajratamiz:
else {
pObj *newblock = static_cast
(::operator new(BLOCK_SIZE * sizeof(pObj)));
// Birinchidan tashqari barcha yacheykalar bo’sh (u band
// bo’ladi), ularni bog’laymiz:
for (int i = 1; i < BLOCK_SIZE - 1: ++i)
newblock[i].next = &newblock[i + 1];
newblock[BLOCK_SIZE - l].next = 0;
// Bo’sh yacheykalar ro’yxatini boshini o’rnatamiz:
headOfFree = &newblock[l];
р = newblock;
}
return p; // Ko’rsatgichni ajratiluvchi xotiraga qaytaramiz
}
Qayta yuklangan new amali meros qoldiradi, shuning uchun u ixtiyoriy obyektlar uchun chaqiriladi. Agar ularning o’lchovi bazaviysi o’lchamiga mos kelmasa, bu muammo tug’diradi. Buni bartaraf etish uchun amal boshlanishida o’lchamlar mosligi tekshiriladi. Agar new amali qayta yuklangan obyekt o’lchami obyekt o’lchamiga teng bo’lmasa, xotirani ajratish buyurtmasi new amaliga uzatiladi.
pObj sinfdan foydalaniladigan dasturda uning statik maydonlarining initsializatsiyasi bo’lishi lozim:
pObj *pObj::headOfFree; // Jimlik bo’yicha 0 ga qo’yiladi
const int pObj::BLOCK_SIZE = 1024;
Bu misolda ko’rinadiki, xotirani tejashdan tashqari yuqori tezlikka erishiladi, chunki ko’p xollarda xotirani ajratish bir nechta oddiy operatorlarga olib kelinadi.
Tabiiyki, agar new amali qayta yuklangan bo’lsa, bu delete amali uchun ham bajarilishi lozim (masalan, bizning misolda delete standart amali obyekt boshida uning o’lchamlari haqida to’g’ri axborotni topa olmaydi, bu esa dasturning aniqmas ishlashiga olib keladi).
Qaralgan misolda delete amali bo’shatilgan xotira yacheykasini bo’sh yacheykalar ro’yxatiga qo’shishi lozim.
void pObj::operator delete(void * ObjToDie, size_t size){
if (ObjToDie == 0) return;
if (size != sizeof(pObj)){
::operator delete(ObjToDie): return:
}
pObj *p = stat1c_cast
(ObjToDie);
p->next = headOfFree;
headOfFree = p;
}
delete amalida new amalida keltirilganiga o’xshash obyektlar o’lchamlari mosligini tekshirish bajarilgan.
Do'stlaringiz bilan baham: |