Текущий архив: 2007.05.20;
Скачать: CL | DM;
Вниз
И снова хелперы :) Найти похожие ветки
← →
Alkid © (2007-04-12 17:21) [80]
> Я его тоже к этому пытался подвести.
> Но конь будет с тем, что объявлено последним.
> Скорее с хвостом. :)
Да нет, это будет крылато-колесатый конь :)
> Скорее дублирует уже существующую функциональность.
Не дулирует. Это прямое нарушение.
Предположим: есть базовый класс А со стандартизованным описанием и интерфейсов. От этого класса пронаследовались другие классы. Теперь появляется третья сторона, которая получает возможность вмешатьяс в интерфейс и поведение класса А, каскадно изменив тем самым поведением всех остальных классов. Это прямое нарушение принципов инкапсуляции и прекрасная возможность создания себе проблем :-)
Собственно говоря, если возникает необходимость таким экзотическим образом менять способ отрисовки целой иерархии классов, то значит иерархия была спроектирована неправильно, способ отрисовки должен быть выделен в стратегию и т.п.
← →
euru © (2007-04-12 18:05) [81]
> Alkid © (12.04.07 16:33) [78] и т.д.
> Замечательно. Есть у меня класс TAnimal и наследники. Есть
> хелпер TWheeledAnimal и есть хелпер TWingedAnimal. Я создаю
> экземпляр THorse и вызываю у него Draw. У меня какой конь
> нарисуется - с колёсами или с крыльями?
Это для меня не неожиданный поворот событий. Я о нём знаю. Более того, если в [63] внимательно посмотреть последовательность вызовов, то обнаружится следующее:
- при наследовании TWheelHorse.Draw() развернётся в
TAnimal.Draw();
THorse.Draw();
DrawWheels(Self, FWheelParams);
- при использовании хелперов THorse.Draw() с хелпером развернётся в
TAnimal.Draw();
TAnimalHelper.DrawWheels();
THorse.Draw();
Т.е. возникает коллизия в последовательности вызовов. Просто до сих пор шло обсуждение принципиальной возможности реализации хелперов с полями и их отличия от наследования.
А по поводу очерёдности вызова. Так как хелпер встраивается в уже готовую конструкцию, то в языке, естественно, должна быть возможность чётко определять последовательность применения хелперов и их методов.
> А вообще то, что предлагается - это бред с точки зрения
> классического ООП, ибо поведение класса меняется извне этого
> класса, что напрямую противоречит парадигме ООП.
Парадигма ООП - это не истина в последней инстанции. Есть ещё парадигма аспектно-ориентированного программирования (АОП). Она тоже с точки зрения ООП является бредом.
Однако, можно познакомиться с мнением Гради Буча http://www.sdmagazine.com/documents/s=843/sdm0107i/0107i.htm
И вообще почитать про АОП http://www.javable.com/columns/aop/
← →
GrayFace © (2007-04-12 20:30) [82]euru © (11.04.07 15:03) [13]
А если учесть и другие несуразности, возникшие с вводом в язык новых понятий (о них я писал в [41] в http://delphimaster.net/view/15-1175234938/), то у меня возникают вопросы о квалифицированности разработчиков языка либо об их отношению к языку.
Честно говоря, тебе лучше задать вопрос о квалифицированности самому себе.
homm © (11.04.07 15:51) [22]
Люди, вообще, учитесь отличать imho от afaik, а то суете не к месту и путаете вечно :(
Имхо, afaik расшифровывается как AsFarAsIKnow, а imho - InMyHumbleOpinion, по этому, afaik, в этом предложении я написал что-то не так.
euru © (11.04.07 16:24) [28]
В такой реализации не добавляется ничего нового, применение таких хелперов точно такое же, как у наследования, только добавляется масса ненужных проблем.
euru © (11.04.07 17:54) [44]
Tricks они до тех пор, пока не будут поддерживаться компилятором.
Компилятор наш, сущий на небесах, да святится имя твое... Комилятор не всемогущь.
euru © (12.04.07 12:17) [63]
С множественным наследованием:type
TAnimalDrawer = class(TAnimal)
private
FWheelParams: TWheelParams;
private DrawWheels();
public
procedure Draw(); override;
end;
TWheelHorse = class(THorse, TAnimalDrawer)
end;
TWheelDog = class(TDog, TAnimalDrawer)
end;
procedure TAnimalDrawer.Draw();
begin
inherited;
DrawWheels();
end;
euru © (12.04.07 18:05) [81]
Просто до сих пор шло обсуждение принципиальной возможности реализации хелперов с полями и их отличия от наследования.
Да, все говорили о их реализации, а ты говорил исключительно об их применении.
Скажи наконец, что должен делать компилятор, чтобы осуществить твой коварный замысел?
← →
GrayFace © (2007-04-12 20:33) [83]Создание новых машин - это экстенсивный путь развития автомабилестроения. Куда лучше было бы идти по интенсивному пути, добавляя новую функциональность в уже существующие машины.
← →
_Аноним (2007-04-12 22:59) [84]Кстати вопрос сторонникам теории "добавить поддержку полей в хелперы"
а что делать компилеру ,если они (класс и хелпер к нему) вдруг попадут в разные ран-тайм пакеты?
← →
Суслик © (2007-04-13 00:20) [85]
> _Аноним (12.04.07 22:59) [84]
+10
← →
jack128 © (2007-04-13 02:41) [86]_Аноним (12.04.07 22:59) [84]
Это вопрос уже ставился перед сторонниками недели три назад. Ответа не было тогда, не думаю, что он появится сейчас...
← →
Суслик © (2007-04-13 09:15) [87]Появилась у меня идея. Наверное не совсем хорошо, когда какой хелпер применять компилятор решает только на основе скопа - т.е. берется ближайший по области видимости хелпер.
Я считаю, что было бы хдорово, если бы можно было указывать хелпер явно.
например, что-то типа такого
uses
MyClassHelper, MyClassHelper2;
...
var
C: TMyClass apply TMyClassHelper;
C1: TMyClass apply TMyClassHelper2;
С2: TMyClass
В первом случае примняется хелпер TMyClassHelper, во втором TMyClassHelper2, в третьем - снова TMyClassHelper2, как ближайший по скопу.
Как считаете?
← →
oxffff © (2007-04-13 12:07) [88]
> Alkid © (12.04.07 17:21) [80]
>
> > Я его тоже к этому пытался подвести.
> > Но конь будет с тем, что объявлено последним.
> > Скорее с хвостом. :)
>
> Да нет, это будет крылато-колесатый конь :)
>
>
> > Скорее дублирует уже существующую функциональность.
>
> Не дулирует. Это прямое нарушение.
> Предположим: есть базовый класс А со стандартизованным описанием
> и интерфейсов. От этого класса пронаследовались другие классы.
> Теперь появляется третья сторона, которая получает возможность
> вмешатьяс в интерфейс и поведение класса А, каскадно изменив
> тем самым поведением всех остальных классов. Это прямое
> нарушение принципов инкапсуляции и прекрасная возможность
> создания себе проблем :-)
C инкапсуляцией это никак не связано.
Это возможность модификации базового класса.
to euro
Как отличить один класс(без apply helper) и другой класс(с apply helper).
Для каждого из них будет создана разная VMT(СlassType),
если вы допускаете возможность override.
Это будет указывать на разные типы.
← →
oxffff © (2007-04-13 12:07) [89]
> C инкапсуляцией это никак не связано.
> Это возможность модификации базового класса.
Но только VMT и DMT. И то если это предусмотрено.
← →
oxffff © (2007-04-13 12:13) [90]to euro
>Аспектно-ориентированное программирование — новая парадигма >программирования, которая позволяет реализовывать отдельные концепции >в слабосвязанном виде, и, комбинируя такие реализации, сформировать >конечную систему
А чем вас COM не устраивает.
← →
euru © (2007-04-13 17:17) [91]
> GrayFace © (12.04.07 20:30) [82]
> С множественным наследованием:
Множественное наследование не расширило возможности класса, а создало два новых класса с расширенными возможностями. Всё равно придётся искать все места, где создаются объекты THorse и TDog и заменять их на TWheelHorse и TWheelDog.
> GrayFace © (12.04.07 20:33) [83]
> Создание новых машин - это экстенсивный путь развития автомабилестроения.
> Куда лучше было бы идти по интенсивному пути, добавляя
> новую функциональность в уже существующие машины.
Насколько я знаю, именно по такому пути автомобилестроение и развивается. Изобретение нового элемента автомобиля (ABS, АКПП и т.д.) не приводит к созданию нового типа автомобиля. Эти элементы добавляют в уже существующие типы автомобилей.
Если бы автомобилестроение придерживалось классического ООП, да ещё и с единичным наследованием, то на внесение каждого изменения пришлось бы изобретать новое название модели.
← →
oxffff © (2007-04-13 17:29) [92]to euru ©
Пожалуйста ваш ответ на oxffff © (13.04.07 12:07) [88]?
← →
euru © (2007-04-13 18:04) [93]
> _Аноним (12.04.07 22:59) [84]
> а что делать компилеру ,если они (класс и хелпер к нему)
> вдруг попадут в разные ран-тайм пакеты?
А чем не устраивает ответ [28]?
Я набросал небольшой пример имитации. Но, к сожалению, Delphi у меня не установлен. Я постарался, насколько смог, не допустить синтаксических ошибок и промоделировать корректность работы, но 100% гарантии дать не могу.
За основу я взял свой предыдущий пример с лошадью и собакой. Внёс в него некоторые изменения, которые, в принципе, мог бы сделать и компилятор. Для имитации хелперов я использовал интерфейсы.
Модуль Animals.pas содержит реализацию трёх классов: TAnimal, THorse и TDog. Интерфейс IAnimalHelper имитирует хелпер. Процедура RegisterHelper имитирует объявление class helper.unit Animals;
interface
type
//Порядок вызова хелперов
TCallOrder = (
coBefore, // вызов перед вызовом хелпера предка
coInstead, // вызов вместо текущего хелпера
coAfter // вызов после вызова хелпера предка
);
IAnimalHelper = interface
procedure Draw();
end;
TAnimal = class
public
// Процедура регистрации хелпера
// Привязывает хелпер к классу, вызывающему процедуру
class procedure RegisterHelper(aHelper: IAnimalHelper;
aCallOrder: TCallOrder = coAfter);
procedure Draw();
end;
THorse = class(TAnimal)
end;
TDog = class(TAnimal)
end;
implementation
type
TAnimalClass = class of TAnimal;
THelperHandle = class
public
Owner: TAnimalClass;
Helper: IAnimalHelper;
Order: TCallOrder;
Parent: PHelperHandle;
Before: PHelperHandle;
After: PHelperHandle;
constructor Create(aOwner: TAnimalClass; aHelper: IAnimalHelper);
destructor Destroy(); override;
end;
constructor THelperHandle.Create(aOwner: TAnimalClass; aHelper: IAnimalHelper);
begin
Owner := aOwner;
Helper := aHelper;
Order := coInstead;
Parent := nil
Before := nil;
After := nil;
end;
destructor THelperHandle.Destroy();
begin
if Before <> nil then FreeAndNil(Before);
if After <> nil then FreeAndNil(After);
Helper := nil;
inherited;
end;
type
TAnimalHelpers = class
private
FHelpers: TStringList;
public
constructor Create();
destructor Destroy(); override;
procedure AddHelper(aParent: THelperHandle; aClass: TAnimalClass;
aHelper: IAnimalHelper; aCallOrder: TCallOrder);
function GetHelperHandle(aClass: TAnimalClass): THelperHandle;
end;
constructor TAnimalHelpers.Create();
begin
FHelpers := TStringList.Create();
end;
destructor TAnimalHelpers.Destroy();
var
Handle: TObject;
i: Integer;
begin
for i := 0 to FHelpers.Count - 1 do begin
Handle := FHelpers.Objects[i];
if Handle <> nil then Handle.Free();
end;
FHelpers.Free();
inherited;
end;
procedure TAnimalHelpers.AddHelper(aParent: THelperHandle;
aClass: TAnimalClass; aHelper: IAnimalHelper; aCallOrder: TCallOrder);
begin
Handle := THelperHandle.Create(aClass, aHelper);
if (aParent <> nil) and (aParent.Owner = aClass) then begin
case aCallOrder of
coBefore: begin
Handle.Before := aParent.Before;
aParent.Before := Handle;
end;
coInstead: begin
aParent.Helper := aHelper;
Handle.Free();
end;
coAfter: begin
Handle.After := aParent.After;
aParent.After := Handle;
end;
end;
end
else begin
FHelpers.AddObject(aClass.ClassName(), Handle);
Handle.Parent := aParent;
Handle.Order := aCallOrder;
for i := 0 to FHelpers.Count - 1 do begin
Child := THelperHandle(FHelpers.Objects[i]);
if (Child.Parent = aParent) and
Child.Owner.InheritsFrom(aClass) then begin
Child.Parent := Handle;
end;
end;
end;
end;
function TAnimalHelpers.GetHelperHandle(aClass: TAnimalClass): THelperHandle;
var
Current: TAnimalClass;
begin
Result := nil;
Current := aClass;
while True do begin
if FHelpers.Find(Current.ClassName(), Index) then begin
Result := THelperHandle(FHelpers.Objects[Index]);
exit;
end;
if Current = TAnimal then exit;
Current := Current.ClassParent();
end;
end;
var
AnimalHelpers: TAnimalHelpers;
class procedure TAnimal.RegisterHelper(aHelper: IAnimalHelper;
aCallOrder: TCallOrder = coAfter);
var
Handle: THelperHandle;
begin
Handle := AnimalHelpers.GetHelperHandle(ClassType());
AnimalHelpers.AddHelper(Handle, ClassType(), aHelper, aCallOrder);
end;
procedure TAnimal.Draw();
procedure HelperDraw(aHandle: THelperHandle);
begin
if aHandle = nil then exit;
with aHandle do begin
case Order of
coBefore: begin
HelperDraw(Before);
Helper.Draw();
HelperDraw(After);
HelperDraw(Parent);
end;
coInstead: begin
Helper.Draw();
HelperDraw(Before);
HelperDraw(After);
end;
coAfter: begin
HelperDraw(Parent);
HelperDraw(Before);
Helper.Draw();
HelperDraw(After);
end;
end;
end;
end;
var
Handle: PHelperHandle;
begin
Handle := AnimalHelpers.GetHelperHandle(ClassType);
HelperDraw(Handle);
end;
type
TAnimalHelper = class(TInterfacedObject, IAnimalHelper)
private
procedure Draw();
end;
procedure TAnimalHelper.Draw();
begin
writeln("Я животное");
end;
type
THorseHelper = class(TInterfacedObject, IAnimalHelper)
private
procedure Draw();
end;
procedure THorseHelper.Draw();
begin
writeln("Меня зовут Лошадь");
end;
type
TDogHelper = class(TInterfacedObject, IAnimalHelper)
private
procedure Draw();
end;
procedure TDogHelper.Draw();
begin
writeln("Меня зовут Собака");
end;
initialization
AnimalHelpers := TAnimalHelpers.Create();
TAnimal.RegisterHelper(TAnimalHelper.Create());
THorse.RegisterHelper(THorseHelper.Create());
TDog.RegisterHelper(TDogHelper.Create());
finalization
AnimalHelpers.Free();
end.
← →
euru © (2007-04-13 18:05) [94]В программе StrangeAnimals.dpr имитируются два хелпера:
- TWheeledAnimalHelper: его действие повлияет на класс TAnimal и его потомков;
- TWingedHorseHelper: его действие повлияет на класс THorse и его потомков.
При этом добавление хелперов не привело к определению новых специализированных классов, хотя поведение классов после применения хелперов изменилось.
Также можно видеть, что для изменения поведения классов из модуля Animals нет необходимости иметь в наличии исходные тексты этого модуля. Фактически, этот модуль может находится в отдельном пакете, однако это не мешает изменять его поведение (а не добавлять новое, как это делается с помощью class helper) из другого.program StrangeAnimals;
uses
Animals;
type
TWheeledAnimalHelper = class(TInterfacedObject, IAnimalHelper)
private
procedure Draw();
end;
TWingedHorseHelper = class(TInterfacedObject, IAnimalHelper)
private
procedure Draw();
end;
procedure TWheeledAnimalHelper.Draw();
begin
writeln("Вместо ног у меня колёса");
end;
procedure TWingedHorseHelper.Draw();
begin
writeln("А ещё у меня есть крылья");
end;
var
H: THorse;
D: TDog;
begin
H := THorse.Create();
D := TDog.Create();
H.Draw();
D.Draw();
TAnimal.RegisterHelper(TWheeledAnimalHelper.Create());
H.Draw();
D.Draw();
THorse.RegisterHelper(TWingedHorseHelper.Create(), coBefore);
H.Draw();
D.Draw();
H.Free();
D.Free();
end.
← →
euru © (2007-04-13 18:06) [95]
> oxffff © (13.04.07 17:29) [92]
Отвечу.
← →
_Аноним (2007-04-13 18:24) [96]
> euru ©
> а что делать компилеру ,если они (класс и хелпер к нему)
>
> > вдруг попадут в разные ран-тайм пакеты?
> А чем не устраивает ответ [28]?
28:
>>RTTI знает о наличии хелперов у класса
Откуда?
← →
GrayFace © (2007-04-14 19:22) [97]euru © (13.04.07 17:17) [91]
Множественное наследование не расширило возможности класса, а создало два новых класса с расширенными возможностями. Всё равно придётся искать все места, где создаются объекты THorse и TDog и заменять их на TWheelHorse и TWheelDog.
Ну чтоб не заменять можно написать THorse = TWheelHorse, TDog = TWheelDog.
euru © (13.04.07 18:04) [93]
Я набросал небольшой пример имитации.
Небольшой)) Верю, что после правок ошибок (если есть) работать будет, но какой ценой... (действительно, если не экономить на скорости, схема получается проще, чем та, о которой думал я)
← →
euru © (2007-04-16 02:55) [98]
> Суслик © (13.04.07 09:15) [87]
Нормальная идея. Только, может, имеет смысл рассматривать такой код не только как указание, какой из хелперов выбирать, но и как способ назначения хелпера непосредственно экземпляру класса.
> oxffff © (13.04.07 12:07) [88]
> Как отличить один класс(без apply helper) и другой класс(с
> apply helper).
Идея-то как раз и заключается в том, что для разработчика название класса и его тип после применения хелпера не изменялись. А если вдруг понадобится информация о наличии в классе хелпера, то можно, например, задействовать операторis
.
> Для каждого из них будет создана разная VMT(СlassType),если
> вы допускаете возможность override.
Наличие VMT в откомпилированной программе -- это внутреннее представление (способ реализации) полиморфизма классов. Как именно будет реализован этот механизм при наличии хелперов, не должно волновать разработчиков. То, что в данной версии Delphi тип класса и VMT эквивалентны, является просто следствием реализации и не факт, что в последующих версиях это условие будет соблюдаться. Вполне возможно, что будет использоваться какая-нибудь XMT (eXtended Method Table), в составе которой будет информация и о виртуальных методах.
> oxffff © (13.04.07 12:13) [90]
> А чем вас COM не устраивает.
Аспекты и СОМ - это несколько разные вещи.
Это всё равно, что сравнить в языке Java атрибут методаsynchronized
и функцииEnterCriticalSection
,LeaveCriticalSection
.
> GrayFace © (14.04.07 19:22) [97]
> Ну чтоб не заменять можно написать THorse = TWheelHorse,
> TDog = TWheelDog.
Т.е. сначала создать два новых класса, а потом определить ещё два класса, имена которых совпадают с именами нужных нам классов, но их типы являются различными? А чем это удобнее хелперов?
> Верю, что после правок ошибок (если есть) работать будет,
> но какой ценой...
Для проверки работы специально скачал триальную версию Delphi. Обнаружены следующие недочёты в модуле Animals.pas:
1. В разделеimplementation
добавить модулиSysUtils
иClasses
.
2. В методеGetHelperHandle
классаTAnimalHelpers
заменитьTAnimalClass
наTClass
.
3. В конструктореTAnimalHelpers.Create()
добавитьFHelpers.Sorted := True;
.
4. Ветку else в TAnimalHelpers.AddHelper заменить наelse begin
for i:= 0 to FHelpers.Count - 1 do begin
Child := THelperHandle(FHelpers.Objects[i]);
if (Child.Parent = aParent) and
Child.Owner.InheritsFrom(aClass) then begin
Child.Parent := Handle;
exit;
end;
end;
FHelpers.AddObject(aClass.ClassName(), Handle);
Handle.Parent := aParent;
Handle.Order := aCallOrder;
end;
5. В программе объявить{$APPTYPE CONSOLE}
После этого работает.
О цене вопрос некорректен.
Во-первых, я не ставил перед собой цель оптимизации работы.
Во-вторых, большая часть проведённой в программе работы должна будет делаться на этапе компиляции и не на много замедлит производительность.
← →
oxffff © (2007-04-16 12:42) [99]euru © (16.04.07 02:55) [98]
> > oxffff © (13.04.07 12:07) [88]
>
> > Как отличить один класс(без apply helper) и другой класс(с
>
> > apply helper).
> Идея-то как раз и заключается в том, что для разработчика
> название класса и его тип после применения хелпера не изменялись.
> А если вдруг понадобится информация о наличии в классе
> хелпера, то можно, например, задействовать оператор is.
>
>
> > Для каждого из них будет создана разная VMT(СlassType),
> если
> > вы допускаете возможность override.
> Наличие VMT в откомпилированной программе -- это внутреннее
> представление (способ реализации) полиморфизма классов.
> Как именно будет реализован этот механизм при наличии хелперов,
> не должно волновать разработчиков. То, что в данной версии
> Delphi тип класса и VMT эквивалентны, является просто следствием
> реализации и не факт, что в последующих версиях это условие
> будет соблюдаться. Вполне возможно, что будет использоваться
> какая-нибудь XMT (eXtended Method Table), в составе которой
> будет информация и о виртуальных методах.
А совместимость c legacy кодом?
Даже если XMT (eXtended Method Table) будет размещена по отрицательным
смещениям от VMT.
Вызовы legacy кода уже привязаны с entry VMT.
Можно даже и из этой ситуации найти выход. Только для чего?
Все что вы хотите можно сделать и текущими средствами. IMHO.
← →
euru © (2007-04-16 17:31) [100]
> oxffff © (16.04.07 12:42) [99]
> А совместимость c legacy кодом?
Неужели в последних версиях Delphi поддерживается совместимость с пакетами ещё из первых версий Delphi? А на уровне исходных кодов остаётся 100% совместимость.
Кстати, про совместимость. В Delphi for .Net отказались от делегирования интерфейсов, ссылаясь на то, что в .Net такого нет. А как же в этом случае совместимость с legacy кодом?
> Можно даже и из этой ситуации найти выход. Только для чего?
> Все что вы хотите можно сделать и текущими средствами. IMHO.
Странно. Почему же тогда разработчики не воспользовались текущими средствами для объединения TObject и Object, а зачем-то ввели какие-то хелперы.
← →
oxffff © (2007-04-16 18:06) [101]to euru
> А на уровне исходных кодов остаётся 100% совместимость.
Ой не торопитесь.
Legacy код привязан к VMT entry.
Пример
Существует откомпилированный код(legacy), к которому добавляем DLL
расширения (code with HelperEx).
Как legacy код вызовет именно тот "virtual метод из DLL", если он привязан к конкретному смещению в VMT.
Я не говорю, что сделать нельзя.
Каков ваш вариант?
>Кстати, про совместимость. В Delphi for .Net отказались от делегирования >интерфейсов, ссылаясь на то, что в .Net такого нет. А как же в этом >случае совместимость с legacy кодом?
C native кодом? А разве она должна быть?
>Странно. Почему же тогда разработчики не воспользовались текущими >средствами для объединения TObject и Object, а зачем-то ввели какие-то >хелперы.
Для того, чтобы объединить scope и добавить псевдо-методы. Это позволило провести порт VCL на .NET на порядок меньшими трудозатратами.
если с DMT дело об
← →
euru © (2007-04-18 17:47) [102]
> oxffff © (16.04.07 18:06) [101]
> Существует откомпилированный код(legacy), к которому добавляем
> DLL расширения (code with HelperEx).
Наверно, всё-таки заменяем существующую DLL новой версией. Иначе как откомпилированный код узнает о появлении в его распоряжении новой DLL?
> Как legacy код вызовет именно тот "virtual метод из DLL",
> если он привязан к конкретному смещению в VMT.
Насколько я знаю, механизм DLL не умеет передавать информацию о классе в программу, использующую эту DLL. Всё, что может получить внешняя программа, - это указатель на область памяти, выделенную под экземпляр класса. Для корректной интерпретации этой области как экземпляра соответствующего класса программа должна обладать дополнительной информацией. Поэтому возможны два варианта использования классов из DLL:
1. программа не использует экземпляры таких классов в явном виде, а взаимодействует с ними посредством экспортируемых из DLL функций;
2. программа использует экземпляры классов из DLL, но для этого должен существовать модуль с описанием этих классов, известный как программе, так и DLL.
В первом варианте прямое взаимодействие программы с экземплярами классов отсутствует. Поэтому, какие бы ни были изменения в реализации классов DLL (в том числе и использование хелперов), на работе программы они не отразятся.
Во втором варианте совместимость в общем случае не гарантирована. Но отсутствие гарантии никак не связана с использованием хелперов. Несовместимости можно добиться и без них. Достаточно, например, в класс добавить ещё один виртуальный метод, и новая версия DLL с большой долей вероятности будет приводить к ошибкам исполнение программы. Поэтому такая несовместимость в качестве аргументации против хелперов, мне кажется, несколько некорректна (такие же аргументы можно привести и против использования обычных экспортируемых из DLL функций).
Кстати, Borland тоже как-то не очень следит за совместимостью со своими пакетами при появлении очередной версии Delphi. Однако активного сопротивления или хотя бы возмущения со стороны разработчиков мной почему-то не наблюдалось.
Но, как возможные варианты решения совместимости, я могу предложить следующие:
1. для каждого класса, в котором выртуальный метод замещён методом из хелпера, в VMT создаётся копия записи оригинального класса, в которой по соответствующему смещению прописывается ссылка на метод хелпера;
2. в VMT класса указатель на оригинальную функцию замещается указателем на функцию-заглушку, которая определяет, какой именно метод должен быть вызван в том или ином случае.
← →
oxffff © (2007-04-18 18:10) [103]
> Во втором варианте совместимость в общем случае не гарантирована.
> Но отсутствие гарантии никак не связана с использованием
> хелперов. Несовместимости можно добиться и без них. Достаточно,
> например, в класс добавить ещё один виртуальный метод,
> и новая версия DLL с большой долей вероятности будет приводить
> к ошибкам исполнение программы.
Соблюдайте правила абстрактного базового класса и никаких неприятностей.
Дополнительные методы аля getInterface или аля AS
> Но, как возможные варианты решения совместимости, я могу
> предложить следующие:
> 1. для каждого класса, в котором выртуальный метод замещён
> методом из хелпера, в VMT создаётся копия записи оригинального
> класса, в которой по соответствующему смещению прописывается
> ссылка на метод хелпера;
> 2. в VMT класса указатель на оригинальную функцию замещается
> указателем на функцию-заглушку, которая определяет, какой
> именно метод должен быть вызван в том или ином случае.
Механизм вызова усложниться + еще один уровень косвенности + проверка.
Что в итоге? Снижение скорости.
И это при учете того, что helperEx может быть востребован в редких случаях при учете того, что разработчик предусмотрит объявление функций virtual или dynamic.
Вы наверно хотите еще и таблицу интерфейсов заменять\дополнять?
-72 Pointer pointer to interface table (or nil)
← →
euru © (2007-04-22 02:29) [104]
> oxffff © (18.04.07 18:10) [103]
> Соблюдайте правила абстрактного базового класса и никаких
> неприятностей. Дополнительные методы аля getInterface или
> аля AS
Как я могу соблюдать эти правила, если Borland практически в каждой версии Delphi вносила изменения в свои компоненты. Большие сомнения у меня, что программа, написанная на Delphi 2, без проблем бы работала с формами и элементами управления, хранящимися в DLL, написанной на Delphi 7.
> Механизм вызова усложниться + еще один уровень косвенности
> + проверка.Что в итоге? Снижение скорости.
Такие же аргументы про усложнение механизма вызова и и снижение скорости были и во времена появления языков ООП. Однако сейчас на это практически не обращают внимание.
Страницы: 1 2 3 вся ветка
Текущий архив: 2007.05.20;
Скачать: CL | DM;
Память: 0.73 MB
Время: 0.065 c