Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Полиморфизм+"множественное наследование" [WinXP]


Vasena ©   (2010-10-29 19:30:00) 

Есть набор классов и интерфейса:
type
 IEncoding = interface
   procedure SetEncoding(NewEncoding: byte);
   function  GetEncoding: byte;
 end;

 TFrameData = class(TInterfacedObject)
 [...]
 end;

 TTextFrameData = class(TFrameData, IEncoding)
 private
   Encoding: byte;
   [...]
 public
   procedure SetEncoding(NewEncoding: byte); inline;
   function  GetEncoding: byte; inline;
   [...]
 end;

Есть массив обектов:
var
 TestArray: array of TFrameData;

В массиве находятся объекты !наследуемых! от TFrameData класса (т.е. объеткы TTextFrameData)
TestArray[i]:=TTextFrameData.Create();
Хочу сделать такую вещь, но как я не пытаюсь типы привести ничего не получается:
var
 Encoding: IEncoding;
begin
 [...]
 Encoding:=TestArray[i]; // ошибка здесь
 if Encoding.GetEncoding > $01 then
   Encoding.SetEncoding($01);
 [...]
end;

Посоветуйте как сделать чтобы задумка работала???
PS Delphi 2010


Vasena   (2010-11-03 23:36:00) [1]

Спасибо reonidпроблема действительно была в ссылках, написав свой TInterfacedObject всё заработало
Ps функции доступа писать оказалось не нужно ибо доступ в программе через интерфейс организован точно также как у вас в функции описано
PPS Всем спасибо за помощь, проблема решена


reonid   (2010-11-02 19:31:00) [2]

>Юрий Зотов ©   (02.11.10 18:31) [10]

>Работать с интерфейсами как с объектами в принципе можно, но НЕ нужно.
>Чтобы не искать приключений.

Да вобщем, иногда бывает нужно. (Я сам грешен :-))) )

Собственно, это бывает нужно, когда реализуешь
библиотеку и в ней хочется минимизировать интерфейс объектов,
не засоряя базовые классы необязательными операциями.

А опциональные операции удобно вынести в подмешиваемые интерфейсы.
И предоставить объектам на выбор,
какой интерфейс из поддерживаемых некоторым обобщенным
алгоритмом реализовать. Или не реализовывать ни одного
и довольствоваться дефолтным поведением.

Конкретно я использовал такой подход в только библиотеке
векторной графики. Возможно, всё это можно было реализовать
и по другому. Но сожалеть о таком подходе я пока повода не имел...


DiamondShark   (2010-11-02 18:54:00) [3]


> Vasena ©   (30.10.10 15:29) [7]
> хм все  замечательно, однако после вызова метода объявленного
> в интерфейсе, у классов очищаются private поля (только String),
>  с чем это может быть связано???


> 1. Не надо работать с наследниками TInterfacedObject, как
> с классами, надо как с интерфейсами, и наче ждет немало
> граблей.

После освобождения всех интерфейсных ссылок экземпляр удаляется (и финализируется).


Юрий Зотов   (2010-11-02 18:31:00) [4]


> reonid ©   (02.11.10 18:10) [9]
> Работать с интерфейсами в таком стиле
> (используя их главным образом как объекты)
> в принципе можно, но для этого нужно  

Лень, я бы сказал немного иначе:

Работать с интерфейсами как с объектами в принципе можно, но НЕ нужно. Чтобы не искать приключений.


reonid   (2010-11-02 18:10:00) [5]

Работать с интерфейсами в таком стиле
(используя их главным образом как объекты)
в принципе можно, но для этого нужно  

во-первых, запретить подсчет ссылок. Например, сделать собственный
базовый класс, подобный TInterfacedObject:

function TRInterfacedObject._AddRef: Integer; stdcall;
begin
 Result := -1;
end;

function TRInterfacedObject._Release: Integer; stdcall;
begin
 Result := -1;
end;

function TRInterfacedObject.QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
const E_NOINTERFACE = HResult($80004002);
begin
 if GetInterface(IID, Obj) then
   Result := 0
 else
   Result := E_NOINTERFACE;
end;


в противном случае можно получить неожиданное разрушение объекта
в процессе работы с ним через интерфейс.

Во-вторых, использовать ссылки на интерфейс только в локальных переменных. (Т.е. никаких списков интерфейсов. Это другой подход).  
Желательно сделать функции-оболочки для доступа к
функциональности интерфейса, наподобие


function GetEncoding(Obj: TObject; var Encoding: Byte): Boolean;
var enc: IEncoding;
begin
 Result := False;
 //Encoding := DefaultValue; //??  
 if Supports(Obj, IEncoding, enc) then
 begin
    Result := True;
    Encoding := enc.GetEncoding;  
 end;
end;


и нигде, кроме таких функций, переменные типа IEncoding не объявлять.
Везде использовать только ссылки на объекты.

Иначе можно получить интерфейсную ссылку на уже уничтоженный объект.


Palladin   (2010-11-01 15:52:00) [6]

космические лучи


Vasena   (2010-10-30 15:29:00) [7]

хм все  замечательно, однако после вызова метода объявленного в интерфейсе, у классов очищаются private поля (только String), с чем это может быть связано???


_Юрий   (2010-10-30 11:17:00) [8]


> Надо нанять программиста


Программисты никогда не проверяют TObject на поддержку интерфейса? Может быть, не нужно ерундой болтать?


Игорь Шевченко   (2010-10-29 23:53:00) [9]


> PS суть проблемы: есть ссылки на базовый тип, но хранятся
> объекты наследники, базовый тип не реализует нужный интерфейс,
>  а вот наследники - да, как правильно вызвать методы интерфейса,
>  через ссылку на базовый класс (наследуемых классов много,
>  в примере - один...)


Надо нанять программиста


Vasena   (2010-10-29 20:28:00) [10]

Юрий, спасибо, всё заработало, за одно и ошибку нашел (оказалось интерфейсу нужно было GUID указать еще...)


_Юрий   (2010-10-29 20:17:00) [11]

if supports(TestArray[i], IEncoding, Encoding) then


Vasena   (2010-10-29 20:12:00) [12]


> секретная очевидно.


> пытаюсь типы привести ничего не получается


> 2. TInterfaceList спасет от всех бед.

я так понял предлагаете заменить массив на спивок, если да, но это не вариант, да и собственно суть ошибки не в этом...

> 1. Не надо работать с наследниками TInterfacedObject, как
> с классами, надо как с интерфейсами, и наче ждет немало
> граблей.

не совсем понял что имеется ввиду...

PS суть проблемы: есть ссылки на базовый тип, но хранятся объекты наследники, базовый тип не реализует нужный интерфейс, а вот наследники - да, как правильно вызвать методы интерфейса, через ссылку на базовый класс (наследуемых классов много, в примере - один...)


Игорь Шевченко   (2010-10-29 20:02:00) [13]


>  // ошибка здесь


секретная очевидно.

1. Не надо работать с наследниками TInterfacedObject, как с классами, надо как с интерфейсами, и наче ждет немало граблей.
2. TInterfaceList спасет от всех бед.


Наверх

Титульная страница Поиск, карта сайта Написать письмо