Динамикалық тәсілдердің индекстері хабарлама идентификаторы ретінде

Динамикалық тәсілдерге индекстерді қолмен беру мүмкіндігі типизациялануға қатысты қатаң шараларды айналып өтуге және мұрагерлік қатысында тұрмаған объекттердің полиморфизмін хабарлама деңгейінде іске асыруға(мысалы, Смолток тілінде жасалынған сияқты) мүмкіндік береді. Мұнда динамикалық тәсілдің индексі объектке жіберілетін хабарламаның идентификаторы ретінде қарастырылады. Әрине, осы класстардағы мұрагерлік қатысында тұрмаған сәйкес тәсілдердің параметрлері бірдей болуы тиіс. Бұдан бөлек, компилятордың бақылау механизмдері өшірілген болады, сондықтан программист тәуекелге бел буады.

Мысал келтірейік:

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

type

TObject = object

constructor init;

destructor done; virtual;

end;

PObject:^TObject;

Айталық, Tobject мұрагерлерінің арасынан периодты түрде көрсеткіш арқылы қол жеткізілетін, логикалық тұрғыдан біртипті элементтер қатары(набор) боп табылатындары кездесіп тұрады. Сонымен бірге, олар мұрагерлік құрылымның әртүрлі бұтақтарында орналасқан; олардың аталықтары біртипті элементтер қатары боп табылмауы да мүмкін.

Барлық осындай объекттерді «мынадай элементтің бар-жоқтығын тексеру» деген хабарламаға полиморфты реакция көрсететіндей етуге болады.

const MSG_ISPRESENT=1025;

type

TControl = object(…TObject)

end;

PControl=^TControl;

TForm = object(…TObject)

function IsControlPresent(Control:PControl): boolean;
virtual MSG_ISPRESENT;

private

FControls: array […] of PControl;

end;

PForm=^TForm;

TCollection = object(…TObject)

  function IsElementPresent(p:pointer): boolean; virtual MSG_ISPRESENT;

private

  FElements: array […] of pointer;

end;

PCollection = ^TCollection;

Көрстілген класстардың кез-келген экземплярына «мына элемент сенде бар ма» деген сұрақ қоюға болады, мысалы былайша:

if PCollection(PMyForm)^.IsElementPresent(pElement) then

Егер PMyObject ішкі құрылымы өзгеше құрылған және коллекциямен туысқандық қатысы жоқ (не состоит с коллекцией в родстве) формаға нұсқап тұрса, онда дәл форманың тәсілі коррект шақырылып, коррект орындалады.

Шындығында, коллекция да, форма да – Tobject-ң туысқандары, сондықтан оларда VMT көрсеткіші бір жерде орналасады. Ізделінді тәсілдің индексі – бұл да бірдей, шақыру шаблоны – бұл да бірдей(бір ғана көрсеткіш-параметрлі логикалық функция). Сондықтан жоғарыда келтірілген конструкцияда форманың VMT-сы алынады, ол жерден – форманың DMT-ң көрсеткіші алынады, ал ол жерден –көрсетілген контрол (элемент)формада жататындығын тексеретін форма тәсілінің көрсеткіші алынады.

Айта кетейік, IsControlPresent тәсілінің реализациясы кезінде TypeOf функциясы арқылы шынымен де параметр ретінде контрол берілгендігін тексеруге болар еді:

result:=false;

if TypeOf(Control^)<>TypeOf(TControl) then exit;

{иначе поиск в массиве}

Өкінішке орай, Паскалда Дельфидегі is операторына ұқсайтын оператор не функция жоқ және стандартты құралдармен Control қайсыбір Tcontrol ұрпағының көрсеткіші болып табылатындығын тексеруге болмайды.

(и нельзя стандартными средствами проверить, является ли Control указателем на какого-то потомка TControl, а именно так и будет при реальном вызове этого метода. )

Бұл мәселені DMT иерархиясы бойлап қарап шығу арқылы шешіп көруге болады: өйткені объект не класстың DMT-сының адресін оның VMT-нан алуға болады, ал DMT-да аталықтардың DMT-ларының адрестері сақталады. Өкінішке орай бұлай етудің де бір кемшілігі бар: егер класстың өз  DMT-сы жоқ болса, ұрпағы оның өзіне тиесілі ме, әлде мұрагерліктің басқа бұтағындағы аталығынан туындаған екенін тексере алмаймыз. Себебі, мұндай класстың VMT-сында аталықтың DMT-сының адресі бар болады.

  1. Классқа тиістілікті тексеру

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

function TObject.KindOf(TypePtr:pointer):boolean; {виртуальный!}

begin

  KindOf := TypePtr=TypeOf(TObject);

end;

Барлық мұрагерлерде бұл тәсілді мынадай үлгі (шаблон) бойынша қайтаанықтаймыз.

function TChildObject.KindOf(TypePtr:pointer):boolean; {виртуальный!}

begin

KindOf := (TypePtr=TypeOf(TChildObject))

or (inherited KindOf(TypePtr));

end;

Берілген механизмді былай қолдануға болады

var p:PSomeChild;

p := pointer(new(PAnyChild,Init)); {на этапе компиляции действует
контроль типов, а PAnyChild может быть несовместим с типом p}

if p^.KindOf(TypeOf(TChildObject)) then

Соңғы тексеру (шарт) мағынасы мынадай: «егер  p^ экземпляры TchildObject-ң әртүрлілігі боп табылса». Дельфиде осы тексеру басқаша жазылады:

if p is TChildObject then

Динамикалық тәсілдің индексін хабарлама номері ретінде пайдалану жолын қолданбаған мақұл. Тілді дайындаушылардың ойында бұл нәрсе болғанымен Турбо Паскалдің 7-ші версиясында реализация жасалынбаған.

«Baribar.kz-тің» Telegram-каналына жазыламыз!