Begin
Assign (f,’b.pas’); {айнымалыны нақты файлмен байланыстыру}
Rewrite (f); {файлды ашу}
… {файл мазмұнын өңдеу}
Close (f); {файлды жабу}
Erase (f); {файлды жою}
End.
Мұнда FILE OF CHAR типіне тиісті f файлдық айнымалы жарияланады (бұл файл символдар тізбегінен тұрады). Осыдан кейін осы айнымалы b.pas файлымен байланыстырылады. Осыдан кейін файл ашылады (REWRITE процедурасының көмегімен). Ары қарай файл мазмұнына қандай-да бір өңдеулер жүргізіледі. Ең соңында B.PAS файлы жабылып (Close процедурасы), жойылады (Erase процедурасы).
Жазу-оқу
Turbo Pascal-да файлға ақпаратты жазуды және файлдан оқуды жүзеге асыру үшін текстік және типтендірілген файлдар үшін Read және Write процедуралары, ал типтендірілмеген файлдар үшін BlockRead және BlockWrite процедуралары қолданылады. Және де Read және Write процедураларын қолдану файл түріне байланысты (текстік әлде типтендірілген бе) ерекшеліктерге ие.
Read және Write процедураларынан өзге текстік файлдар үшін ReadLn және WriteLn процедуралары қолданылады.
Файл мазмұнымен жұмыс істеу
Айталық, файлдық айнымалы жариялап, оны дисктағы қандай-да бір файлмен байланыстырдық, содан кейін оны RESET немесе REWRITE процедурасының көмегімен аштық. Ары қарай не істеуге болады? Файлдың мазмұнымен оны оқу мен оған жазудан басқа не істеуге болады?
Файлдарды әр элементтері бойынша өңдеу
Айталық, қандай-да бір файлдың әр элементін қалай-да өңдеу керек. Мысалы, егер файлдың бұл элементтері – сандар болса, онда оларды қандай-да бір коэффициентке көбейту керек, ал егер бұл жолдар болса, әр жолдың соңына символдар қосу керек. Мұндай есептерді шешу үшін файлды ашу керек, содан кейін файл соңы маркеріне жеткенше оның әрбір элементін өңдеу керек. Бірақ файл соңына жеткенімізді қалай анықтау керек (яғни, ағымдағы позиция нұсқауышы соңының белгісінің алдында тұрғанын)? Ол үшін Turbo Pascal-да EoF стандартты функциясы бар.
Егер ағымдағы позиция нұсқауышы соңғы элементтен кейін тұрса немесе файл бос болса, онда EoF функциясы TRUE мәнін қабылдайды. Кері жағдайда функция FALSE мәнін қабылдайды. Бұл функцияның тақырыбы типтендірілген және типтендірілмеген файлдар үшін төмендегідей болады.
Function EoF (var f):Boolean;
Текстік файлдар үшін.
Function EoF (var f: Text):Boolean;
Мұндағы f – файлдық айнымалы (текстік, типтендірілген немесе типтендірілмеген).
7-суреттегі үш бейнеге назар аударайық.
Осы жерде көрсетілген үш жағдайдың алғашқы екеуінде EoF функциясы FALSE мәнін қабылдайды, ал үшінші жағдайда - TRUE мәнін қабылдайды.
EoF функциясы қолданылған программаны төмендегі мысалдан көруге болады.
Program EndOfFile;
Var f:text;
Symb:char;
Begin
Assign(f, ‘C:\autoexec.bat’);
Reset(f);
Repeat
Read(f, symb);
Write(Symb);
Until EoF(f)
End.
Бұл мысалда Text типті f файлдық айнымалы жарияланып, ол С түпкі каталогындағы Autoexec.bat файлымен байланыстырылады. Осыдан кейін файл оқу үшін ашылады (Reset процедурасы арқылы). Содан кейін Repeat цикл операторы арқылы ондағы символдарды циклық оқу орындалады. Цикл денесі болатын құрылымдық оператор өзіне кезекті символды оқу операторын (Read процедурасы) және осы символды экранға шығару операторын (Write) қамтиды. Нәтижесінде Autoexec.bat файлының түгел мазмұны экранға шығарылады.
Autoexec.bat файлының орнына Assign процедурасының параметрі ретінде кез-келген басқа текстік файлды алуға болады. Нәтижесінде бұл файлдың да мазмұны экранға шығарылады.
Файлды қию
Кейде белгілі позициядан бастап файлдың соңын жою қажеттілігі туындайды. Мұндай жағдайда Turbo Pascal-да Truncate стандартты процедурасы бар.
Truncate процедурасы ашық файлға қолданыла отырып, оның мазмұнын ағымдағы позициядан бастап, соңына дейін жояды.
Procedure Truncate (var f);
Мұндағы f - Text типінен өзге кез-келген типті файлдық айнымалы. Нұсқауышты файлдағы белгілі бір элементтің алдына орналастыру мүмкіндігі бар ма? Жалпы Turbo Pascal-да ол үшін Seek процедурасы бар. Дегенмен, бұл процедурамен таныс болмағандықтан, параметрлі цикл операторының (For) көмегімен файлдағы (типтендірілген немесе типтендірілмеген) белгілі элементтер санын оқуды ұйымдастырып, соңынан Truncate процедурасын қолдануға болады. Truncate процедурасы қолданылған программа келесі мысалда көрсетілген.
Program Trunc;
Var f:file of char;
i:integer;
j:char;
procedure out;
begin
Reset(f);
While not EoF(f) do
Begin
Read(f, j);
Write(j)
End
End; {Out}
Begin {Program}
Assign(f, ‘FILE.TXT’);
Rewrite(f);
{A, B, C, D, E, F енгізу}
FOR J:=’A’ to ‘F’ do Write(f, j);
WriteLn(‘Қиғанға дейінгі файл:’);
Out;
Reset(f);
{3 жазбаны оқу}
For i:=1 to 3 do Read(f, j);
Truncate(f); {Файлды қию}
WriteLn;
WriteLn(‘Қиғаннан кейінгі файл:’);
Out; {Файл мазмұнын шығару}
Close(f);
Erase(f)
End. {Program}
Бұл программада типтендірілген f файлдық айнымалы жарияланып, соңынан FILE.TXT файлымен байланыстырылған. Осыдан кейін осы файл Rewrite процедурасының көмегімен ашылады (егер мұндай файл болмаса, Rewrite процедурасының жаңа бос файл жасайтынын білеміз). Егер файлдық айнымалымен файлды байланыстырған кезде каталог көрсетілмесе, үнсіз келісім бойынша ағымдағы каталог қолданылады. Сонымен FILE.TXT файлы Turbo Pascal файлдары орналасқан каталогта құрылады. Бірақ программа соңында шақырылған Erase процедурасы бұл файлды жояды.
Осылайша файл құрылды, ашылды, енді оған алты элемент – ‘A’, ‘B’, ‘C’, ‘D’, ‘E’, ‘F’ символдары енгізіледі де, файл мазмұны экранға шығарылады. Осыдан кейін файлдың үш элементі оқылады да, Truncate процедурасының көмегімен файлды қию орындалады. Содан кейін файл мазмұны тағы да экранға шығарылады, осымен Truncate процедурасын қолдану нәтижесі көрінеді. Ең соңында басында құрылған FILE.TXT файлы жабылып (Close процедурасы), жойылады (Erase процедурасы). FILE.TXT файлын экранға шығару Out процедурасы арқылы орындалған. Ол программа денесінде екі рет шақырылады (толық файлды және қиылған файлды экранға шығару үшін).
Trunc программасының экранға шығарылуы төмендегідей көрінеді.
Қиғанға дейінгі файл:
ABCDEF
Қиғаннан кейінгі файл:
ABC
Trunc программасының әрекетін 8-сурет бейнелейді.
Қалауыңызша келесі операторлардағы ‘F’ және 3 мәндерін өзгерте отырып, файлға жазылатын символдар ұзындығы мен Truncate процедурасы қолданылғаннан кейін қалатын әріптер санын өзгертіп көруге болады.
FOR J:=’A’ to ‘F’ do Write(f, j);
және
For i:=1 to 3 do Read(f, j);
11–ДӘРІС. Нұсқама типтер және динамикалық жады.
Статикалық және динамикалық айнымалылар.
Айнымалылардың моделі.
Адрестер және нұсқамалар. Нұсқамаларды хабарлау.
Нұсқамаларды қолдану.
Динамикалық жады.
Динамикалық жадыларды ерекшелеу және босату.
Динамикалық жадылармен жұмыс істеу процедуралары мен функциялары.
Үйме администраторы.
Осы уақытқа дейін біз статикалық мәліметтер және айнымалылармен жұмыс істедік. Мұндай айнымалылар программаның басында жарияланып, программаның жұмысы аяқталғанша бар болады – бұл статикалық айнымалылар. Сәйкесінше, бұл айнымалыларды сақтауға арналған жады бөлініп, ол программа жұмысы барысында босамайды. Әрине, бұл компьютер жадысын пайдаланудың тиімді емес тәсілі. Бұл дәрісте мүмкін тәсілді қарастырамыз – ол динамикалық айнымалылар, яғни мұндай айнымалылар оларды қолдану алдында жасалып, оларды қолданып болғаннан кейін бірден жойылады (алып тұрған жадыны босатады).
Әрине, Turbo Pascal тілінде мұны жүзеге асыруға болады және осы мақсатта динамикалық жады қолданылады.
Динамикалық жады үйме (куча) деп те аталып, Turbo Pascal тілінде шамамен 300000 байт көлемі бар байттар массиві ретінде қарастырылып, әлдеқайда үлкен мәліметтер құрылымдарын өңдеуге мүмкіндік береді. Алдыңғы дәрістерде кәдімгі жадыны қолдана отырып, LongInt типті 20000 элементтен тұратын массив жасай алмадық (ол үшін 80000 байт жады қажет, ал құрылымданған типтер үшін максималды өлшем 65520 байт). Дегенмен, динамикалық жадының көмегімен әлдеқайда үлкен массивті өңдеуге болады. Әрине, мәліметтерді динамикалық түрде орналастыру кезінде статикалық мәліметтер сияқты оларға атаулары бойынша қатынас жасай алмаймыз. Сол сияқты динамикалық түрде орналасқан мәліметтердің саны мен типі алдан ала белгілі болмайды. Мәліметтер үшін динамикалық жады программаның жұмысы барысында бөлінеді (босатылады). Turbo Pascal-да динамикалық жадыны басқару үшін нұсқауштар деп аталатын қолайлы құрал пайдалынады.
Нұқауыштар
Компьютердің оперативті жадысы - бұл әрбіреуі бір байт ақпаратты сақтауға арналған және әрбіреуі оған сол арқылы қатынас жасауға болатын жеке адреске ие ұяшықтар жиыны. Ал нұсқауыш - бұл программаның сипаттау бөлімінде жарияланған, мәні жадының бір байтының адресі болып табылатын айнымалы.
Turbo Pascal-да қолданылатын нұсқауыштар типтендірілген және типтендірілмеген болып бөлінеді. Егер екінші нұсқауыш – ол кез-келген типті мәліметтер адресінен тұратын айнымалы болса, онда бірінші нұсқауыш - осы нұсқауышты жариялау кезінде көрсетілген типті мәлімет адресінен тұрады. Типтендірілмеген нұсқауыштар төмендегідей жарияланады.
Var
pp : pointer;
Мұндағы POINTER - мәліметтердің стандартты типі; pp – кез-келген типті мәліметтер сақтала алатын жады адресінен тұратын айнымалы. Типтендірілген нұсқауыштарға келетін болсақ, олардың сипатталуы Turbo Pascal-да төмендегідей.
Var
px : ^char;
рy : ^intеger;
Бұл мысалда екі типтендірілген нұсқауыш рх және ру сипатталған. Бұл айнымалылардың мәндері сәйкесінше char және integer типті мәліметтер орналасатын оперативті жадыдағы адрестерді көрсетеді. Типтендірілген нұсқауыш сипаттамасы сол типті статикалық айнымалы сипаттамасынан тек нұсқауыш жағдайында типтің алдында «^» символы болатындығымен ғана ерекшеленетінін байқау қиын емес.
Қортындылайық: динамикалық жадыны қолдану керек болса, сипаттау бөлімінде айнымалының өзі емес, оған нұсқауыш (немесе сілтеме) жарияланады. Бұл жағдайда нұсқауыш кәдімгі айнымалыны, ал ол сілтейтін айнымалы - динамикалық айнымалыны көрсетеді. Мұнда, егер өрнекте нұсқауыш қатысу керек болса, сипаттау бөлімінде жарияланған идентификатор қолданылады, мысалы рх. Дегенмен, егер өрнекте нұсқауыш сілтейтін динамикалық айнымалы қатысуы керек болса, онда нұсқауыш идентификаторы «^» символымен толықтырылады, мысалы рх^. Мұндай әрекет атауын өзгерту деп аталады. Нұсқауыштарды қолдануды үйрену керек болса, осы абзацтағы айтылғандарды міндетті түрде меңгеру керек.
Мысал қарастырайық.
Type
DatePointer=^Date;
Date=record
year:1900..2100;
month:1..12;
day:1..31;
next:DatePointer
end;
Var
pd: DatePointer;
Бұл мысалда жазбаны сипаттайтын Date типіне нұсқауыш болып табылатын Date Pointer типі жарияланған. Егер мұқият қарайтын болсақ, DatePointer типі ол сілтейтін Date типінен бұрын сипатталып тұр. Және де Datе жазбасының бір өрісі Date Pointer типіне жатады. Жалпы алғанда Turbo Pascal-да әлі сипатталмаған типтерге сілтеме жасауға болмайды, дегенмен осы жағдайда (нұсқауыштармен жұмыс істегенде жиі кездесетін жағдай), сипаттауларды қалай орналастырса да, әлі сипатталмаған типке сілтеме жасаудан қаша алмаймыз. Сондықтан нұсқауыштар үшін бір ерекшелік жасалынған: динамикалық мәліметтерге нұсқауыштың типі, мәліметтердің өздерін сипаттаудан бұрын жариялана алады. Ескерту: типтендірілген нұсқауыштарға қолданылатын меншіктеу амалы тек бір типті мәліметтерге жасалынатын нұсқауыш үшін мүмкін болады. Айталық, осындай нұсқауыштар программада жарияланған болсын.
Var
px, py:^char;
pz:^intеger;
Бұл жағдайда меншіктеу амалы px және py нұсқауыштарына ғана мүмкін болады.
px:=py;
Ал келесі операторларды қолдануға болмайды.
pх:=pz;
немесе
pz:=py;
Сонымен қатар типтендірілмеген нұсқауыш меншіктеу операторында кез-келген типтендірілген нұсқауышпен бірге қатыса алады. Мысалы, программада келесі нұсқауыштар жарияланған.
Var
px : ^char;
py : ^intеger;
pz : pointer;
Бұл айнымалылар үшін келесі меншіктеу амалдары мүмкін.
px:=pz; py:=pz;
pz:=py; pz:=px;
Осыдан, типтендірілмеген нұсқауыштар – мәліметтер типтерін түрлендірудің қолайлы құралы деген қортынды жасауға болады.
Нұсқауыш қалпы
Нұсқауыш үшін, ол айнымалыларды сипаттау бөлімінде жарияланғаннан кейін үш қалып мүмкін. Нұсқауыш қандай-да бір айнымалы адресінен, NIL «бос» адрестен тұруы мүмкін немесе анықталмаған қалыпта болуы мүмкін. Бірінші жағдайды түсіндірудің қажеті жоқ. Екінші жағдайда, егер нұсқауыштың ештеңеге нұсқауы қажет болмаса, онда оған арнайы NIL мәні меншіктеледі. Ал анықталмаған қалыпқа келетін болсақ, ол программа жұмысы басында (нұсқауышқа қандай-да бір адрес немесе NIL мәні меншіктелгенге дейін) немесе осы нұсқауыш сілтейтін жадыны босатқаннан кейін орын алады.
Динамикалық жадыны бөлу және босату
Мұнда типтендірілген және типтендірілмеген нұсқауыштар үшін динамикалық жадыны бөлудің (резервтеудің) ерекшеліктері қарастырылады. Және де алдында бөлінген жадыны қалай босатуға болатынын анықтаймыз.
Типтендірілген нұсқауыштар үшін
Типтендірілген нұсқауыштар сілтейтін динамикалық түрде орналастырылған айнымалылар үшін жады сәйкесінше New және Dispose процедуралары арқылы бөлінеді және босатылады. New процедурасы типтендірілген нұсқауыш сілтейтін жаңа динамикалық айнымалы жасайды. Бұл процедураның тақырыбы мынадай:
Procedure New (Var p: Pointer);
Мұндағы р – типтендірілген нұсқауыш.
Dispose процедурасы типтендірілген нұсқауыш сілтейтін динамикалық айнымалының жадындағы алып тұрған орнын босатады. Тақырыбы мынадай:
Procedure Dispose (Var p: Pointer);
Мұндағы р – типтендірілген нұсқауыш.
Динамикалық жадыда орналасқан айнымалыларға нұсқауыштар қолданылған программаның схематикалық түрі төмендегідей болады.
Var
px, py: ^ char;
pz: ^ integer;
begin
New (px);
New (py);
New (pz);
px ^:=’A’;
py ^:=’7’;
pz ^:=’666’;
…
Dispose (px);
Dispose (py);
Dispose (pz);
…
end.
Бұл программада айнымалыларды сипаттау бөлімінде 3 типтендірілген нұсқауыш жарияланған. Соңынан программа денесінде бұл нұсқауыштар сілтенетін динамикалық айнымалылар үшін New процедурасының көмегімен динамикалық жады бөлінген. Осыдан кейін динамикалық айнымалыға типтеріне сәйкес мәндер меншіктеуге және оларды әр түрлі өрнектерде қолдануға болады. Px, Py және Pz айнымалылардың қажеті болмаған кезде олар үшін бөлінген жады Dispose процедурасының көмегімен босатылады. Осыдан кейін босатылған жадыны программада жарияланған және басқа операторларда қолданылатын басқа айнымалылар үшін резервтеуге болады. Dispose және New процедурасын қолданатын программа мысалы төмендегідей.
Program New_Disp;
Type
Ar=array [1..10] of integer;
Var
P:= ^ ar;
Begin
Writeln;
Writeln(‘Жады бөлгенге дейін бос’, MemAvail, ‘байт’);
New (P);
Writeln(‘Жады бөлгеннен кейін бос’, MemAvail, ‘байт’);
Dispose(p);
Writeln(‘Жады босатқаннан кейін бос’, MemAvail, ‘байт’);
End.
Мұнда MemAvail функциясының көмегімен динамикалық жадының бос көлемі туралы мәлімет экранға шығарылады, яғни жадыны бөлгенге дейінгі және жадыны бөлгеннен кейінгі, сол сияқты жадыны босатқаннан кейінгі бос орын туралы мәліметтер көрсетіледі.
MemAvail функциясы үймедегі барлық бос жадының санын көрсетеді. Әдетте бос жады тұтас блокты емес, бөлінген аудандардың жиынтығын көрсетеді. Функцияның нәтижесі Longint типті мән қабылдайды. Бұл функцияның тақырыбы төмендегідей.
Function MemAvail: Longint;
12-ДӘРІС. Деректердің дннамикалық құрылымы.
Рекурсивтік деректердің типтері.
Байланысқан тізімдер.
Стектер. Кезектер. Дектер. Ағаштар.
Екілік ағаштардың негізгі амалдары.
Динамикалық мәліметтердің екі түрі
Нұсқауыштар сілтейтін динамикалық мәліметтерді екі категорияға бөлуге болады: ішкі сілтемелері жоқ мәліметтер және іскі сілтемелері бар мәліметтер.
Ішкі сілтемелері жоқ динамикалық мәліметтер
Бұл мәліметтер статикалық мәліметтерден тек қана мәліметтерді сипаттау бөлімінде айнымалылар емес, оларға сілтемелер ғана жарияланатындығымен ерекшеленеді. Ал айнымалылардың өздері программа жұмысы барысында оларға жады бөлінеген кезде (New немесе GetMem процедурасымен) немесе бұл жады босатылған кезде (Dispopse немесе FreeMem процедурасымен) жасалып, жойылады.
Осындай статикалық мәліметтермен салыстырғанда олардың артықшылығы неде?
Алдында айтылғандай, статикалық мәліметтер үшін жады программа жүктелгенде бөлінеді де, программа жұмысы аяқталғанша босамайды. Ал динамикалық мәліметтер үшін (ішкі сілтемелілері үшін де, сілтемесіздері үшін де) жады сол динамикалық айнымалыны қолдану кезінде бөлінеді де, оны қолданып болғаннан кейін бірден босатылады. Сонымен, динамикалық жадыны қолдана отырып, аз көлемді оперативті жадыны пайдалануға болады. Басқаша айтқанда, динамикалық жадыны пайдалану үлкен көлемді динамикалық жадымен жұмыс істеуге мүмкіндік береді. Мысал ретінде массивтерді өңдеуді алуға болады. Алдында айтылғандай 15 ммың элементі бар массивтерді өңдеуге болады, ал 20 мың элементі бар массивті өңдей алмаймыз. Төмендегі мысалда динамикалық жадыны қолданып, көлемді ақпараттық құрылымдармен жұмыс істеуге болатынын көруге болады.
Статикалық және осындай динамикалық (ішкі сілтемесі жоқ) құрылымдарды қолдану мысалдарын 6-кестеден көруге болады.
6-кесте
Статикалық айнымалылар
|
Динамикалық айнымалылар
|
Var
A:Boolean;
B: integer;
X:array[1..10] of integer;
J:1..10;
Begin
A:=true;
B:=44;
For j:=1 to 10 do
Read(x[j]);
…
End.
|
Type
V = array[1..10] of integer;
Var
Pa:^Boolean;
Pb:^integer;
Px:^v
J:1..10;
Begin
new(pa);
new(pb);
new(px);
pa^:=true;
pb^:=44;
for j:=1 to 10 do
read(px^[j]);
…
Dispose(pa);
Dispose(pb);
Dispose(px);
End.
|
Бұл кестеде екі программа үзіндісін көруге болады, біріншісінде статикалық айнымалылар қолданылады (олардың екеуі Boolean және integer типті, ал үшіншісі массив), ал екіншісінде - осындай динамикалық айнымалылар. Динамикалық жадыны қолданудың негізгі ерекшелігі бұл айнымалыларға жады бөлу, содан кейін оны босату қажеттілігі болып табылады.
Ескрету: бірінші программада массив төмендегідей жарияланған:
X:array[1..10] of integer;
Ал екінші программада типтерді жариялау бөлімінде V типі жарияланған.
V = array[1..10] of integer;
Осыдан кейін айнымалыларды жариялау бөлімінде V типті мәліметтерге нұсқауыш жарияланған.
Px:^v;
Неліктен екінші программада біріншідегідей массивке нұсқауыш жарияланған жоқ?
Px: array[1..10] of integer;
Бірақ, бұлай жазып, соңынан программаны іске қоссақ, программаның осы нүктесінде (^ белгісінен кейін) идентификатор күтілетіндігі жөнінде қателік туралы хабарлама келеді. (array – идентификатор емес, резервтелген сөз). Басқаша айтқанда нұсқауышты тікелей массивке жариялауға болмайды. Бұл кедергіні айналып өту үшін алдымен V пайдаланушы типін жариялауға тура келді.
V = array[1..10] of integer;
Содан кейін V типті мәліметтерге нұсқауыш жарияланды.
Px:^v;
Осы жерде айтылғандардың жазбалар мен жиындарға да қатысы бар, себебі Record және Set – бұлар да резервтелген сөздер.
Көлемді массивтермен жұмыс істеу
Алдыңғы тақырыпта айтылғандай LongInt типті 15 мың элементтен тұратын массивті өңдей аламыз, ал 20 мың элементтен тұратын массивті өңдей алмаймыз. Себебі құрылымданған типтер үшін максималды өлшем 65520 байт, ал динамикалық жадының (немесе үйменің) көлемі шамамен 300000 байт. Неге көлемді массивтерді өңдеу үшін осы жады пайдаланылмайды? Дегенмен динамикалық жадыны пайдаланғанда да құрылымданған типтер үшін максималды өлшемге шектеу қойылады (65520 байт). Сондықтан қосымша динамикалық жады бөле отырып (NEW процедурасы арқылы), жай ғана айнымалылырды сипаттау бөлімінде массивті жариялай салу мүмкін емес. Бірақ 65520 байт бөгетті жеңу үшін жады бөліктеріне (немесе блоктарына) типтендірілмеген нұсқауыштар болып табылатын 9 элементтен тұратын массив құруға болады. Мұнда осындай блоктардың әрбіреуі LongInt типті 8000 элементке арналған. (Басқаша айтқанда біз 72 мың элементтен тұратын массивпен жұмыс істеуге тырысамыз – бұл жуық шамамен динамикалық жадының мүмкіндіктеріне сәйкес келеді). Неліктен біздің көлмеді массивімізбің блоктары (8000 элементтен) сақталатын жады бөліктеріне сілтемелер үшін типтендірілмеген нұсқауыштар қолданылады. Себебі типтендірілмеген нұсқауыш нұсқайтын динамикалық айнымалыға жады резервтеу үшін GetMem процедурасы қолданылады. Ал бұл процедураның типтендірілген нұсқауыштар үшін қолданылатын New процедурасынан ерекшелігі резервтелетін жадының көлемін көрсететін параметрге ие. Басқаша айтқанда бұл тәсіл 8000 элементтен тұратын блоктың бірінші элементіне нұсқауышты анықтауға және бір мезгілде блоктың қалған 7999 элементі үшін жады резервтеуге мүмкіндік береді.
Келесі мысалда осындай программа көрсетілген:
Program array2;
Const number=8000; {бір блоктағы элементтер саны}
Type
ab=array[0..8] of longint;
pab=^ab;
Var
Ch:array[0..8] of pointer;
Total, i:longint;
Begin
Total:=number*9; {9 блоктағы элементтерсаны}
Writeln(‘Бос жады=’, MemAvail, ‘; ең үлкен бөлік=’, MaxAvail);
For i:=0 to 8 do
GetMem(ch[i], number*SizeOf(longint)); {жады резервтеу}
For i:=0 to total-1 do
Pab(ch[i div number])^[i mod number]:=i; {реттік номерді меншіктеу}
For i:=0 to total-1 do
If (i mod 1000=0) or (i=total) then
Write(i:10, pab(ch[i div number])^[i mod number]:6);
Writeln;
Writeln(‘Бос жады=’, MemAvail, ‘; ең үлкен бөлік=’, MaxAvail);
Readln;
End.
Мұнда Number тұрақтысы блоктағы элементтердің санын береді. Ch айнымалысы (Ch:array[0..8] of pointer) әр блоктағы бірінші элементтерге нұсқайтын типтендірілмеген нұсқауыштар массивін сипаттайды. Total айнымалысы барлық блоктардағы элементтердің жалпы санын (Total:=Number*9) көрсетеді.
Динамикалық жадыны бөлгенге дейін және бөлгеннен кейін экранға үйменің жалпы бос кеңістігінің және оның ең үлкен үзіліссіз бөлігінің мәні (сәйкесінше MemAvail және MaxAvail функциялары) шығарылады. Сонымен қатар біз өңдейтін массивке динамикалық жады бөлінген:
For i:=0 to 8 do GetMem(ch[i], number*SizeOf(longint))
i айнымалысының мәні жады бөлінетін кезекті блоктың номеріне сәйкес келеді. GetMem процедурасының (типтендірілмеген нұсқауыш үшін динамикалық жады фрагментін резервтейтін) екі параметрі бар. Оның бірінішісі (ch[i]) – блоктың бірінші элементіне арналған динамикалық жады облысына нұсқайтын типтендірілмеген нұсқауыш. Процедураның екінші элементі (number*SizeOf(longint)) динамикалық айнымалының байт бойынша өлшемін анықтайды. Біздің жағдайымызда Number – бұл блоктағы элементтер саны (8000). SizeOf функциясы көрсетілген объектінің ішкі көрсетілімінің ұзындығын береді (LongInt типі үшін – 4 байт). Енді қанша байт жады резервтелетін есептеуге болады – 9 блокты 8000 блок элементіне көбейтіп, содан кейін әрбір элементті 4 байтқа көбейтеміз. Нәтижесі 288 мың байт. MemAvail функциясының программа басында және соңында беретін мәндерінің арасында тура осындай айырмашылық болуы керек.
Ары қарай программа кейбір (цикл параметрінің мәндерін) мәндерді көлемді массивтің әр элементіне бөлінген жады адрестері бойынша орналастырады.
For i:=0 to total-1 do
рab(ch[i div number])^[i mod number]:=i
Бұл оператордың екінші жартысы мұқият зер салуды талап етеді. Бірінші жартысы түсінікті - for i:=0 to total-1 do параметрлі цикл операторы біз жасаған динамикалық жадыдағы тоғыз блокта қамтылған әрбір элементке қатынас жасайды. Бірақ қатынасты қалай жасайды? Оны түсіну үшін төмендегі 3-суретке назар аударайық.
3-суретте көрсетілген программа жолында i mod number өрнегі – блоктағы әр элемент номері. Ch – бұл блоктардың бірінші элементтеріне 9 нұсқауыштан тұратын массив, сондықтан ch[i div number] өрнегі 9 блоктың бірінші элементтеріне қатынасты көрсетеді.
Бірақ әрбір блоктың әр элементіне қалай қатынас жасауға болады? Ол үшін ch массиві (типтендірілмеген нұсқауыштар массиві) Pab типіне келтіріледі (рab(ch[i div number])). Pab – бұл LongInt элементтерінің массивіне нұсқауыш екенін білеміз. Содан кейін бұл нұсқауыштың атауы өзгертіледі (яғни, массивтің өзіне қатынасқа түрлендіріледі) және массив идентификаторын көрсететін (рab(ch[i div number])^) өрнекке ([i mod number]) индексі қосылады. Осылайша, рab(ch[i div number])^[i mod number]:=I өрнегі LongInt типті 72000 (8000*9) элементтен тұратын массивтің әрбір элементіне қатынас жасайды.
Содан кейін экранға массивтің әрбір мыңыншы, сол сияқты соңғы элементтері шығарылды.
For i:=1 to total do
If (I mod 1000=0) or (i:=total-1) then
Write(i:10, pab(ch[I div number])^[I mod number]:6);
Әрине, әрбір элементтің мәні цикл параметрінің і мәнімен бірге шығарылады (бақылау үшін) – бұл мәндер бірдей болуы керек.
Ең соңында, экранға үйменің жалпы бос кеңістігінің және оның ең үлкен үзіліссіз бөлігінің мәні (сәйкесінше MemAvail және MaxAvail функциялары) шығарылады. Мұндай салыстырулар динамикалық жадының ұсынатын мүмкіндіктерін демонстрациялайды. Осы программаның нәтижесі экранда қалай көрінетіні 4-суретте келтірілген. Статикалық жадыны қолданып LongInt типті 15000 элементті массивті ғана өңдеуге болса, динамикалық жадыны қолдана отырып, осындай 72000 элементті қамтитын массивті өңдей алдық. Осы программа динамикалық жадыны бөлдік (GetMem процедурасы арқылы), бірақ соңынан босатқан жоқпыз.
Мәселе мынада: жадыны боосату – мақсат емес. Жадыны тек басқа айнымалыларға қолдану қажет болған кезде ғана босату керек. Біздің жағдайымызда динамикалық жадыны босату қажет мезетте программа өз жұмысын аяқтайды. Ал программаны қайта жүктегенде динамикалық жады бастапқы көлемге қайта ие болады.
Ішкі сілтемелері бар динамикалық мәліметтер
Қарапайым (яғни, ішкі сілтемелерсіз) динамикалық мәліметтерден өзге элементтері бір-біріне сілтейтін динамикалық құрылымдар болады. Бұл қалай жүзеге асырылады?
Әрине мұндай құрылымды элемент кем дегенде екі өрісті жазба болуы керек. Мұндай жазбаның бір өрісі ақпаратқа арналған, ал екіншісі – осы құрылымның келесі элементіне сілтемеге арналуы керек. Осы аталған құрылым типтерді сипаттау бөлімінде төмендегідей жариялана алады.
Type
P=^item;
Item=record
Data:integer;
Reference:p
End;
Бұл құрылым графикалық түрде төмендегі 5-суреттегідей көрсетіледі.
13-ДӘРІС. Модульдік бағдарламалау.
Модульдердің құрылымы.
Модульдердің тақырыбы және модульдердің бір-бірімен байланысы.
Модульдің интерфейстік, орындалатын және инициалданатын бөліктері.
Модульдердің компиляциясы.
Модульдар программалардың құрылымдануының концепциясын дамытады. Ішкі программалар программаны құрылымдаудың құралы екені белгілі. Негізгі мақсат – программаның көп операторлардан емес, жеке өзалдына программа бөліктерінен (ішкі программалардан) тұруын көзденеді. Өсындай өзбетінше программа бөліктерін соңынан осы әрекетті орындау үшін программада бір немесе бірнеше рет қолдануға болады. Төменде осындай қырдың бірнеше артықшылықтары көрсетілген:
Программа жеңіл түсініледі, оны ары қарай дамыту оңай болады;
Мұнда программаны жал5ыз адам емес, ұжым болып құруға болады. Программисттер ұжымының әрбір мүшесі белгілі ішкі программалар жиынтығын құрастырады, соңынан олардан үлкен программа жиналады.
Егер программа орындайтын әрекет көп кездесетін болса, бұл ішкі программаны басқа да программаларда бірнеше рет қолдануға болады.
Дегенмен мұны қалай практикалық тұрғыдан жүзеге асыруға болады? Осыған байланысты Turbo Pascal программалау тілінде модуль ұғымы енгізілген.
Модуль – бұл Turbo Pascal-дың жеке өзалдына компиляцияланатын файлы, онда тұрақтыларды, айнымалыларды және типтерді, сол сияқты процедуралар мен функцияларды сипаттау бөлімдері болады. Модуль жасалып, компиляцияланғаннан кейін, оның ресурстарын кез-келген Turbo Pascal программасында тек осы модульдың атауын көрсету арқылы қолдануға болады.
Сонымен, модульдар құрылымдық программалаудың қуатты құралы бола отырып, сол сияқты жиі қолданылатын процедуралар мен функциялардың кітапханаларын жасаудың және сақтаудың қолайлы құралы болып табылады.
Стандартты модульдар
Turbo Pascal-дың құрамына дайын типтер, тұрақтылар, айнымалылар, процедуралар мен функциялар жиынтығы бар стандартты модульдар жиыны (барлығы 8) енеді. Олар: SYSTEM, DOS, CRT, PRINTER, GRAPH, OVERLAY, TURBO3 және GRAPH3. Оларды пайдаланушы программаларында шектеусіз қолдана беруге болады. Turbo Pascal-дың құрамына енетін стандартты модульдерден басқа мамандандырылған модульдерді Интернеттен табуға болады. Дайын модульдердің ресурстарын программада қолдану үшін қажетті модульді программаға қосу керек.
Стандартты модульдерге тоқталайық:
SYSTEM модулі Turbo Pascal-дың кез-келген программасына автоматты түрде қосылады, яғни оның ресурстарын ешқандай әрекетсіз бірден қолдануға болады. Мысалы Read, Readln, Write, Writeln процедуралады SYSTEM модулінен алынады. Көптеген арифметикалық есептеулерге, файлдармен жұмыс істеуге, динамикалық жадыны пайдалануға арналған және т.б. функциялар мен процедуралар сол сияқты SYSTEM модулінде қамтылған.
Басқа модульдардың (SYSTEM модулінен басқа) құралдарын программада қолдану үшін бұл модульдарды программаға қосу қажет. Ол үшін қажетті модульдің атауын USES сөзінен кейін көрсету жеткілікті.
Мысалы:
Uses dos;
Begin
Writeln(DiskFree(3) div 1024, ‘Кбайт бос’);
End.
USES – бұл «қолданылады» мағынасын беретін резервтелген сөз. Мысалдағы программа фрагментінде DOS модулінен белгілі дисктегі борс кеңістік көлемін беретін DiskFree функциясы қолданылған. (функция параметрінің 3-ке тең мәні С: дискісіне сәйкес келеді, ал көлем Кбайтпен көрсетілу үшін функция мәні 1024-ке бөлінген).
Осылайша басқа кез-келген модульдерді (ол стандартты немесе пайдаланушы жасаған болсын) программаға қосуға болады. Және де оларды модульдерге топтап қосуға болады.
Uses dos, crt, graph;
DOS модулі. Мұнда программадан MS DOS құралдарына қатынас жасауға және файлдарды басқаруға мүмкіндік беретін процедуралар мен функциялар жинақталған.
CRT модулі. Бұл модульдің ішкі программалары экранның текстік режимін түстер мен терзелерді, символдардың жарқырау ашықтығын қолданумен басқаруға, сол сияқты пернетақтаның кеңейтілген кодтары мен дыбысты басқаруға мүмкіәндік береді.
PRINTER модулі. Бұл модульде LPT1 жүйелік құрылғысымен байланыстырылған, TEXT типті LST файлдық айнымалысы жарияланады.
Var
Lst:text;
Begin
Assign(lst, ‘LPT1’);
Осыдан кейін программада баспаға шығаруды көрсету қажет болса, lst айнымалысын Write процедурасының бірінші параметрі ретінде көрсету жеткілікті (ол үшін текстік файлды жариялап, бекітіп, ашып, жабудың қажеті жоқ).
Write(lst, ‘LPT1’);
Әрине, LST файлдық айнымалысын программада қолдану үшін осы программаға PRINTER модулін қосуды ұмытпау қажет.
GRAPH модулі. Экранның графикалық режимін басқаруға арналған көптеген ішкі программалардан, сол сияқты тұрақтылар, типтер мен айнымалылыардан тұрады. Модульдің ресурстары экранның кез-келген писеліне қатынас жасап, оның жарықтануын басқаруға мүмкіндік береді.
GRAPH модулін графикалық драйверсіз (біреуін немесе бірнешесін, бұлар - .BGI кеңейтілуі бар файлдар) іске қосу мүмкін емес. Көрсетілген файлдар модуль құрамына енбейді, бірақ Turbo Pascal 7.0 –мен бірге әкелінеді (олар BGI каталогында орналасады). Ал егер программада векторлық қаріптер (шрифттер) қолданылса, драйверлерге қосымша ретінде қаріп файлдары қажет болады (.CHR кеңейтілуі бар файлдар).
OVERLAY модулі. Үлкен программаларды дайындау кезінде оларды жүктеу үшін компьютер жадысының жетіспейтін жағдайлары кездеседі. Turbo Pascal программаны жеке сегменттерге (оверлейлік сегменттер) бөлу арқылы тұғырықтан шығуды ұсынады. Осы кезде әр мезетте жадыға ағымдағы әрекетті орындауға қажетті программа бөлігі жүктеледі. Программаны оверлейлерге бөлу құралдары OVERLAY модулінде қамтылған.
TURBO3 және GRAPH3 модульдері. Бұл модульдер Turbo Pascal 3.0 версиясымен үйлесімділікті қолдау үшін жасалған. Turbo Pascal-дың бұл ескі версиясы қолданылмайтындықтан бұл модульдердің қазіргі кезде маңызы жоқ.
GRAPH, TURBO3 және GRAPH3 модульдарынан басқасы TURBO.TPL кітапханалық файлында орналасады. Ал бұл аталған үш модульге өз атауларына сәйкес және .TPU кеңейтілуі бар жеке файлдар қарастырылған.
Модуль құрылымы
Turbo Pascal-да модуль – жеке компиляцияланатын бірлік болғандықтан кәдімгі программаның құрылымына ұқсас болады.
Модульді дұрыс компиляциялау үшін оның атауы модуль сақталатын дискідегі файлдың атауымен сәйкес келуі керек. Мысалы,
Unit Сomplex;
болса, онда оның мәтіні Сomplex.pas атауымен сақталуы қажет. Модуль атауы оның басқа программалар немесе модульдермен байланысы үшін қажет. Бұл байланыс арнайы сөйлеммен жүзеге асады:
Uses <Модульдер тізімі>;
Мысалы,
Uses CRT, Graph, Complex
Модульдың құрылымы схематикалық түрде төмендегідей бейнеленеді:
Unit <модуль тақырыбы>;
Interface
<Интерфейстік бөлік>
Implementation
<Жүзеге асыру бөлігі>
[Begin
Орнататын бөлік]
End.
Мұнда кездесетін резервтелген сөздер келесі мағынаны береді:
Unit – модуль; осы сөзден кейін модуль тақырыбы жазылады;
Interface – интерфейс; модульдің интерфейстік бөлікті бастайды.
Implementation – жүзеге асыру; жүзеге асыру бөлігін бастайды.
Begin және End сөздері кәдімгі программадағыдай мағынаға ие, дегенмен Begin сөзі модульда орнататын бөліктің басын білдіреді (модульда орнататын бөліктің (сәйкесінше Begin сөзінің де) болуы міндетті емес). Ал End сөзіне келетін болсақ, ол бұл жерде модульдың соңын білдіріп тұр.
Модульдің кез-келген көрсетілген бөліктері бос бола алады.
Интерфейстік бөлік. Бұл бөлікте модульдің басқа программалар мен модульдерге қатынас жасайтын барлық ауқымды объектілері (типтер, тұрақтылар, айнымалылар, блоктар) жариялануы қажет. Процедуралар мен функцияларды жариялау кезінде интерфейстік бөлікте тек олардың тақырыптары ғана көрсетіледі, мысалы Vect модулінің мәтіні көрсетілген 1-суреттегі 2-ші интерфейстік бөлікте үш процедураның тақырыптары сипатталған, олар:
procedure Summa(var f,d,e:vector) – векторлардың қосындысын есептейтін процедураның тақырыбы ;
procedure proizvscal(var f,d:vector; var k:real) – векторлардың скалярлы көбейтіндісін есептейтін процедураның тақырыбы;
procedure proizvvect(var f,d,e:vector) – векторлардың көбейтіндісін есептейтін процедураның тақырыбы;
Егер негізгі программада:
Uses Vect;
жолы жазылатын болса, онда ол программада vector типіне қатынас жасалынып, Summa, proizvscal, proizvvect процедураларын қолдануға болады.
Жүзеге асыру бөлігі. Бұл бөлік интерфейстік бөлікте жарияланған процедуралар мен функциялардың денелерінен тұрады. Мұнда модуль үшін жергілікті болып табылатын объектілер де (қосымша типтер, тұрақтылар, айнымалылар, процедуралар және т.б.) жариялана алады. Ал интерфейстік бөлікте тақырыптары көрсетілген процедуралар мен функциялар сол ретпен сипатталуы қажет. Мысалы 1-суреттегі 3-ші жүзеге асыру бөлігінде алдымен Summa процедурасы, екінші proizvscal процедурасы, соңынан proizvvect процедурасы сипатталған.
Орнататын бөлік. Ол өзін бастайтын Begin сөзімен бірге болмауы мүмкін немесе бос болуы мүмкін. Бұл бөліктекейбір программа фрагменттерінен тұратын орындалатын операторларды орналастырады. Бұл операторлар негізгі программаға басқаруды бермес бұрын орындалады да, әдетте оны жұмысқа дайындау мақсатына қолданылады. Мысалы, орнататын бөлікте қажетті файлдар ашылады, айнымалыларға мәндер беріледі және т.б.
МОДУЛЬДЕР КОМПИЛЯЦИЯСЫ
Егер программаны компиляциялау нәтижесінде .EXE кеңейтілуі бар файл алынса, ал модульді компиляциялау нәтижесінде .TPU кеңейтілуі бар файл алынады. Turbo Pascal-да компиляцияның үш режимі мүмкін: COMPILE, MAKE және BUILD. Олар бір-бірінен тек компиляцияланатын модульдің немесе негізгі программаның Uses сөйлемінде жарияланған басқа модульдермен байланысу тәсілдерімен ғана ерекшеленеді.
COMPILE режимінде компиляциялау кезінде Uses сөйлемінде көрсетілген барлық модульдер алдын-ала компиляцияланып, олардың нәтижесі атауы бірдей болатын .TPU кеңейтілуі бар файлдарда сақталуы қажет.
MAKE режимінде компилятор әрбір жарияланған модуль үшін TPU-файлдардың бар-жоқтығын тексереді. Егер файлдардың біреуі жоқ болса, жүйе бірдей атауы бар PAS-файлдарды (яғни, модульдің мәтіні сақталған бастапқы файлды) іздей бастайды және оны компиляциялауға кіріседі. Бұл режимде жүйе кез-келген қолданылған модульдің мәтінінде болған өзгерістерді бақылап отырады. Егер бастапқы мәтінге қандай-да бір өзгерістер енгізілсе, TPU-файлдың бар-жоқтығына қарамастан негізгі программаны компиляциялаудан бұрын оның компиляциясын қайта жасайды. Егер өзгеріс модульдің интерфейстік бөлігіне енгізілсе, онда осы модульмен қатынаста тұрған басқа модульдер де қайта компиляцияланады.
BUILD режимінде TPU-файлдар есепке алынбайды, ал жүйе жарияланған әрбір модуль үшін сәйкес PAS-файлдарды іздеп, оны компиляциялайды. Бұл режимде компиляциялағаннан кейін модульдардың кез-келгенінде жасалынған өзгерістер есепке алынғанына сенімді болуға болады.
Мысал ретінде 1-суретте көрсетілген Vect модулін төмендегі программада пайдалануды көрсетейік:
program primermodul;
uses vect;
var a,b,c:vector;
begin
writeln('Vvedite koord vect a');
with a do
readln(x,y,z);
writeln('Vvedite koord vect b');
with b do
readln(x,y,z);
summa(a,b,c);
writeln('summa vect a+b=',c.x:2,c.y:2,c.z:2);
proizvscal(a,b,i);
writeln('scal proizv vectorov a i b=',i:2);
proizvvect(a,b,c);
writeln('vect proizv vect a i b=',c.x:2,c.y:2,c.z:2);
readln;
end.
14-дәріс. Объектіге арналған бағдарламалау (ОББ).
ОББ-ның негізгі принциптері.
Инкапсуляция. Мұрагерлеу. Полиморфизм.
Объектілік типті сипаттау. Виртуальды әдістер.
НБП құрылымдық программалаумен салыстырғанда, әлдеқайда жетілдірілген түрі. Программалау ғылымының дамуының белгілі кезеңінде күрделі есептің шешімін жеңілдету үшін оны қарапайым ішкі есептерге бөлу туралы ұғым қалыптасты. Мәселе программаның көп операторлардан емес, салыстырмалы түрде алғанда өз бетінше бөліктер жиынтығынан тұруында болды. Ішкі программалар программисттерді қарапайым есептердің мазмұнына терең үңілуден құтқарды, яғни ішкі программа жасалынғаннан кейін оның қалай құрылғанын білмей–ақ, оны қолдана беруге болады. Белгілі бір процедураның, функцияның қандай қызмет атқаратынын білу жеткілікті. Соңынан құрылымдық программалау одан әрі дамыды, яғни модульдер концепциясы дүниеге келді. Модуль – Turbo Pascal-дің тұрақтылар, мәліметтер типі, айнымалылар, сол сияқты процедуралар мен функциялар сипатталатын компиляцияланатын файлдары.
НБП – бұл программалаудың ескі әдстемесінің табиғи эволюциясының нәтижесі болып табылады. Ішкі программалар программистке қарапайым есептердің мазмұнына енбей-ақ қолдануға болатыны сияқты объектілер мен де, олардың қалай ұйымдастырылғанын білмей-ақ жұмыс істеуге мүмкіндік берді.
Ескерту! НБП қарапайым есептеулерді орындайтын программалар үшін арналмаған. Мұндай жағдайда НБП тәсілдерін қолдансақ, программа тілдік конструкциялармен артық жүктеледі.
НБП негізінде 3 негізгі принцип жатыр. Олар: инкапсуляция, мұрагерлеу(наследование) және полиморфизм.
Инкапсуляция
Объектіні сипаттау барлық басқа типтер сияқты сипаттау бөлімінде болу қажет.Объекті қамтитын мәліметтер объект өрістері деп аталады. Қарапайым объектілік типтің сипаттамасы жазбалар сипаттамасына өте ұқсас, тек record резервтелген сөзінің орнына object сөзі қолданылады.
Type
Dote = object
a., b:integer;
end;
Бұл 2 өрістен тұратын объектілік тип, ол экранда a,b кординаталары бар нүкте болып табылады.Өріс түрінде берілген мәліметтерден басқа объект осы өрістерге мүмкін әрекеттерді сипаттайтын ішкі программмалардан тұруы мүмкін.Мұндай ішкі прогрммалар әдістер деп аталады.Әдіс объект өрістеріне қатынас жаай отырып, оған параметр ретінде берілуді қажет етпейді.Өзінде тек қана өрістерді ғана емес, сонымен қатар осы өрістерге мүмкін әрекеттердің сипатталуын қамтитын объектінің қасиетін инкапсуляция деп атайды.Мұнда объектінің сипатталуында тек ішкі программаның тақырыптары болады, аләрбір ішкі программаның денесі жеке көрсетіледі.Алдыңғы мысалдағы Dote типін қажетті әдістермен толықтырайық.
Type
Dote = object
a., b:integer;
procedure Init(x,y:integer);
procedure Show;
procedure Hide;
procedure Move(Da,Db:integer);
end;
{- - - - - - - - - - - - -}
Procedure Dot.Init;
Begin
a:=x; b:=y;
end;
{- - - - - - - - - - - - -}
Procedure Dot.Show;
Begin
PutPixel (a,b,white);
end;
{- - - - - - - - - - - - -}
Procedure Dot.Hide;
Begin
PutPixel (a,b,black);
end;
{- - - - - - - - - - - - -}
Procedure Dot.Move;
Begin
Hide;
a:=a+Da; b:=b+Db;
Show;
End.
Бұл мысалда объект 4 өрістен тұрады. Init әдісі объектіні инициализациялайды,яғни нүктеге бастапқы мән береді. Show және Hide әдістері экрандағы нүктені «жандырады» және «сөндіреді». Move әдісі экандағы нүктенің орнын ауыстырады.Объектілік тип жарияланғаннан кейін осы типтік айнымалылардыжасауға болады немесе НБП терминалогиясы бойынша объект экземплярын жасаймыз.Олар айнымалылар жасау бөлімінде жариияланатын статистикалық айнымалылар New стандартты процедура арқылы жасалған динамикалық айнымалылар болуы мүмкін.
Var Dot1: Dot;
Мұнда Dot типіне жататын Dot1 айнымалысы жарияланған.Объект экземпляры жасалынғаннан кейін оның өрістерінен әдістерге қатынас жасай аламыз.Объект өрісіне қандай да бір стандартты ішкі программаны қолдану үшін оның құрылымдық атауын қолдану жеткілікті – объект идентификаторы мен нүкте арқылы өріс идентификаторын көрсету.
НБП- да объект өрістерімен жұмыс істеу кезінде тек оның әдістері қолданылады.
Dot1:Init(100,100);
Dot1:Show: Dot1.Move(50,50);
Жазбаларға қолданылатын сияқты, объектілерге де with операторын қолдануға болады.
With Dot1 do begin
Init (100,100);
Show;
Move (50,50);
End.
Жоғарыда көрсетілген операторлар тізбегі бірдей.Төменде жоғарыда қарастырылған мысалдардың толық программасы көрсетілген.Бұл программа экранда нүктені бейнелейді және де бейнеленген нүктені бағдарша пернелердің көмегімен 4 бағытта жылжытуға болады.
Program object;
Uses crt; graph;
Type
Dot=object;
a,b:integer;
procedure Init(x,y:integer);
procedure Show;
procedure Hide;
procedure Move(Da,Db:integer);
{-------------------------------------}
Procedure Dot.Init;
Begin
a:=x; b:=y;
end;
{-------------------------------------}
Procedure Dot.Show;
Begin
PutPixel (a,b,white);
End;
{--------------------------------------}
Procedure Dot.Hide;
Begin
PutPixel(a,b,0);
End;
{--------------------------------------}
Procedure Dot.Move;
Begin
Hide;
a:=a+Da; b:=b+Db;
Show;
End;
Var
i,j,k,Err:integer;
a:char;
Dot1:Dot;
{-------------------------------------}
Begin
i:=detect;
InitGraph(I,j,’ ‘);
Err:=GraphResult;
If Err<>gr OK then
Writeln(Graph Error Msg(Err))
Else begin
Dot1.Init(GetMax x div 2, GetMax y div 2);
Dot1.Show;
While KeyPressed do a:=ReadKey;
Repeat
Begin
a:=ReadKey;
case ord(a) of
72:Dot1; Move(0,-5)
80:Dot1; Move(0,5)
77:Dot1; Move(5,0)
75:Dot1; Move(5,0)
End;
End;
Until a=chr(27)
End;
End.
Программада Dot объектісі жарияланды.Оның 2 өрісі, 4 әдісі бар.Ары қарай Dot1 объект экземпляры басқа айнымалылар сияқты жарияланды.Программа денесі графикалық режимгеөтуді жүзеге асыратын оператордан басталады.Содан кейін Repeat операторы белгілі пернені басуды анықтайды.Case операторы 4 нұсқаудан тұрады, олар 4 бағдарша пернелеріне сәйкес келеді.Нұсқалардың әрбіреуі нақты параметрлері бар Move әдісін шақырады, бұл әдіс нүктені қажетті бағытта 5 пиксельге жылжытады. Repeat операторы арқылы ұйымдастырылған циклдың тоқтау шарты 27 Scan кодын беретін пернесінің басылуы болып табылады.
Мұрагерлеу
Айталық, нүкте объектісінен басқа шеңбер объектісі қатысатын программа құрайық.Әрине бұл жаңа типтің сипатталуын Dot типі сияқты басынан бастауға болады.Дегенмен, бұл жаңа шеңбер – типтің Dot типімен ортақ өрістері және әдістері бар.Яғни, шеңбер не нүкте сияқты оның центрін анықтайтын a,b координатасымен сипатталады.Дегенмен,құрылатын объектіге шеңбердің радиусын беретін өріс қосу керек.Ал әдістерге келетін болсақ, жаңа Ring типіне Move әдісі қолданылады, нүктенің орнын ауыстыруы мен экранда шеңбердің ауысуы бірдей жүзеге асады.Ал Init,Show және Hide әдістерін жаңадан жасауға тура келеді.Сонымен, жаңа Ring типі Dot типінің кейбір әдістерін қайталайды.Ендеше бар типтің негізінде оған жаңа өрістер мен әдістерді қоса отырып, жаңа тип жасауға бола ма?Бұл мұрагерлеу деп аталатын объектілік типтердің қасиеттерінің арқасында жүзеге асады.Мәселе мұрагерлеу туралы болғандықтан генеологиялық терминологияға сәйкес жаңа объектіні жасауға негіз болатын бар типті ата-бабасы немесе ата-аналық тип деп атайды.Ал құрылатын объектіні ұрпағы деп атайды.Ұрпақ автоматты түрде өхінің ата-бабасының барлық өрістері мен әдістерін мұраға алады.Мұрагерлеу қасиеті НБП-да қолданылады.Оның арқасында бар объектінің негізінде көптеген жаңа объектілер құруға болады.Осы объектілерге негіздей отырып,боъектілерді көптеп кұра беруге болады және де әрбір объектінің көп ұрпағы болуы мүмкін, бірақ оның ата-бабасы біреу ғана болады.Ал енді Dot және Ring типтеріне оралайық.Ұрпақ типінң сипаттауында ата-аналық типтің атауы көрсетілуі керек.
Type
Ring=object(Dot);
Rad=integer;
End;
Ring типінің сипатталуында шеңбердің радиусын анықтайтын Rad өрісі бар.Бұл өріс dot типінде болмаған және де Ring типі өзінің ата-бабасының өрістерін мұраға алады(нүкте координаталары a,b). Егер Ring типінің сипаттамасын сәйкес әдістермен толықтырсақ,төмендегідей болады:
Ring=object(Dot);
Rad:integer;
Procedure Init(x,y,r:integer );
Procedure Show;
Procedure Hide;
End;
{------------------------}
Procedure RingInit;
Begin
a:=x; b:=y; Rad:=r;
end;
{------------------------}
Procedure RingShow;
Begin
SetColor (white);
Circle (a,b,Rad);
End;
{------------------------}
Procedure RingHide;
Begin
SetColor (black);
Circle(a,b,Rad);
End;
Осы жерден ұрпақ объектісінің әдістері ата-ана объектісінің бірдей атаулы әдістермен алмастырылатынын көруге болады.Басқа сөзбен айтқанда, егер Ring.Move әдісіне қатынас жасалса, жүйе алдымен Ring объектісінің сипаттамасында осындай атаудың бар-жоқтығын анықтайды.Егер бар болса, осы жаңа әдіс қолданылады.Егер жоқ болса,ата- бабасынан мұраға алған әдісті қолданылады.
Ескерту! «Тек әдістерді ғана қайта анықтауға болады.Ал ұрпақ объектісіндегі өріс атаулары ата- анасының объектісінлегі өріс атауларымен сәйкес келмеуі тиіс».
Ұрпақ объектісі жарияланғаннан кейін оның өрістерімен жұмыс істеу үшін оның экземплярын жасауға болады.
Var Ring1: Ring.
Виртуалды әдістер мен полиморфизм
Алдыңғы программадан Move әдісіне оралайық.Оның сипаттамасы төмендегідей.
Procedure DotMove;
Begin
Hide;
a:=a+Da; b:=b+Db;
Show;
End.
Осы жерден Move әдісінің Hide және Show әдістеріне қатынас жасайтынын көреміз.Егер Move әдісін осы түрде dot және ring2 объектісі бар программада қолдансақ не болады?
Бұл жағдайда нүкте үшін ешқандай қиындық туындамайды.Себебі,нүкте dot объектісінің «туған» объектісі болғандықтан, нүкте еш қиындықсыз өшіп, координатасын ауыстырып,қайта жаңарады.Ал шеңберге келетін болсақ, Ring.Move объектілік жүйе,алдымен Ring объектілік типінің сипаттамасынан осындай әдісті іздейді,таба алмағаннан кейін іздеуді ата-баба объектісінде жалғастырады.Нәтижесінде DotMove әдісіне қатынас жасалады.Осыдан кейін Move әдісінен Ring.Hide және Ring.Show әдістері шақырылу керек,бірақ бұл орындалмайды: Ring1 объект экземпляры мұраға алынған DotMove әдісіне RingHide және RingShow дәсітерінің орнына Dot боъектісінің дәсітерін шақырады.Мұның себебі DotHide, DotShow қатаң байланысқан,себебі олар Dot объектілік типінің бірдей контексінде компиляцияланған.Басқа сөзбен айтқанда, бұл әдістер арасындағы байланыс статистикалық сипатқа ие.Бұл жағдайда щеңбер емес, нүкте орын ауыстырады. Hide және Show әдістері қай объект экземплярының Move әдісіне қатынас жасауына байланысты шақырылу үшін не істеу керек?Бұл жерде статикалық байланысудан ерекшеленетін динамикалық байланысу деп аталатын механизм көмеккке келеді.Бұл механизм виртуалды әдістердің көмегімен жүзеге асады.Объектілік типтердің сипаттамасында виртуалды әдістердің тақырыбы VIRTUAL резервтелген сөзімен толықтырылады.Егер объектілік типтің ұрпақтарында қайта анықталған әдістер бар болса, олар да виртуалды ретінде жариялануы қажет және де ата-баба объектісінің әдістері сияқты формальді параметр жиынтығына ие болуы қажет.
Виртуалды әдістері бар Dot және Ring объектілік типтердің сипаттамасы төмендегідей:
Dote = object
a, b:integer;
Constructor Init(x,y:integer);
procedure Show:virtual;
procedure Hide: virtual;
procedure Move(Da,Db:integer);
end;
{------------------------------------}
Ring=object(Dot);
Rad:integer;
Constructor Init(x,y,r:integer );
Procedure Show: virtual;
Procedure Hide: virtual;
End;
Мұндағы конструктор процедурасының ерекше түрін бейнелейтін резервтелген сөз.Енді Move әдісіндегі Ring1 боъект экземплярын шақыруға, ал одан Hide және Show әдістерін шақыруға оралайық.Мұнда жүйе алдымен DotMove әдісіне қатынас жасайды, мұндай атаулы әдіс алдымен Ring объектісінің ізделінеді де, таба алмағаннан кейін сәйкес ата-баба объектісінің әдісіне қатынас жасайды.Осыдан кейін шеңбердің орнын ауыстыру үшін алдымен оны көрінбейтіндей ету қажет(RingHide әдісін шақыру).Содан кейін оның центрінің координатасын өзгертіп шеңберді экрандағы жаңа орында бейнелеу қажет.(RingShow әдісін шақыру).ТР программасын орындау кезінде DotMove әдісіне шақырылатын объект үшін анықталған әдіске қатынас жасау қамтамасыз етіледі.Бұл жерде RingShow және RingHide әдістеріне қатынас жасалады.Қорытындысында сәйкес пернелердің көмегімен жылжытуға болатын экрандағы нүкте мен шеңберді бейнелейтін программаның толық мәтінін көрсетейік:
Program ObjDoture;
Uses crt; graph;
Type
Dot=Object;
a,b:integer;
conctructor Init(x,y=integer);
procedure Show:virtual;
procedure Hide:virtual;
procedure Move(Da,Db:integer);
end;
{----------------------------------}
Ring=object(Dot);
Rad:integer;
conctructor Init(x,y=integer);
procedure Show:virtual;
procedure Hide:virtual;
end;
{----------------------------------}
Constructor DotInit;
Begin
a:=x; b:=y;
end;
{----------------------------------}
Procedure DotShow;
Begin
PutPixel(a,b:White);
End;
{---------------------------------}
Procedure DotMove;
Begin
Hide;
a:=a+Da; b:=b+Db;
Show;
End;
{----------------------------------}
Constructor RingInit;
Begin
a:=x; b:=y;
Rad:=r;
End;
{----------------------------------}
Procedure RingShow;
Begin
SetColor(white);
Circle(a,b,Rad);
End;
{----------------------------------}
Procedure RingHide;
Begin
SetColor(black);
Circle(a,b,Rad);
End;
{----------------------------------}
Var i,j,k,Err:integer;
a:char; Dot1:Dot; Ring1:Ring;
begin
i:=detect;
InitGraph(i,j,’ ‘);
Err:=GraphResult;
If <>grok then
Writeln(GraphErreor Msg (Err))
Else
Begin
Dot1.Init (GetMax x div 2,GetMax y div 2);
Dot.Show;
RingInit (GetMax x div 2, GetMax y div 2,GetMax y div 6);
RingShow
While KeyPressed do a:=ReadKey ;
Repeat
a:=ReadKey;
case ord(a) of
72: Dot1.Move(0,-5);
80: Dot1.Move(0,5);
77: Dot1.Move(5,0);
75: Dot1.Move(-5,0);
73: Ring1.Move(0,-5);
81: Ring1.Move(0,5);
79: Ring1.Move(5,0);
71: Ring1.Move(-5,0);
End;
End;
Until a=chr(27);
End;
End.
Бұл программаның алдыңғы мысалдардан айырмашылығы – мұнда қосымша ұрпақ – жарияланған және Show және Hide әдістері 2 объектіде де виртуалды жарияланған.Ал Init әдісі конструкторға түрлендірілген.Сол сияқты Case жаңа варианттармен толықтырылды.Көрсетілген варианттар шеңбердің экранда 4 бағытта жылжуын қамтамасыз етеді:
(жоғары),PgDown>(төмен), (оңға),
Достарыңызбен бөлісу: |