2008-10-05 5 views
4

У меня небольшая проблема с интерфейсами. Здесь он находится в Псевдокод:Интерфейс «рекурсия» и подсчет ссылок

type 
    Interface1 = interface 
    end; 

    Interface2 = interface 
    end; 

    TParentClass = class(TInterfacedObject, Interface1) 
    private 
    fChild : Interface2; 
    public 
    procedure AddChild(aChild : Interface2); 
    end; 

    TChildClass = class(TInterfacedObject, Interface2) 
    private 
    fParent : Interface2; 
    public 
    constructor Create(aPArent : Interface1); 
    end; 

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

+0

См. Http://stackoverflow.com/questions/487311/how-to-implement-reference-counted-objects-in-delphi#487387 для получения полного ответа на эту проблему круговых ссылок с интерфейсами Delphi. – 2012-02-01 17:28:15

+0

Используйте настоящий GC вместо подсчета ссылок. – 2008-11-24 18:40:25

ответ

10

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

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

TChildClass = class(TInterfacedObject, Interface2) 
private 
    fParent : Pointer; 
    function GetParent: Interface1; 
public 
    constructor Create(aPArent : Interface1); 
    property Parent: Interface1 read GetParent; 
end; 

function TChildClass.GetParent: Interface1; 
begin 
    Result := Interface1(fParent); 
end; 

constructor TChildClass.Create(AParent: Interface1); 
begin 
    fParent := Pointer(AParent); 
end; 

Это безопасно, если корень дерева экземпляров гарантированно где-то где-то поддерживаться, т. е. вы не полагаетесь только на то, чтобы ссылаться на ветвь дерева и все еще иметь возможность ориентироваться во всем этом.

1

Вы должны сделать метод, который явно отключает правильные ссылки. В этом случае невозможно автоматическое использование автоматического подсчета ссылок.

+0

Явный метод не требуется; это зависит от требуемой семантики ссылок. – 2008-10-05 10:23:40

3

Ну, ссылка, конечно, делает Работа в этой ситуации - это просто не решает проблему.

Это самая большая проблема с подсчетом ссылок - если у вас есть круговая ссылка, вы должны явно «разбить» ее (например, установить ссылку на интерфейс «nil»). Вот почему подсчет ссылок на самом деле не является заменой сбора мусора - сборщики мусора знают, что циклы могут существовать и могут выпускать такие циклические структуры, когда на них не ссылаются «снаружи».

0

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