Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
УМКД_ОБП_Урдабаева.doc
Скачиваний:
113
Добавлен:
01.03.2016
Размер:
1.29 Mб
Скачать

4. Бинарлы операторларды қайта анықтау

Класс ішінде анықталатын бинарлы функция-операторлар параметрлерсіз тұрақты емес әдістің көмегімен көрсетілуі керек, бұл кезде оны шақырған обьект бірінші операнд болып табылады:

Class monstr {

bool operator > (const monstr &M) {

If (health> M.health) return true;

Return false;

}

};

Егер функция класстан тыс анықталатын болса, ол класс типінің екі параметріне ие болу керек:

bool operator >(const monstr &M1,const monstr &M2) {

if(M1.get_health() > M2.get_health()) return true;

return false;

}

5. Меншіктеу операторларын қайта анықтау

Меншіктеу операторы жасырын түрде кез-келген класста элемент бойынша көшіру ретінде анықталған. Бұл операция әркез бір обьектіге екіншісінің мағынасын меншіктеген кезде шақырылады. Егер класста жады динамикалық түрде көрсетілетін жолдарға ие болса, онда меншіктеудің өзіндік операциясын анықтау керек. Меншіктеу семантикасын сақтап қалу үшін оператор-функция сілтемені ол шақырылған обьектіге қайтарып және параметр ретінде жалғыз ғана аргумент- меншіктелетін обьектіге сілтемені қабылдау керек.

const monstr& operator = (const monstr &M) {

/ / Өзіне меншіктеп алуды тексеру:

if (&M == 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;

}

Функциядан сілтегіштің обьектіге қайтуы меншіктеу операторының тізбегін жасайды:

monstr A(10), B, C;

C =B = A;

Меншіктеу операторын тек класс әдісі ретінде ғана анықтауға болады. Ол мұраға берілмейді.

6. New және delete операторларын қайта анықтау

Жадыны басқарудың балама нұсқаларын қамтамасыз ету үшін обьектіге динамикалық жадыны және сәйкесінше обьект массивтерін бөлуге new және new [ ] операторларының , сонымен қатар delete және оны босату үшін delete [] операцияларының өзіндік нұсқаларын анықтауға болады. Бұл функция-операторлар келесі ережелерге сай болуы тиіс:

  • Оларға класс типінің параметрлерін беру қажет емес;

  • new және new [ ] функцияларына бірінші параметр болып size_t типті обьектінің көлемі жіберілуі тиіс ( бұл sizeof операторымен қайтарылатын тип, ол <stddef. h> тақырыптық файлда анықталады); шақырған кезде ол функцияларға түсініксіз түрде жіберіледі;

  • return сілтегішті өзге типтерге қайтарып тұрса да, олар void* мәнінің қайтарылатын типімен анықталуы керек;

  • delete операторы void қайтарымының типіне және void* типінің бірінші аргументіне ие болу керек;

  • Жадыны бөлу және босату оперторлары класстың статистикалық элементтері болып табылады.

Қайта анықталған операторлар әрекеті олармен жасырын түрде орындалатын әрекеттерге сай келуі тиіс. New операторы үшін бұл ол дұрыс мағынаны қайтаруы керек, нөлдік көлемдегі жадты бөлуге сұранысты корректілі түрде өңдеп және сұранысты орындау мүмкіншілігі болмаған кеэде шығарып тастап отыруды білдіреді. Delete операторы үшін нөлдік сілтегішті жою қауіпсізболуы керек екендігін ескерген жөн, сондықтан оператор ішінде сілтегішті нөлге және тепе-теңдік жағдайындағы кез-келген әрекеттің жоқ екендігіне тексеру жүргізу керек. Жадыны бөлудің және босатудың қалыпты операторлары класстың әрекет облысында қайта анықталғандармен бірге қолданылуы мүмкін ( көрінетін облысқа кіретін операторлар көмегімн : : (осы класс және өзгелері үшін де).

Жадыны бөлу операторын қайта жүктеу жадыны үнемдеу үшін,бағдарламаның тез жұмыс жасауы және мәліметтерді кейбір белгілі бір облыстарға орнату үшін қолданылады. Мысалы, кейбір обьектіге сілтегіші бар класс сипатталсын:

class Obj { … };

class pObj {

private:

Obj *p;

};

p0bj типіндегі обьект астына new қалыпты операторының көмегімен жадыны бөлу кезінде

pObj *p = new pObj;

байттардың нақтылы көлемі sizeof(p0bj) асып кетеді, себебі new , әдетте бөлінетін облыстың басына оның көлемін жазып кетеді ( delete операторларын дұрыс өңдеу үшін).

Шағын обьектілер үшін бұл накладты шығындар маңызды болуы мүмкін. Жадыны үнемдеу үшін жадының үлкен блогын бөліп отыратын, кейін онда 0bj сілтегіштерді орнататын өзіндік p0bj классты new операторын жазуға болады. Бұл үшін p0bj обьектісіне head0free статикалық жолы енгізіледі, онда келесі обьектіні орнатуға арналған блоктың бірінші бос ұяшығына сілтегіш сақталады

Қолданылмайтын ұяшықтар тізімге жиналады. Байланыс жолының астында жадты алмау үшін, бірлестік қолданылады ( union), оның көмегімен бір ұяшық не обьектіге сілтеуішті орнату үшін, не келесі бос ұяшықпен байланыс үшін қолданылады:

class pObj {

public:

static void * operator new(size_t size);

private:

union {

Obj *p / / обьектіге сілтеуіш

pObj *next; / /келесі бос ұяшыққа сілтеуіш

};

static const int BLOCK_SIZE; / / блок колемі

// бос ұяшықтар тізімінің атауы

static pObj *headOfFree;

};

void * pObj: :operator new(size_t size) {

// жадының дұрыс емес көлемінің сұранысын қайта бағыттау

//new қалыпты операциясы

If (size != sizeof(pObj)) return : :operator new(size);

pObj *p = headOfFree; // бірінші бос ұяшыққа сілтегіш

//бос ұяшықтар тізімінің сілтегішінің орнын өзгерту

If (p) headOfFree = p ­­­-> next;

// егер бос жады болмаса, кезекті блокты бөлім аламыз:

else {

pObj *newblock =static_cast<pObj*>

( : :operator new(BLOCK_SIZE * sizeof(pObj)));

// біріншіден басқа барлық ұяшыұтар бос емес (ол

//бос болмайды). Оларды жинаймыз:

for (int i= 1; i< BLOCK_SIZE - 1; ++i)

newblock[ i ].next = &newblock[ I + 1 ];

newblock[BLOCK_SIZE - 1 ].next = 0;

//бос ұяшықтар орнатамыз:

headOfFree = &newblock[ 1 ];

p =newblock;

}

return p; // Сілтегішті бөлінген жадыға қайтарамыз

}

Қайта анықталған new операторы мұраға беріледі, сондықтан ол туынды обьектілер үшін шақырылады. Егер олардың көлемдері базалық көлемге сай келмесе, бұл ашық жер қалдыруы мүмкін. Оларды болдырмау үшін оператор басында көлемнің сәйкестігі тексеріледі. Егер обьект көлемі new операторы қайта шақырылған көлемге сәйкес келмесе, жадыны бөлуге сұраныс new қалыпты операторына жіберіледі.

p0bj класын қолданатын бағдарламада оның статикалық жолдарының инилизациясы болуы тиіс:

pObj *pObj : :headOfFree; // 0 ге жасырын түрде қойылады

const int pObj: :BLOCK_SIZE = 1024;

Бұл мысалдан көріп отырғанымыздай, жадыны үнемдеуден басқа жоғары тез әсер етуге де қол жеткіземіз. Себебі көп жағдайда жадыны бөлу бірнеше қарапайым операторларға түсіріледі.

Әрине, егер new операторы қайта анықталса, delete операторы үшін де дәл солай болу керек ( мысалы, біздің жағдайымызда delete қалыпты операторы обьект басында оның көлемі туралы дұрыс мәліметті таба алмауы мүмкін, бұл бағдарламаның нақтылы емес әркет етуіне алып келеді).

Void pObj: :operator delete(void * ObjToDie. Size_t size) {

if (ObjToDie == 0) return;

if (size != sizeof(pObj)) {

: :operator delete(ObjToDie); return;

}

pObj *p = static_cast<pObj*>(ObjToDie);

p->next = headOfFree;

headOfFree = p;

}

Delete операторында обьектілер көлемінің сәйкестігінің тексерісі оындалған, ол new операторында келтірілгенге бара-бар.

Бақылау сұрақтары:

  1. Операторды қайта анықтау дегеніміз не?

  2. Қайта жүктеу дегеніміз не?

  3. Қандай операторларды қайта анықтауға болмайды?

  4. Қайта анықталған операторларды шақыру формалары қандай?

Әдебиеттер:

  1. Г.С. Иванова и др. ООП: Учебник для вузов, М., Изд-во МГТУ им.Баумана, 2003.- 368 с.

  2. Павловская Т.А. С и С++. Программирование на языке высокого уровня.

  3. Р. Лафоре. Объектно-ориентированное программирование в С++.4-е издание. Питер.2004

  4. Подбельский В.В., Фомин С.С. Программирование на языке Си: Учебное пособие. – М.: Финансы и статистика, 2004

8-9 дәріс.

Тақырыбы: Полиморфизм. Жәй және күрделі полиморфизм

Дәріс мақсаты: объектіге бағытталған программалаудың қасиеттерінің бірі – полиморфизм түсінігін беру, оның түрлерін ажырата білу.

Кілттік сөздер: полиморфизм; жәй полиморфизм; күрделі полиморфизм; ерте байланысу механизмі; кеш байланысу механизмі.

Жоспар:

  1. Жәй және күрделі полиморфизм

  2. Виртуальді функциялар