3
Коммерциялық емес акционерлік
қоғам
ОБЪЕКТІГЕ БАҒЫТТАЛҒАН ПРОГРАММАЛАУ 5В070300 – Ақпараттық жүйелер, 5В060200 – Информатика
мамандықтарының студенттеріне арналған
Алматы, 2016
Ақпараттық жүйелер кафедрасы АЛМАТЫ ЭНЕРГЕТИКА ЖӘНЕ БАЙЛАНЫС УНИВЕРСИТЕТІ
4
ҚҰРАСТЫРУШЫ: А.С.Сәрсенбай. «Объектіге бағытталған программалау». 5В070300-Ақпараттық жүйелер, 5В060200 – Информатика мамандықтарының студенттеріне арналған дәрістер жинағы. – Алматы:
АЭжБУ, 2016. – 58 б.
Дәрістер жинағы «Объектіге бағытталған программалау» таңдау курсына сәйкес 5В070300 - Ақпараттық жүйелер, 5В060200 - Информатика мамандықтарының студенттеріне арналған. Дәрістер жинағында объектіге бағытталған программалау негіздері, абстрактты тип ретіндегі класс, ағынды кластар, үлгілер (шаблоны), мұрагерлік, кластар иерархиясы, полиморфизм, класс достары, кластарға арналған стандартты операцияларды қайта жүктеу, әрекеттер аймақтары мен атаулар кеңістіктері, файлдық енгізу-шығару кластары қарастырылған.
Библиография –10.
Пікір беруші: т.ғ.к., доцент Кожамбердиев К.О.
«Алматы энергетика және байланыс университеті» коммерциялық емес акционерлік қоғамының 2016 жылғы жоспары бойынша басылады.
© «Алматы энергетика және байланыс университеті» КЕАҚ, 2016 ж.
5 Введение
Основное различие между современными лидирующими объектно- ориентированными языками программирования С++ и Java и процедурными языками состоит в том, что первые имеют синтаксис для использования объектно-ориентированных понятий, таких как наследование, инкапсуляция, полиморфизм и так далее
Язык С++ имеет в своих стандартных библиотеках большое количество уже написанного низкоуровневого кода, но главным образом он приспособлен для использования коллекций и низкоуровневых структур данных, таких как стеки и очереди.
Обычные задачи программирования, такие как работа с базами данных, изображениями, Интернетом реализованы не в самом языке С++, а в виде дополнительных библиотек операционной системы.
Язык С++ основан на С, который известен как высокопроизводительный язык за счет простоты использования. С++ - это компилирующий язык. Это означает, что когда вы пишите исходный код, вы должны откомпилировать его и скомпоновать, чтобы он стал выполнимым для определенной платформы, и перекомпилирован для выполнения на другой платформе. Так как пользовательский интерфейс отличается на различных платформах, перенос приложения на С++ - основная проблема при переносе программ с одной операционной системы на другую. С++ не предоставляет никакой безопасности.
Любая программа на С++ может получать доступ к любой части памяти и к любым ресурсам. С++ не поддерживает сбор мусора, то есть возможность языка автоматически, как в языке Java, очищать ресурсы(память). В С++, выделив блок памяти, вы отвечаете за его освобождение. Язык С++ не предоставляет никаких элементов пользовательского интерфейса, кроме консоли ввода-вывода.
6 Мазмұны
1 Дәріс №1. Объектіге бағытталған программалау технологиясы.
С++ тілі ... 4
2 Дәріс №2. Сілтемелер деректер типі ... 6
3 Дәріс №3. Абстрактты тип ретіндегі класс ... 9
4 Дәріс №4. Класс достары. Кластарға арналған стандартты операцияларды қайта жүктеу ... 13
5 Дәріс №5. Үлгілер (шаблоны) ... 16
6 Дәріс №6. Мұрагерлік ... 20
7 Дәріс №7. Кластар иерархиясы ... 23
8 Дәріс №8. Полиморфизм ... 28
9 Дәріс №9.Абстрактылы кластар ... 31
10 Дәріс №10. Әрекеттер аймақтары мен атаулар кеңістіктері ... 34
11 Дәріс №11. Стандартты кітапхана құрылғыларымен С++ тіліндегі енгізу-шығару. Ағынды кластар ... 38
12 Дәріс №12. Файлдық енгізу-шығару ... 41
13 Дәріс №13. Ерекше жағдайларды өңдеу ... 45
14 Дәріс №14. Динамикалық идентификациясы және типтерді келтіру ... 49
15 Дәріс №15. С++ тілінің стандартты кітапханасы. Жалпыланған бағдарламалау ... 52
Әдебиеттер тізімі ... 56
7
1 Дәріс №1. Объектіге бағытталған программалау технологиясы.
С++ тілі
Дәрістің мақсаты: объектіге бағытталған программалау технологиясы түсініктерімен таныстыру.
Дәрістің мазмұны: класс ұғымы және оның элементтері. С++ тілі ортасының артықшылықтары.
Программалаушылар көптеген жылдар бойы бизнесті жүргізу әдістерін автоматтандыратын программалаларды жазып үлкен жұмыс атқарды.
Бизнесте программалар – бизнес операцияларына қызмет етуі талап етеді.
Программалаушыларға көмекке қайта пайдаланылатын кодтар (reusable code) есебінен, жұмысты жеңілдететін процедуралық программалау келді.
Процедуралық программалау программалар жазуда үлкен өзгеріс болды, бірақ объектіге бағытталған әлемді қайта құру мәселесі шешілмеген күйінде қалды.
Бұл мәселе 1980 жылы объектіге бағытталған программалаудың (ОБП) пайда болуымен шешілді. Нақты әлемнің объектілеріне еліктеуді C++ немесе Java сияқты объектіге бағытталған программалау тілдерінде кластарды анықтау арқылы жүзеге асыруға болады. Класс деректер мүшелері мен әдістер мүшелерінен тұрады. Деректер мүшелері (data members) кейде өрістер (fields) деп аталады және объект атрибуттарын сақтау үшін пайдаланылады. Әдістер мүшелері (member methods) кейде функциялық мүшелер (member functions) деп аталады және объектінің жәй-күйін анықтайды. Қазіргі уақытқа сай алдыңғы қатарлы C ++ және Java объектіге бағытталған программалау тілдерімен процедуралық тілдердің арасындағы негізгі айырмашылық, біріншісінде мұраға, инкапсуляция, полиморфизм сияқты т.б. объектіге бағытталған тұжырымдамаларды пайдалануға арналған синтаксисі бар екенінде.
C++ тілінің стандартты кітапханаларында көп мөлшерде жазылған төменгі деңгейлі коды бар, бірақ негізінен бұл стек және кезек сияқты төмен деңгейлі деректер құрылымдардың жинақтарын пайдалану үшін бейімделген.
Деректер қорымен, суреттермен, интернетпен жұмыс істеу сияқты қарапайым программалау есептері C++ тілінің өзінде емес, операциялық жүйелердің қосымша кітапханалары түрінде іске асырылған.
C++ тілі пайдалануға қарапайымдылығына байланысты өнімділігі жоғары тіл ретінде белгілі C тіліне негізделген. C++ - бұл компиляциялайтын тіл. Бұл, бастапқы кодты жазғанда, ол анықтаған платформа үшін орындалатындай етіп, оны компиляциядан және компоновкадан өткізіп, басқа платформада орындалуы үшін қайта компиляция жасауды білдіреді.
Қолданушы интерфейсі әртүрлі платформаларда ерекшеленетіндіктен, қосымшаны C++-ке көшіру - программаны бір операциялық жүйеден басқасына көшіру барысындағы басты мәселе. C++ ешқандай қауіпсіздікті қамтамасыз етпейді. C++ тілінде программа жадының кез келген бөлігіне және кез келген ресурстарға қол жеткізе алады.
8
C++ қоқыс жинауды қолдамайды, яғни оның мүмкіндігі Java тіліндегі сияқты ресурстарды (жады) автоматты түрде тазалайды. C++ тілінде жады блогын бөле отырып, сіз оның босауына жауап бересіз. C++ тілі енгізу- шығару консолінен басқа ешқандай қолданушы интерфейсінің элементтерін ұсынбайды. Ол мұнда Windows жүйесіндегі сияқты ешқандай графикалық пайдаланушы интерфейсін қолдаудың жоғын білдіреді. Windows ортасының өзінің С++ те пайдалануға болатын жеке программалық интерфейсі бар (application programming interface, API). C ++ тілі көпжақты мұрагерлік қолдау көрсетеді, ол дегеніміз бір кластың бір мезгілде бірнеше базалық кластары болуы мүмкін дегенді білдіреді.
C++ шаблондар (templates) аталымды механизмін ұсынады. Шаблондар печенье пісіретін формалар сияқты кластар мен функцияларды анықтау барысында, жаңа кластар мен функцияларды құру үшін қолданылады.
C++ тілінің түйінді сөздері программа объектілерінің жады кластарымен, типтердің аттарымен, көріну спецификациясымен, модификаторлармен және операторлармен байланысты. C++ тілі операциясының белгілері өрнектерді қалыптастыру және әрі қарай есептеуді қамтамасыз етеді. Мәнді алу үшін өрнек қағида болады. Операцияның бір белгісі әртүрлі өрнектерде қолданылу мүмкін және контекстке байланысты әртүрлі интерпретациялануы мүмкін. Әрине, барлық операциялардың өз рангісі болып, приоритеттер иерархиясын құрап, ассоциативтік (оңнан солға немесе солдан оңға) ережеге бағынады.
C++ тілінің операторлары мен функциялары өз кезегінде классикалық алгоритмдік тілдердің құрылысын мұра еткен C тілімен толықтай дерлік сәйкес келіп, шамалы жетілдірілген. Операторлар әдеттегідей іс-әрекеттерді және осы іс-әрекеттердің программада орындалу логикасын (ретін) анықтайды. C++ тілінде әртүрлі функциялардың атауы бірдей болуы мүмкін.
Бұл жағдайда әртүрлі функциялар ретінде бір-бірінен формальді параметрлер санымен немесе типімен ерекшеленетін функцияларды түсінеміз. Тек қана кері қайтарылатын мәннің типі бойынша айырмашылықтар рұқсат етілмейді.
Inline модификаторы бар функциялар алмастыру функциялары деп аталады.
Ереже бойынша, бұл барлық жұмысы жалғыз оператормен атқарылатын және оның көмегімен программада бірнеше рет қолданылатын кодты жүзеге асыратын функциялар.
C++ тілінде бар және С тілінде жоқ кейбір мүмкіндіктерді қарастырайық:
- С++ тілінде комментарияларды - // белгісі арқылы енгізуге болады;
- С++ тілінде енгізу-шығарудың қосымша жабдықтары бар;
- функцияны қайта жүктеу - бірнеше функциялар үшін бірдей атауларды пайдалану. Бір функцияға кейде әр типті объектілермен ұқсас әрекеттерді орындау талап етіледі;
-программада динамикалық жады облысын таңдап және жоюға мүмкіндік беретін new және delete операциялары;
-көріну аймағын кеңейту операциясы.
9
Кластар және оның әдістері (ОБП түйінді ұғымдары):
- конструкторлар мен деструкторлар кластар объектілерін құратын және жоятын арнайы әдістер болып табылады;
- кластың мүшесі болмайтын, бірақ ондағы сипатталған айнымалылар мен әдістерге қол жеткізуге мүмкіндігі бар достық функциялары;
- қайта жүктеу операциялары – тек стандартты типтегі деректерге ғана емес, әртүрлі кластардың объектілеріне де қолдануға мүмкіндік беретін тілдің көптеген негізі операцияларының мағынасын өзгерту мүмкіндігі;
- туынды кластар. Осы класс объектiлерi барлық ашық айнымалылар мен түбірлік (родительский) класс әдістерін мұра етеді, бірақ оған қоса өзінің жеке айнымалылары мен әдістері болуы мүмкін.
- полиморфизм - виртуалды функциялар жабдықтары арқылы жүзеге асырылады;
- хабарламалар көмегімен объектілерді басқаруға болады. Объектіге хабарламаны жіберу функцияны шақыруды еске түсіреді.
Бақылау сұрақтары:
1) Компьютерлік жүйелерді құру барысында объектіге бағытталған программалауды қолдану неліктен маңызды?
2) Мұралықтың объектіге бағытталған программадағы орнын түсіндіріңіз.
3) ОБП күрделі компьютерлік жүйелерді қандай жолмен қолдауға көмек береді?
4) Адам объектісінен мұра етілетін Университет объектілерін сипаттаңыз.
2 Дәріс №2. Деректер типінің сілтемелері
Дәрістің мақсаты: объектіге сілтемені қолданудың әдістерін ұғындыру.
Дәрістің мазмұны: сілтемені анықтау және оны қолдану әдістері.
Нұсқауыштан айырмашылығын көрсету. Функцияға сілтемені пайдалану.
С++ тілінде нұсқауышқа туыс элемент – сілтеме (reference) бар. Сілтеме барлық жағдайда жасырын нұсқауыш болып, оны кезкелген мақсат үшін айнымалының тағы бір аты ретінде қолдануға болады. Сілтемені үш түрлі әдіспен қолдануға болады. Біріншіден, сілтемені функцияға жіберуге болады.
Екіншіден, оны функциядан қайтарып алуға болады. Ақырында, тәуелсіз сілтемені құруға болады. Сілтеменің ең маңызды қолданылуы – бұл оның функция параметрі ретінде берілуі.
Сілтемені анықтау үшін & белгісі пайдаланылады, егер ол келесі контексте қолданылатын болса: type & сілтеме_ аты инициализатор;
Сол жақтағы мәні болатын инициализатор ретінде болуы міндетті, яғни жадыда орын алатын объектінің атауы болуы керек. Инициализацияны
10
анықтаудан кейін сілтеменің мәні сол объектінің адресі болады. Мысалы: int k=2; int& ref=k; сілтемені анықтауда‘&’ символы типтің бөлігі болып табылмайды, яғни ref int типті және дәл осылай программада қабылдануы керек.
Функциональді түрде сілтеме өзін-өзі қарапайым типті сияқты айнымалы ретінде ұстайды. Нұсқауыш үшін керек болатындай, сілтеме
«қарайтын» жады бөлігінің мәнін иемдену үшін қайта атауды нақты орындау қажет емес.
Сілтеме айнымалы не көрсеткішке ұқсас толық құқылы объект емес.
Инициализациядан кейін сілтеменің мәнін өзгертуге болмайды, ол әрқашан инициализациямен байланысқан жады бөлігіне «қарайды». Бір де бір операция сілтемеге әсер етпей, онымен байланысқан объектіге қатысты болады. Мұны сілтеменің негізгі қасиеті деп есептеуге болады. Сонымен, сілтеме толықтай бастапқы объект атымен бірдей.
Анықталған болсын:
int ar[]={1,2,3,4}; //ar - массив int *p=ar; //р - нұсқауыш
int & ref=ar[0]; //ref – массивтің бірінші элементіне сілтеме int*& rp=ar; //нұсқауышқа сілтеме (массив атына)
Келтірілген мысалдан сілтемелер мен нұсқауыштарға келесі теңдіктер орындалады:
p==&ref, *p==ref, rp==ar; ref== ar[0].
Сілтемеге Sizeof операциясын қолдану нәтижесі оның өлшемі емес, онымен аталған объектінің өлшемі болып табылады.
Сілтеме шын объект болмаған соң, сілтемені анықтауда және қолдануда шектеулер бар. Біріншіден, сілтеме void типті бола алмайды.
Сілтемені new операциясы көмегімен құруға болмайды, яғни сілтемеге жаңа жады бөлігін бөлуге болмайды. Басқа сілтемелерге сілтеме анықталмаған.
Сілтемелерге нұсқауыштар жоқ және сілтеме массивін құру мүмкін емес.
Сілтеменің мәні өзгермегенімен, бір объект сілтемелер және нұсқауыштардың кез келген санымен адрестелуі мүмкін:
int k=7; // k айнымалысы анықталған int &r1=k; // r1сілтемесі k-мен байланысты int *p=&r1; // p нұсқауышы k-ні адрестейды int &r2=r1; // r2 сілтемесі k-ны көрсетеді
Енді k айнымалысының мәніне төрт әдіспен жетуге болады:
- k атауымен;
- r1 сілтемесі;
11
- *p нұсқауышы және r2 сілтемесі арқылы.
Сілтеме айнымалыға қарағанда, сілтеме өзімен байланысқан тұрақты объектінің мәнін өзгертуге мүмкіндік бермейді. Мысалы:
int k=5;
const int &ref=k; //ref – тұрақтыға сілтеме Осы анықтамалардан:
k =0; // қалыпты меншіктеу операторы
ref =0; // қате, себебі сілтеме тұрақтыға жарияланған
Сілтемелерді анықтауда оларды міндетті түрде атаулау (инициализация) талап етіледі. Алайда, сілтемелердің сипаттамасында оның болуы міндетті емес, бірақ та тыйым салынбайды.
Осындай сілтемелердің сипаттамаларына мыналар қатысты:
- сыртқы сілтемелер сипаттамасы (extern ерекшелегішімен (специфика- торымен));
- класс компоненттеріне сілтемелер сипаттамасы;
- функцияның формальды параметрлерін ерекшелеу;
- функция қайтаратын мән типінің сипатталуы.
С++ тіліне сілтемелерді енгізудің негізгі себебі (тек қана С++ үшін емес), функциялармен параметрлер аппараты арқылы алмасу тиімділігін және функцияны шақыруды сол тұрғыдағы мән ретінде мақсатты қолдану мүмкіндігін арттыру қажеттілігінен болды. Мысалы:
int f1(int &k) // функция бүтін санды қайтарады {return k;}
int &f2(int &k) // функция k айнымалысына сілтемені қайтарады {return k;}
Екі функцияда k енгізілетін параметрінің сандық мәніне сәйкес келетін мәнді қайтарады. Екінші жағдай үшін шақырудың келесі түрі мүмкін:
int main(void) {int n=3;
f2(n)=7; // n жетіге тең болады return 0;
}
Функцияға нұсқауышқа ұқсас функцияға сілтеме форматы анықталады:
функция_типі (&сілтеме_аты) (функция_параметрлерінің_ерекшеліктері)
=атаулаушы өрнек; Мысалы:
int func(float, int); // функция прототипі int (&ref) (float, int)=func; // сілтеменің анықталуы
12
Функция атының жақшасыз (және параметрлерсіз) қолданылуы функция адресі ретінде қабылданады.
Функцияға сілтеме функцияның негізгі атының барлық құқықтарына ие, яғни оның синонимі (псевдонимі) болып табылады. Функцияға сілтеме (нұсқауышқа сілтеме) мәнін өзгерту мүмкін емес, сондықтан функцияға нұсқауыштар сілтемеге қарағанда үлкен ауқымға ие. Келесі программа функцияны шақыруды негізгі аты бойынша, нұсқауышпен және сілтеме бойынша орындауды суреттейді:
#include <iostream.h>
void func(char lit) {cout<<endl<<lit;}
int main (void)
{void (*pf)(char); // pf - функцияға нұсқауыш void(&ref)(char)=func; // ref - функцияға сілтеме func(‘A’); // атымен шақыру
pf=func; // нұсқауышқа функция адресі меншіктеледі (*pf)(‘B’); // нұсқауыш көмегімен адресі бойынша шақыру ref(‘C’); // функцияны сілтеме арқылы шақыру
return 0;
}
Функциямен сілтемені қайтару бірнеше функцияларға бірнеше қайтара әрекеттесуді ұйымдастыруға мүмкіндік береді. Осы әрекеттесу нәтижесінде бір объектіні бірнеше қайтара әр түрлі ережемен өзгертуге болады.
Бақылау сұрақтары:
1) Сілтеме дегеніміз не?
2) Сілтеме параметрлерінің қандай артықшылығы мен кемшіліктері бар?
3) Объектіні сілтеме арқылы функцияға бергенде оның көшірмесі құрыла ма?
4) Сілтеме параметрлерін қолданған кезде адрес аргументі қалай жіберіледі?
5) Тәуелсіз сілтеме деген не?
3 Дәріс №3. Класс абстрактылы тип ретінде Дәрістің мақсаты: класс ұғымын толық түсіндіру.
Дәрістің мазмұны: «Клиент-сервер» технологиясы бойынша класс әдістерін анықтау. Конструктор мағынасы. Деструктор мағынасы.
13
Деректер абстракциясына негізделетін программаларды жүзеге асыру және құрастыру, жобалау принциптерінің жиынтығы, шешілмелі есептердің ерекшеліктері мен түсініктерін анағұрлым толық көрсететін деректердің жаңа типтерін құруды қарастырады. С++ тілінде программалаушының өзіндік деректер типтерін енгізуге және олармен кластар көмегімен орындалатын операцияларды анықтауға мүмкіндігі болады.
Класс - бұл бар типтер негізіндегі туынды құрылымдық (структурированный) тип. Класты келесідей ең оңай әдіс арқылы анықтауға болады:
Класс_кілті класс_аты {компоненттер тізімі};
мұнда класс_кілті - class, struct, union қызметші сөздерінің бірі;
класс_аты - еркін таңдалатын идентификатор;
компоненттер тізімі - класқа қатысты функциялар мен типтелген деректердің сипаттаушылары мен анықтамалары. Компоненттер обьект күйін анықтайды және класс объектісінің тәртібін шартқа негіздейді. Класс компоненттері деректер, функциялар, кластар, санауыштар, биттік өрістер, достық функциялар мен типтер атаулары бола алады. Мысалы:
class Classid
{ int k; // к, х, у жабық мүшелер - үнсіздік бойынша деректер double x,y;
public: char lit, ch; // lit,ch ашық мүшелер - деректер int f3(int,int); // кластың ашық әдістері
int Get x (void) // кластың орнына қою әдісі { return x; }
private:
void f1 (void); // жабық мүшелер - класс әдістері int f2 (int);
};
Қатынау спецификаторлары public: және private: қатынау спецификаторлары класс мүшелеріне өтуге мүмкін беретін режимді анықтайды: private - класс мүшелерін жабыққа айналдырады, ал public - ашық. Кластың жабық мүшелеріне тек берілген класс мүшелерінің қатынауға рұқсаты бар, сонымен қатар функциялардың – класс достары. Кластың ашық мүшелеріне кез келген функциялардың қатынауға мүмкіншіліктері бар. Олар бар болып табылатын бағдарлама мен класс объектілерінің байланысы үшін арналған.
Класты жобалап отырып, оның қай мүшесін ашық, ал қайсысын жабық етуді мұқият ойластырған жөн. Көптеген жағдайда класс анықтамасы блокта локализацияланбаған және класс атауының іс-әрекет облысы бүкіл файл болып табылады.
Жай кластық әдістерін анықтау класс анықтамасының ішінде болуы мүмкін және мұндай жағдайда олар автоматты түрде орын ауыстырғандар
14
болып табылады. Орын ауыстыратын функцияларды егер функция қарапайым және қысқа болса, қолданған жөн, мысалы, Getx ( ) функциясы.
Әдетте, қауіпсіздікті жоғарылату мақсатымен кластың мүше- берілгендерін жалпыға бірдей рұқсат етілмейтін етеді және еркін бағдарлама ортасынан олармен тікелей байланысуға болмайды. Бірақ оған қарамастан олармен кластың барлығына рұқсат етілген әдістерін қолданып ерікті бағдарламалық ортадан да жұмыс істеуге болады (public:). Жоғарыда қарастырылған мысал үшін келесі әдіс қолданылады:
int Getx (void) { return x; }
жабық мүше мәнін берілген х қайтарады.
Арнайы түрде мұндай әдістердің «жүдеу» денелерін тиімділікті жоғарылату үшін орын ауыстырушы етіп класс анықтамасының ішінде енгізеді. Класс анықтамасынан тыс орналастыратын әдістерді анықтаған жағдайда әдістер тақырыбына inline спецификаторы қосылады.
«Клиент-сервер» технологиясы бойынша класс әдістерін анықтау класс анықтамасынан тыс орналастырған жөн. Көру облысының «::» рұқсат ету операторы арқылы компиляторға берілген анықталатын әдіс қандай класқа қатысты екендігін хабарлайды, мысалы:
int Classid:: f2 (int х) { әдіс денесі }
Класс анықтамасы берілген класс объектілерін құрмайды. Объектілер оларды анықтау жолымен ғана құрады, мысалы:
Classid obj1, obj2, obj Array [10];
Класс объектісінің өлшемі кластың статикалық емес мүше берілгендерінің өлшемдер қосындысымен жадыда анықталады. Класс әдістері класс объектісі үшін бөлінген жады облысының орнын алмайды.
Бірнеше файлдардан тұратын бағдарламалық жобалармен жұмыс жасағанда класс анықтамасы берілген класс объектілері қолданатын немесе оның әдістері анықталатан файлдарда болуға міндетті. Сондықтан класс анықтамасын арнайы түрде ол қажет болып табылатын файлдарда #include дерективасы көмегімен қосылатын тақырыптық файлға (хедер-файл) орналастырылады. Егер класс әдісінің анықтамасы анықталудан тыс орналасса, онда ол міндетті түрде өзі қолданылатын файлдарда анықталған болуы керек. Мұндай әдістің анықтамасы класс анықтамасымен бірге тақырыптық файлда болуы керек.
15
Белгілі бір класс объектісінің ашық мүшелеріне қатынауға рұқсат алуды тура «.» және жанама « » таңдау операторлары көмегімен жүзеге асырылады.
C++ тілінде объектілерді жою мен инициализациялау жұмыстарын орындайтын, обьектілердің жойылуы мен құрылуы кезінде автоматты түрде шақырылатын, кластың арнайы әдістері сәйкесінше конструкторлар мен деструкторлар деп аталады. Класта бірнеше конструкторларды құруға болады. Әрбір конструктордың өзінің басқалардан айырмашылығы бар параметрлері болады. Параметрлері жоқ конструктор үнсіздік конструкторы.
Деструктор әрқашан жалғыз және параметрлері болмайды.
Тек ашық мүшелері бар және конструкторы жоқ класс объектісі мәндер тізімі арқылы жай құрылымдық айнымалы сияқты инициализациялануы мүмкін.
Егер класс конструкторларының біреуі де ашық функция – класс мүшесі болып табылмаса, онда мұндай кластың мүшелері құрыла алмайды. Мұндай кластар басқа кластар (мұрагерлік) үшін базалық кластар (родительские) болып табылады.
Класс объектісін құрған кезде ол үшін сәйкес келетін конструктор автоматты түрде шақырылады. Объекттің деректер мүшесі (объект айнымалыларының) инициализациясы конструктордың орындалуы сияқты инициализациясы кезінде де орындала алады.
Конструктор параметрі өз класы бола алмайды, бірақ көшіру конструкторы сияқты оған жасалған сілтеме болуы мүмкін.
Кластың деректер компонентінің жалғыз данасы болуы үшін және әрбір жаңа кластың объектісінің құрылуы кезінде тираждалмауы үшін ол класты статикалық сияқты анықтау керек, яғни Static атрибуты болуы керек.
Кластың статикалық компоненттік функциялары нақты обьект атауы жоқ кластың Static берілгендеріне қатынасуды қамтамасыз етеді. Кластың Static функциялары функциялардың жай (статикалық емес) компоненттік барлық негізгі ерекшеліктерін сақтайды. Класқа қатысты функция нақты объекттің деректерін өңдеу үшін шақырған кезде бұл функцияға автоматты және айқын емес функция шақырылған объект көрсеткіші беріледі. Бұл нұсқауыштың бекітілген this аты бар және программалаушы үшін кластың әрбір функциясы келесі түрде анықталған:
класс_аты*const this=өңделетін_обьекттің_адресі;
this нұсқауышын қолдану тиімділігі көрінетін жағдайлар:
- берілген класс компонентінің аты класс функциясының формальды параметрінің атымен сәйкес келгенде;
- класс функциясының денесінде айқын түрде бұл функция шақырылған объект адресін көрсету қажет болғанда;
16
- функция параметрі ретінде бұл кластың функция атын жазған кезде объекттің нақты атына жол берілмегенде (керек объектіге мұндай функция сілтемесін немесе нұсқауышын берудің орнына).
Бақылау сұрақтары:
1) Белгілі бір кластың екі объектісін анықтағанда, деректер мүшелері өздерінің әртүрлі (бірдей) мәндеріне ие бола ала ма?
2) Кластың қандай деректер мүшелерін қандай жолмен инииализациялау керек?
3) this нұсқаушысы нені білдіреді?
4 Дәріс №4. Кластар достары. Кластарға арналған стандартты операцияларды қайта жүктеу
Дәрістің мақсаты: класс достары және достық функциясы ұғымдарын беру.
Дәрістің мазмұны: достық функциясының ерекшеліктері. Көшіріп алу конструкторы. Беттік және тереңдетілген көшіріп алу. Кластарға арналған операциялардың қайта жүктелуі.
Класс мүшесі болмауына қарамастан кейбір жағдайларда функция кластың жабық мүшелеріне тиесілікке (доступ) ие болғаны жөн. Егер функция класс досы немесе мүшесі болып табылатын класты friend қызметші сөзі көмегімен жарияласа, осы әрекетті С++ ортасы орындауға мүмкіндік береді,.
Достық функциялары мен кластарды қолданудың бірқатар қызықты ерекшеліктерін көрсететін мысалды қарастырайық:
#include <iostream.h>
сlass Class1; // класты алдын ала жариялау class Class2;
{ public : void ff (Class1 &ref);
};
class Class1
{ private : int x; // достық функциялары мен кластарға арналған //жол беру спецификаторының мәні жоқ
friend int main (void); // main – достық функциясы бола алады friend void f (Class1 &ref);
friend class Class3;
friend void Class2 :: ff (Class1 &ref);
}; //Class1 анықтамасының соңы
class Class3 // Class3 – Class1 класына дос { public : void func (Class1 &ref)
{ ref.x=9;
17 return;
} };
void Class2 :: ff (Class1 &ref) { ref.x=11;
return;
}
//f – Class1 класына дос қарапайым сыртқы функция void f (Class1 &ref)
{ ref.x=7;
return;
}
int main (void) {Class1 obj1;
obj1.x=5;
cout << “obj.1x=” << obj1.x << endl; //x=5 f(obj1);
cout<<“obj1.x=” << obj1.x <<endl; //x=7 Сlass3 obj3;
obj3.func(obj1)
cout<< “obj1.x=” << obj1.x <<endl; //x=9 Class2 obj2;
Obj2.ff(obj1);
cout<< “obj1.x=” <<obj1.x<<endl; //x=11 return 0;
} // main соңы
Достық функциясының ерекшеліктері:
- достық функция класс объектісіне автоматты түрде this нұсқауышын ала алмайды, сондықтан оның шақыруында міндетті түрде аргумент ретінде оған жұмыс істеуге қажет класс объектісін көрсету керек;
- консольды қосымшаның басты функциясы класқа дос болуы мүмкін;
- қажетсіз достық функциялары мен кластарын қолдануға ұмтылмау керек, себебі бұл инкапсуляция концепциясына кері болып табылады.
Кластарға арналған операциялардың қайта жүктелуі (перезагрузка).
С++ тілінің көптеген @ операциялары қолданушы типтерінің объектілерімен жұмыс істеу үшін қайта жүктелуі мүмкін. Мұндай мүмкіндіктер объект-кластар үшін де болады. @ операциясының қайта жүктелуі operator @ фунция-операциясы көмегімен жүзеге асырылады, оны класс мүшесі немесе достық функциясына айналдыру (қажет емес) немесе қарапайым (глобальды) функцияға айналдыруға болады.
Соңғы екі жағдайда функция-оператор ең болмаса бір сілтеме немесе нұсқауыш, класс типі бар аргументті қабылдау керек. Сыртқы функция -
18
операциясы үшін сәйкес класс мүшелерінің тиесілігін (доступность) ескерген жөн.
Функция - оператор атауы operator қызметші сөзінен, және одан кейін орналасқан қайта анықталатын операция белгісінен тұрады.
Операцияларды қайта жүктеу типті беру, функцияны шақыру ережелері ISO/IES14882 халықаралық стандартында берілген.
Көшіріп алу конструкторы. Беттік және тереңдетілген көшіріп алу Класс құрамына арнаулы түр конструкторы – көшіріп алу конструкторы жатады. Көшіріп алу конструкторының жалғыз параметрі ретінде, осы класс объектісіне сілтемені қолданады:
Classid : Classid (const Classid & obj) { конструктор денесі }
Көшіріп алу конструкторы жаңа обьект класс типімен бар обьектіні көшіріп алу жолымен құрылған кезде шақырылады:
- сол типтің басқа бар объектімен инициализациясы және класс типі бар жаңа объект анықтаған кезде;
- мән бойынша класс типі бар параметр - объект класс әдісіне берілген кезде;
- return операторы арқылы класс типі бар объект мәнін класс әдісінен қайтарылған кезде.
Егер программалаушы бір де бір көшіріп алу конструкторын құрмаса, онда компилятор автоматты түрде қалыпты көшіріп алу конструкторын құрады. Мұндай конструктор кластың мәліметтер өрістерінің элемент бойынша көшірілуін орындайды (беттік көшіріп алу). Егер өрістердің ең болмаса біреуі динамикалық жадының белгілі бір облысына нұсқауыш болып табылмаса, онда қалыпты конструкторды қолдану программаның дұрыс емес, яғни бұрыс жұмысына әкеледі. Осы жағдайда қалыпты көшіріп алу конструкторының орнына өзінің көшіріп алу конструкторын жобалап алған жөн:
- беттік көшіруді орындайтын конструктор (нұсқауыштың объектіге көшірілуі орындалады, ал объект көшірмесі динамикалық жадыда құрылады);
- тереңдетілген көшіріп алуы бар конструктор (динамикалық жадыда объект көшірмесі құрылады).
Қорытындысында мынаны қайталайық, егер класта динамикалық жадымен жұмыс орындалмаса және конструктор қажет болмаса, онда қалыпты көшіріп алу конструкторын қолдану көмегімен көшіріп алу конструкторын анықтау керек емес. Осындай кластарды қолданатын бағдарламалар дұрыс жұмыс істейді.
Мүмкіндігінше мән бойынша, класс типі бар параметрді кластың әдісіне және класс типі бар объекттің мәнін емес, сілтемесін оған класс әдісіне
19
қайтарудан аулақ болған жөн. Бұл жағдайда көшіріп алу конструкторы қажет емес, бұл қосымшаның шапшаңдығының жоғарылауына әкеледі.
Көрсетілген мақсатқа жету үшін келесі ережелерді қолданған жеткілікті:
- мән бойынша класс типі бар параметрді, класс әдісіне берудің орнына бұл параметрді сілтемемен берген жөн, ал сәйкес аргументтің модификациясын тоқтату үшін функция параметрін const модификаторымен қамтамасыз ету керек;
- класс типі бар объектілер үшін арифметикалық операцияларды қайта жүктегенде қайта жүктеу әдісін объектке қайтаратындай етіп жобалау керек (оны әрқашанда орындауға болады).
Бақылау сұрақтары:
1) C++ тілінің операцияларын қайта жүктеу операциялары қандай?
2) Көшіріп алу конструкторы қашан шақырылады?
3) Бірігіп көшу операторларының префиксті және постфиксті қайта жүктеуін қалай айыруға болады?
4) short int типті операндалар үшін қосынды операциясын қайта жүктеуге бола ма?
5 Дәріс №5. Үлгілер (шаблоны)
Дәрістің мақсаты: көп қолданылатын және қарсылыққа тұрақты программаларды құру мүмкіндіктері.
Дәрістің мазмұны: функция-үлгілер. Туыстық функциялар. Туыстық кластар.
Жоғары деңгейлі С++ тілінің келесідей екі негізгі сипаттамасы болып мыналар табылады: үлгілер (templates) (шаблоны) және ерекше жағдайлардың өңделуі (exception handling). Бұл сипаттамалар қазіргі уақыттағы барлық компиляторлардан қолдау табады және программалауда анағұрлым қызықты екі мақсатқа жетуге: көп рет қолданылатын және қарсылыққа төзімді программаларды құруға мүмкіндік береді.
Үлгілер көмегімен туыстық функцияларды (general functions) және туыстық кластарды (general classes) құруға болады. Туыстық функцияда немесе класта, класс немесе функция жұмыс істейтін мәліметтер типі параметр ретінде беріледі. Бұл бір класты немесе функцияны функция немесе кластың жаңа нұсқауын қолданбай-ақ деректердің әртүрлі бірнеше типтерін қолдануға мүмкіндік береді. Сөйтіп, үлгілер көп рет қолданылатын программаларды құруға мүмкіндік береді.
Көптеген алгоритмдер логикалық жағынан бірдей деректер типінен тәуелсіз, мысалы, сұрыптау алгоритмдері. Туыстық функцияны құрудың арқасында деректер типінен тәуелсіз алгоритм мәнісін анықтауға болады.
20
Туыстық функция template шешуші сөзі арқылы құрылады. Функция- үлгі анықтамасының типтік формасы:
template < class T > мәнді_қайтару функция_аты (параметрлер_тізімі) {функция денесі}
Мұндағы T - берілгендер типінің жалған аты, оны компилятор функцияның нақты нұсқасын құрғанда берілгендердің шын типінің атымен автоматты түрде ауыстырады.
Мағынасы ұқсас функциялар бар болғанда түрлі деректер типтері үшін екі шаманың ең кішісін табу үшін MyMin атты жалғыз үлгілік функцияны анықтауға болады:
template < class T > T MyMin (T x, T y) { if (x<=y) return x; else return y;}
Ол потенциалды түрде белгісіз T типімен де жұмыс істей алады.
Функциялар үлгілерінің келесі тақырыптары синтаксистік жағынан дұрыс болып табылады:
template< class T > T Fun1(T x, T y, int z) template<class T > double Fun2 (Tx, Ty)
template<class T, class W > W Fun3(Tx,Wy,bool z).
1) Үлгінің формальды параметрлерінің анықтауыштары (T,W) ең болмаса формальды параметрлер тізімінде бір рет болса да болу керек.
2) Үлгілік функцияның денесі ішінде үлгінің формальды параметрлері локальды айнымалыларды анықтау операторларында, типті беру операторларында және т. б. өзге түрлі деректердің нақты типтерімен бірдей қолданылады, яғни жұмыс істеуде деректер типтерінің толық құқылы атаулары сияқты.
3) Кәдімгі функциялар сияқты үлгілік функцияларға да прототиптерді жазуға болады, сонымен қатар оларға inline, static спецификаторларын да жазуға болады (бұл спецификаторлар үлгінің формальды параметрлер тізімінен кейін және функциямен қайтарылатын мән типіне дейін орналасу керек).
4) Функция үлгілерін анықтау мәтіні шақыру орындалатын файлдарда немесе тақырыптық файлдарда (h-файлдарда) орналастырылу керек.
5) Үлгілік функция анықталу алдында template кілттік сөзімен нұсқаулық орналасу керек.
6) Функция үлгілерінің механизмін дәлелсіз қолданудың ешқандай қажеті жоқ! Біріншіден, функция үлгілерінің деректердің абстрактты типтерімен байланысының пайдасы бар. Үлгілер механизмі глобальды
21
функциялар үшін емес кластар мен олардың әдістерінің үлгілері үшін ерекше пайдалы!
Туыстық кластар.
Туыстық функцияларын толықтыру үшін туыстық кластарды да анықтауға болады. Осы кластың объектілерін құру кезінде барлық қажетті алгоритмдер анықталып, өңделетін деректердің нақты типтері параметрлері ретінде кейінірек беріледі.
Туыстық кластар, класс құрамында жұмыстың жалпы логикасын қамтығанда пайдалы. Мысалы, бүтіндер кезегін жүзеге асыратын алгоритм символдар кезегімен де жұмыс істейді. Сонымен пошталық адрестердің байланысқан тізімін жүзеге асыратын механизм автомобильдерге арналған қосалқы бөлшектердің байланысқан тізімін де қолдайтын болады. Туыстық класс арқылы түрлі берілгендер типтеріне арналған байланысқан тізімдер кезегін жүзеге асыратын класты құруға мүмкіндік береді. Компилятор берілген объектіні құруда, объектінің тип негізінде дұрыс типін автоматты басқарады.
Класс үлгісінің сипатталу синтаксисі келесі түрде болады:
- template < үлгі_параметрлерін_сипаттау > класс_анықтамасы
- Параметрлер ретінде стандарттыға ұқсас қолданушымен анықталатын типтер үлгілер мен типтелген конструктор қолданылады.
Бір байланысты тізімді жүзеге асыратын жай туыстық класты құрайық:
#include< iostream.h >
template< class T > class List { T data;
List*next;
рublic:
List(T d); // класс конструкторы Void add(List*node)
{node next=this; next=0;}
List*getnext() {return next;}
T getdata(){return data;}
}
template< classT >List<T>::List(Td) {data=d; next=0;}
int main(void)
{List< char > start(‘a’); //start-обьект List< char >*p,*last;
//тізімді құру last=&start;
for(int i=1; i<26;i++) {p=newList<char> (‘a’+i);
p->add(last); last=p;
22 }
//тізімді шығару p=&start;
while(p)
{cout<<p->getdata();
p=p->getnext();
}
return 0;
}
Көрініп тұрғандай, туыстық класты жариялау туыстық функция жариялануына ұқсас. Тізімде сақталынатын берілгендер типі класты жариялағанда туыстыққа айналады, бірақ ол деректердің нақты типін беретін объект жарияланбай көрінбейді. Объектті құрғанда көрсетілген мәліметтер типін өзгерту жолымен тізімде сақталған мәліметтер типін өзгертуге болады.
Кейбір қорытындыларды келтірейік және үлгілерді сипаттаудың негізгі ережелерін атап өтейік:
1) Класс үлгісінің ішінде тип параметрі тип спецификациясы қолданылатын кез келген жерде қолданылады.
2) Үлгі параметрінің әрекет ету облысы – үлгі параметрінің сипаттау нүктесінен класс үлгісінің соңына дейін.
3) Класс үлгісінің әдістері автоматты түрде функция үлгілеріне айналады. Егер әдіс класс үлгісінен тыс сипатталса, онда әдіс тақырыбы келесі құрылымға ие болу керек:
template<үлгі_параметрін_сипаттау>
типті_қайтару класс_аты < үлгі_параметрлері>::
Үлгі параметрлерін сипаттау әдіс тақырыбын сандық және позициялық түрінде сақтай отырып, класс үлгісіне сәйкеес келу керек.
4) Локальды кластар үлгілерді өз элементтері ретінде қолдана алмайды.
5) Класс үлгілерінің әдістері виртуальды бола алмайды.
6) Класс үлгілеріне статикалық элементтер, достық функциялар мен кластар ене алады.
7) Класс үлгісінің ішінде достық функциялардың үлгілерін анықтауға болмайды.
8) Класс үлгілері үлгіліктерден және жай кластардан туынды бола алады, сонымен қатар үлгілік және жай кластар үшін базалық болып табыла алады.
Бақылау сұрақтары:
1) Класс үлгілерін анықтау мүмкіндігі не?
23
2) Үлгілік функцияға арналған машиналық кодтың шын генерациясы қалай және қашан жүргізіледі?
3) Үлгілік функцияны шақырғанда нақтыландыру қалай орындалады?
4) Белгілі бір функционалдық үлгінің қай функциясы маманданған деп аталады?
5) Кезекті жүзеге асыратын туыстық класты құрыңыз және көрсетіңіз.
6 Дәріс №6. Мұрагерлік
Дәрістің мақсаты: кластар мұрагерлігін түсіндіру.
Дәрістің мазмұны: кластың қорғалған мүшелері. Конструкторлар, деструкторлар және мұрагерлік.
Мұрагерлік – С++ тіліндегі объектіге бағытталған программалаудың басты механизмдерінің бірі. Оның көмегімен жалпыдан жекеге ауыса отырып өте күрделі кластарды құруға болады, сонымен қатар қорытынды кластардан айрықшаланатын жаңа кластарды өсіруге болады.
Жаңа класты жобалай отырып, алдын-ала оның объектілері қандай анағұрлым жалпы ерекшеліктерге ие болу керектігін анықтау және ұқсас дайын кластың бар жоқтығын тексеру қажет. Басқаша айтқанда, басында қайта өндіретін класс жоспарын «ірі көріністермен» құрған жөн, ал кейін бір уақытта жаңа қасиеттерді ала отырып, тәртіп пен қасиеттерді (яғни мүше деректер мен класс әдістері) мұраға алатын жаңа кластарды құрылған класс негізінде құра отырып, рет-ретімен бөлшектенуге көшеміз.
Түрлі класс объектілері мен кластардың өздері алдын-ала құрастырған кластар иерархиясына сай келетін объектілер иерархиясы құрылған кезде мұрагерлік қатынасында бола алады.
Бір класс екінші класс мұрагері болғанда жазбаның келесі негізгі пішіні қолданылады:
{ class_ класс_ аты_ as базалық_ класс_ аты _ туынды { туынды класының анықтамасы
Мұндағы as – рұқсат ету спецификаторы ( access specifier) базалық класс элементтері ( base class) туынды класқа (derived class) қалай мұрагер болатынын анықтайды.
Егер as public болса, онда барлық ашық мүшелері туындысы да ашық болып қалады. Егер as private шешуші сөзі болса, онда базалық кластың барлық мүшелері туынды класта жабыққа айналады. Екі жағдайда да базалық кластың барлық private мүшелері туынды класта қалай мұрагер болуына тәуелсіз, жабық және рұқсатсыз болып қалады.
24
Егер as private болса, онда базалық кластың ашық мүшелері туынды класта жабық болуына қарамастан олар туынды кластың функция мүшелері үшін рұқсат етілген болып қалатынын ескерген жөн.
Техникалық жағынан рұқсат ету спецификаторы міндетті емес. Егер ол көрсетілмеген туынды класс class шешуші сөзімен анықталса, онда базалық класс struct қызметші сөзімен үнсіздік бойынша ашық түрде мұра болады.
Түсініктілік үшін рұқсат ету спецификаторын нақты түрде беру дұрыс.
Public спецификаторымен мұрагерлік мысалын көрсетейік:
class Base { int x;
public:
void setx (int n) {x=h;}
void showx( ) { cout « x «endl ;}
};
class Derived: public Base { int y;
public:
void setx (int n) {x=h;}
void showx( ) { cout « x «endl ;}
};
int main (void) { Derived obj;
obj.setx (10);
obj.sety (20);
obj showx( );
obj showy( );
return 0;
}
Base класы ашық болып, мұраға қалдырылатындықтан оның ашық функциялары туынды класқа ашық болып қалады және сондықтан да программаның кез келген бөлігінен рұқсат етілген болады. Бұл функцияларды main ( ) функциясынан сәйкесінше дұрыс шақыру керек.
Базалық кластың мүшелері рұқсат етілмеген болады, сондықтан туынды класс ішінде х айнымалысына тікелей рұқсат алуға талаптану әрекеті дұрыс емес. Ал базалық кластың ашық функциясы арқылы бұл мүмкін болады.
Егер класс сияқты жабық мұраға қалса, онда базалық кластың барлық мүше деректері мен туынды класта жабық болады және одан тыс қана рұқсат етілген болады. (Derived типті берілген объекттер үшін олар жабық болады).
Рrivate спецификаторын қолдана отырып мұра ету кезінде базалық кластың ашық мүшелері туынды класта жабық болады.
# include < iostream.h >