Форум » [x]Harbour » как реализована объектная модель ? » Ответить

как реализована объектная модель ?

MIKHAIL: В конструкции for each var in arr var - содержит значение элемента массива и в то же самое время можно получить дополнительные свойства как объекта var:__enum* Как это реализовано ?

Ответов - 21, стр: 1 2 All

Pasha: для этого введен отдельный тип данных: enum. На prg уровне для var нет различия между регулярным типом и enum. Но на уровне C для хранения var а HB_ITEM используется отдельная структура: enum, которая содержит ссылку на элемент массива, и дает доступ к свойствам типа __enumIndex, __enumStart и пр.

MIKHAIL: Pasha пишет: для хранения var а HB_ITEM используется отдельная структура: enum, которая содержит ссылку на элемент массива, и дает доступ к свойствам типа __enumIndex, __enumStart и пр. А можно это как то реализовать в Харбор ? Удобно например из функции вернуть значение,у которого могут быть дополнительные свойства/значения

Pasha: Можно использовать хэш. Это похоже на массив с именованными элементами. Примерно так: FUNC <fn> LOCAL hVal := {=>} hVal[ "Value" ] := <value> hVal[ "Name" ] := <..> ... RETURN hVal отдельно значения у хеш нет, надо использовать его элемент.


Петр: MIKHAIL пишет: В конструкции for each var in arr В папке tests есть пример foreach2.prg Реализация конструкции for each для класса. Может это то, что ищете.

MIKHAIL: Pasha пишет: для этого введен отдельный тип данных: enum А можно сделать на С функцию, которой передавать вид структуры и значения и получать обратно переменную с сылкой на эту структуру и ее элементы ?

Pasha: Можно просто сделать класс средствами ООП с нужной структурой. Но ординарного значения объект этого класса иметь не будет HB_IT_ENUM - это отдельный тип специально для цикла for each, повторить это не получится Там даже переменная этого типа используется и передается другим функциям через процедуру unref, где вместо типа enum подставляется ординарный тип

MIKHAIL: Pasha пишет: повторить это не получится Жаль, мне кажется такой подход имеет хороший потенциал... Много написано в старом стиле clipper, который ограничивает функционал и что бы все переделать нужно потратить много времени, разобраться и переписать на объектную модель. А была бы такая возможность реализовать, можно в функцию которая возвращает значение добавлять нужные свойства, без глобального изменения кода...

SergKis: MIKHAIL Посмотрите в hmg h_objects.prg CLASS TKeyData с методами это объект контейнер в котором можете создавать свою структуру переменных, например Local o := oKeyData() o:cVar1 := "...." o:nVar1 := 12345 o:Set(1, "test1") o:Set(2, "test2") ... ? o:nVar1, o:cVar1, o:Get(1), oGet(2), , o:Get(3, "Default3") ? "All elements as {{key, value}, ...} =", o:GetAll(.F.) AEval(o:GetAll(.F.), {{|a,n| _logfile(n, a[1], a[2]) }) ? ? "All elements as {value, ...} =", o:GetAll(.T.) AEval(o:GetAll(.T.), {{|x,n| _logfile(n, x) }) ? Если переменной объекта нет, возвращает Nil или что стоит во 2м параметре o:Get(xKey, xDef) Можно сделать ф-ии для работы с public переменными[pre2] *----------------------------------------------------------------------------* FUNCTION oPubGet( cVar, cVarName, xDef ) *----------------------------------------------------------------------------* Default cVarName := "m_Container" RETURN __mvGet( cVarName ):Get( upper(cVar), xDef ) *----------------------------------------------------------------------------* FUNCTION oPubSet( cVar, xVal, cVarName ) *----------------------------------------------------------------------------* Default cVarName := "m_Container" RETURN __mvGet( cVarName ):Set( upper(cVar), xVal ) [/pre2] делать PUBLIC m_Container := oKeyData()

MIKHAIL: SergKis Это обычные объекты, то о чем и писал Pasha, сам объект не будет иметь ординарного значения. Реализаций много, но это связано с глобальной перепиской кода... Меня заинтересовал именно тот момент, что в конструкции for each var, var - имеет собственное значение и можно получить некий набор свойств...но увы

SergKis: MIKHAIL пишет что в конструкции for each var, var - имеет собственное значение и можно получить некий набор свойств Не так однозначно и не ясно зачем, т.к. for each var, var1, var2, var3 in aVar, aVar2, cVar3

Pasha: Для объектов класса можно переопределить арифметические/логические операции. Можно переопределить даже присваивание, т.е. assign Можно динамически добавлять свойства и методы. Но значение переменной объекта переопределить нельзя Если o - объект, то выражение <var> := o будет возвращать сам объект, а не некое значение

SergKis: MIKHAIL пишет сам объект не будет иметь ординарного значения. Реализаций много, но это связано с глобальной перепиской кода... CLASS TKeyData это обвязка Hash контейнера, потому может исп. как разные структуры данных с доступом к hash данным через именованный ключ, как к переменной объекта. При этом можете наследовать TKeyData и расширять возможности свойств полученного объекта, если надо, но можно обходится и ф-ями, передавая ссылку на объект-контейнер. Например работа с записью o1 := (cAls1)->( oRecGet() ) o := (cAls)->( oRecGet() ) o:Field1 := "..." o:Field2 := 12345 o:Field3 += nSum o1:Field3 := o:Field3 + o:Field4 ... (cAls)->( oRecPut( o ) ) (cAls1)->( oRecPut( o1 ) ) ф-ии [pre2] *----------------------------------------------------------------------------* FUNCTION oRecGet( aField, oRec ) *----------------------------------------------------------------------------* LOCAL cFld, nPos Default oRec := oKeyData() IF ISCHAR(aField) IF left(aField, 1) == "{" .and. right(aField, 1) == "}" aField := &aField ELSE aField := hb_ATokens(aField, ",") ENDIF ENDIF IF ISARRAY(aField) FOR EACH cFld IN aField IF Empty( cFld ) ; LOOP ELSEIF ISARRAY(cFld) ; cFld := cFld[1] // массив как структура ENDIF IF ( nPos := FieldPos(cFld) ) > 0 oRec:Set( trim(FieldName(nPos)), FieldGet(nPos) ) ENDIF NEXT ELSE AEval( Array( FCount() ), {|v,n| v:=n, oRec:Set( trim(FieldName(n)), FieldGet(n) ) } ) ENDIF RETURN oRec *----------------------------------------------------------------------------* FUNCTION oRecPut( oRec, aField ) *----------------------------------------------------------------------------* LOCAL aFld, cFld, nPos, xVal, nCnt := 0 IF ISCHAR( aField ) IF left(aField, 1) == "{" .and. right(aField, 1) == "}" aField := &aField ELSE aField := hb_ATokens(aField, ",") ENDIF ENDIF IF ISARRAY( aField ) FOR EACH cFld IN aField IF Empty( cFld ) ; LOOP ELSEIF ISARRAY(cFld) ; cFld := cFld[1] // массив как структура ENDIF cFld := upper(trim( cFld )) xVal := oRec:Get( cFld ) IF xVal == NIL ; LOOP ENDIF IF ( nPos := FieldPos(cFld) ) > 0 IF FieldType( nPos ) $ "+^="; LOOP // защита записи ENDIF FieldPut( nPos, xVal ) nCnt++ ENDIF NEXT ELSE FOR EACH aFld IN oRec:GetAll(.F.) cFld := aFld[1] IF aFld[2] == NIL ; LOOP ENDIF IF ( nPos := FieldPos(cFld) ) > 0 IF FieldType( nPos ) $ "+^="; LOOP // защита записи ENDIF FieldPut( nPos, aFld[2] ) nCnt++ ENDIF NEXT ENDIF RETURN nCnt > 0 [/pre2]

SergKis: PS Если есть relation с документов на справочник, можно делать o := (cAlsSpr)->( oGetRec() ) o := (cAls)->( oGetRec( , o) ) получим в объекте все поля с разных алиасов, причем совпавшие поля по именам будут иметь значения с пос. алиас, т.е. документов

MIKHAIL: SergKis пишет: Не так однозначно и не ясно зачем, т.к. for each var, var1, var2, var3 in aVar, aVar2, cVar3 речь не о for each, а подход который там реализован в части : __enum* SergKis объектная модель хороша, спору нет, просто интересное решение когда переменная имеет и собственное ординарное значение и дает возможность получать ссылки на свойства этой переменой Pasha пишет: <var> := o будет возвращать сам объект, а не некое значение это понятно...

SergKis: MIKHAIL пишет дает возможность получать ссылки на свойства этой переменой Не оч. понятно, что имеете ввиду, если данные из внутренней таблицы hb, описывающей, структуру переменной (public, private,...), то на уровне hb такие C ф-ии должны быть.

MIKHAIL: SergKis Pasha пишет: для этого введен отдельный тип данных: enum. На prg уровне для var нет различия между регулярным типом и enum. Но на уровне C для хранения var а HB_ITEM используется отдельная структура: enum, которая содержит ссылку на элемент массива, и дает доступ к свойствам типа __enumIndex, __enumStart и пр. ... HB_IT_ENUM - это отдельный тип специально для цикла for each, повторить это не получится

SergKis: MIKHAIL пишет речь не о for each или все таки о for each ... или hash подойдет aHash := hb_hEval( aHash, bBlock, [nStart], [nCount] ) Выполняет кодоблок для каждой пары массива aHash, кодоблоку передаются ключ, значение и индекс.

MIKHAIL: SergKis пишет: или все таки о for each ... или hash подойдет Нет, Pasha уже написал что не повторить такую конструкцию в HB Смысл в том что в for each реализована похожая на объектную модель схема, где у переменной var есть собственное значение и есть свойства, доступ к которым через свойства var:__enumindex и другие... В объектной модели, переменная, которой присвоен объект, ссылается на объект и не имеет своего значения, все это выше уже обсуждалось. Понятно что это можно заменить разными решениями, просто мне понравилась именно такая реализация...

Петр: MIKHAIL пишет: В объектной модели, переменная, которой присвоен объект, ссылается на объект и не имеет своего значения Это не относится к скалярным классам. #include "hbclass.ch" PROCEDURE Main() LOCAL aDim, e LOCAL nVar0 := 2, nVarN := 3 ENABLE TYPE CLASS ALL aDim := { {1,2,3},; {||Qout("A")},; "String",; Date(),; {"A"=>1},; .T.,; 100,; hb_StrToTS("2021-03-02 01:12:13.10"),; @Mul(),; Nil} FOR EACH e IN aDim ? e:ClassName(), [ >> ], e:AsString() NEXT ASSOCIATE CLASS MyNumericClass WITH TYPE NUMERIC ? nVar0 ? nVarN ? nVar0 += nVarN ? nVar0 += "100" ? nVar0 *= "100" ? nVarN:AsString(), "*", nVar0:AsString(), "==", Mul(nVar0, nVarN):AsString() RETURN FUNCTION Mul(a, b) RETURN a*b CLASS MyNumericClass FROM __HBNumeric OPERATOR "+" ARG xArg INLINE ( Self := Self + Val(xArg) ) OPERATOR "*" ARG xArg INLINE ( Self := Self * Val(xArg) ) END CLASS

MIKHAIL: Петр пишет: Это не относится к скалярным классам Не вполне понял пример, поясните пож-ста, кое что мне не знакомо: ENABLE TYPE CLASS ALL - ? e:ClassName(), e:AsString() - что за методы, откуда они беруться ? [ >> ] - что за оператор ? ASSOCIATE CLASS MyNumericClass WITH TYPE NUMERIC - что означает начало и концовка выражения ? и как переменные и операции связаны с этим классом ? FROM __HBNumeric - ? где можно получить более подробную информацию о скалярных классах ?

Петр: ### SCALAR CLASSES ### ============================ Both compilers support scalar classes and allows to add OOP functionality to native types like numeric, character, array, hash, codeblock, date, ... It's possible to overload default scalar classes provided by Harbour and xHarbour or use ASSOCIATE CLASS command to bound any class with some native type. It's also possible to overload the behavior of some operators if it's not already defined for given types. Anyhow it's not possible to change operator precedence which is the same for all types and defined at compile time. Команда ENABLE TYPE CLASS ALL разрешает ООП функциональность для ВСЕХ (ALL) скалярных типов, поддерживаемых Hb. Можно было бы написать ENABLE TYPE CLASS NUMERIC но в первой части примера я показал, что все типы (ну еще есть указатель, кроме перечисленных) имеют, как минимум, один метод AsString унаследованный от ScalarObject. Рекомендую изучить исходник src\rtl\tscalar.prg В т.ч. информацию по ссылке /* Class(y) documentation is located at: https://harbour.github.io/ng/classy/menu.html */ ASSOCIATE CLASS MyNumericClass WITH TYPE NUMERIC это означает, что мы ассоциировали класс MyNumericClass (унаследованный от класса Numeric) с числовым типом и Hb при операциях с числовым типом будет использовать свойства (операторы/методы) этого класса. [ >> ] == " >> " - просто строка для вывода QOut MIKHAIL пишет: что означает начало и концовка выражения ? Уточните какого именно.



полная версия страницы