2010-10-28 5 views
4

Есть ли побочные эффекты для изменения предка иерархии классов от TObject до TInterfacedObject, чтобы я мог реализовать интерфейсы дальше по цепочке наследования?Введение интерфейсов в существующую иерархию классов в Delphi

Я программировал в Delphi в течение нескольких лет, но никогда не встречал интерфейсов. Я привык использовать их на других языках. Теперь, когда я снова участвую в проекте Delphi, я бы хотел начать использовать их, но я знаю, что они работают немного иначе, чем на Java или C#.

ответ

4

Если у вас уже есть существующий код с использованием класса, вам, вероятно, придется модифицировать его много, чтобы поддерживать ссылки на интерфейсы вместо экземпляров объектов. Интерфейсы подсчитываются и публикуются автоматически, в результате любая ссылка на экземпляр-исполнитель станет недопустимым указателем.

+0

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

+2

@codeelegance: Да, подсчет интерфейса заменяет ручное управление памятью. Вы можете использовать один или другой, но не оба, на любом заданном объекте. –

+0

@Mason Итак, если у меня нет ссылки на объект и ссылка на интерфейс, указывающая на тот же объект, я должен быть в порядке? –

1

Помимо нескольких дополнительных байтов в вашем экземпляре, нет. Вероятно, это лучший способ сделать это.

3

Это будет работать нормально, если вы наследуете класс ниже в верхней части (внизу?) Вашей иерархии. Этот код гарантирует, что ваши новые классы не освободятся - как и поведение TInterfaceObject по умолчанию - вы, по-видимому, уже освобождаете их самостоятельно и хотите сохранить это. Это фактически то, что TComponent в VCL делает - он поддерживает интерфейсы, но не подсчитывается ссылкой.

type 


    TYourAncestor = class(TInterfacedObject) 
    function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall; 
    function _AddRef: Integer; stdcall; 
    function _Release: Integer; stdcall; 

    end; 



implementation 



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


function TYourAncestor._AddRef: Integer; 
begin 
    Result := -1 // -1 indicates no reference counting is taking place 
end; 

function TYourAncestor._Release: Integer; 
begin 
    Result := -1 // -1 indicates no reference counting is taking place 
end; 
+0

Предположим, я не реализовал эти три функции и попытался вручную освободить объект из ссылки на интерфейс. Какой результат? –

+0

@codeelegance: результатом будет ошибка компилятора, невозможно освободить объект из ссылки на интерфейс. – mjn

+0

Вам не нужно наследовать от TInterfacedObject здесь, TObject, реализующий IUnknown, будет в порядке. – tomazy