Текущий архив: 2004.05.16;
Скачать: CL | DM;
ВнизПроблема с Interface ом Найти похожие ветки
← →
Yuri2004 (2004-04-29 10:54) [0]Имееется следующее:
IMy = interface
["{16D03169-0661-4504-B18B-8EB2A8353C9D}"]
function GetValue: String;
end;
TClass1 = class(TEdit, IMy)
function GetValue: String;
end;
TClass2 = class(TComboBox, IMy)
function GetValue: String;
end;
function TClass1.GetValue: String;
begin
Result:="1111";
end;
function TClass2.GetValue: String;
begin
Result:="2222";
end;
Вопрос: Почему выдает ошибку в таком случае?
var
c1, c2: TControl;
begin
c1:=TClass1.Create(Self);
ShowMessage((c1 as IMy).GetValue);
c1.Destroy;
c2:=TClass2.Create(Self);
ShowMessage((c2 as IMy).GetValue);
c2.Destroy;
а в таком не выдает
var
c1, c2: TControl;
begin
c1:=TClass1.Create(Self);
ShowMessage((c1 as IMy).GetValue);
c2:=TClass2.Create(Self);
ShowMessage((c2 as IMy).GetValue);
c1.Destroy;
c2.Destroy;
Отличие только в том, где я удаляю объект.
← →
Гаврила © (2004-04-29 11:04) [1]ФыьА зачем c1 as IMy
можно же у самого c1 запросить.
Вообще дело сколее всего в том, что компилятор добавляет вызов _Release на неявную интерфейсную переменную в тот момент, когда класс уже разрушен.
Могу и ошибаться. насколько я помню, в TComponent реализация AddRef и Release просто возвращает по -1, так как временем жизни объекта управляет Owner. Так что лучше всего зайти в отладчик CPU в Delphi и посмотреть ,что там происходит.
Почему не выдает во втором случае - попробуйте запустить такой код
var SL: TStringList;
SL:=TStringList.Create;
SL.Free;
SL.Free;
SL.Free;
тоже никакой ошибки не будет (скорее всего)
← →
Romkin © (2004-04-29 11:07) [2]Интересно, и какая ошибка? Вообще-то и во втором случае AV может быть :)
Итак, во-первых, объекты уничтожают обычно вызовом Free, а не Destroy - это соглашение. Хотя особой разницы в этом случае нет.
Во-вторых, сказал А скажи Б. Юзаешь интерфейсы - юзай их.
Проблема у тебя именно с подсчетом ссылок, да и предков ты выбрал неудачно :) AddRef & Release - слышал? (c2 as IMy) вызывает AddRef (в первый раз! счетчик = 1), и когда интерфейс не нужен (у тебя - сразу после ShowMessage) вызывается Release. Счетчик становится = 0, и вызывается Destroy :))))
Вот так. Перекрой метод Destroy с ShowMEssage(Name + " are destroyed"); inherited; например. Увидишь.
Вот так ошибок не будет:var
c1, c2: IMy;
begin
c1:=TClass1.Create(Self);
ShowMessage(c1.GetValue);
c2:=TClass2.Create(Self);
ShowMessage(c2.GetValue);
← →
Тимохов © (2004-04-29 11:18) [3]Полностью согласен с Romkin.
Здесь идет смешение интерфейсов и объектов.
Есть еще вариант (не красив, но иногда выручает): в своем классе переопределить realease и addref так, чтобы они ничего не делали. Но тогда надо понимать, что стандарнтный подсчет ссылок для интерфейсов работать не будет. Сам раньше этим пользовался. Теперь все новые разработки строго разделаяю либо на объекты либо на интерфейсы. Но иногода все же данным способ выручает.
← →
Гаврила © (2004-04-29 11:24) [4]>>Romkin © (29.04.04 11:07) [2]
Скорее всего, по вызову Release и обнулению счетчика деструктор не будет вызван
function TComponent._Release: Integer;
begin
if FVCLComObject = nil then
Result := -1 // -1 indicates no reference counting is taking place
else
Result := IVCLComObject(FVCLComObject)._Release;
end;
Хотя, кто такой FVCLComObject, я немного не понял
← →
Гаврила © (2004-04-29 11:25) [5]>>Тимохов © (29.04.04 11:18) [3]
Разумеется, код не корректен, так смешивать нельзя. Но меня, все таки, больше теперь интересует именно причина ошибки
← →
Тимохов © (2004-04-29 11:28) [6]
>
> Разумеется, код не корректен, так смешивать нельзя. Но меня,
> все таки, больше теперь интересует именно причина ошибки
он не "разумеется" не корректен, а некорректен с случае некорректной реализации addref и realease. Некоррекной в данном случае считается корректная реализация, как это сделано в TInterfacedObject. Корректной считается - полное отсуствие реализации как таковой.
← →
Гаврила © (2004-04-29 11:30) [7]>>Тимохов © (29.04.04 11:28) [6]
В данном случае реализация не от TInterfacedObject, а от TComponent
← →
oleg_art (2004-04-29 11:41) [8]To Гаврила:
Ваш пример будет работать всегда:
procedure TObject.Free;
begin
if Self <> nil then
Destroy;
end;
TO Romkin:
var
c1, c2: IMy;
begin
c1:=TClass1.Create(Self);
ShowMessage(c1.GetValue);
c2:=TClass2.Create(Self);
ShowMessage(c2.GetValue);
Ваш пример будет работать потому, что при выходе за область видимости Release вызывается автоматически
← →
Гаврила © (2004-04-29 11:45) [9]
> To Гаврила:
> Ваш пример будет работать всегда:
> procedure TObject.Free;
> begin
> if Self <> nil then
> Destroy;
> end;
Если вы заметили, я не обниливаю ссылку
По сути, вопрос остался такой - в какой именно момент времени происходит выход за область видимости с соответствующим вызовом Release. Сразу после ShowMessage или по выходу из процедуры
← →
Гаврила © (2004-04-29 11:46) [10]теоретически, ошибку мы должны поиметь только в случае Release на последнем end, иначе все должно отработать. Поправтьте ,если не прав
← →
Тимохов © (2004-04-29 11:48) [11]
> Сразу после ShowMessage или по выходу из процедуры
Какой код имеете в виду?
Если исходный код автора вопроса, то сразу после showmessage.
если совет romkin, то при выходе из метода.
← →
Гаврила © (2004-04-29 11:54) [12]>>Тимохов © (29.04.04 11:48) [11]
имею в виду исходный код.
Что получается
c1:=TClass1.Create(Self);
ShowMessage((c1 as IMy).GetValue);
Release - вызов компилятором
if FVCLComObject = nil then
Result := -1 // -1 indicates no reference counting is taking place
else
Result := IVCLComObject(FVCLComObject)._Release;
c1.Destroy;
то есть все должно отработать корректно
← →
Тимохов © (2004-04-29 11:56) [13]
> то есть все должно отработать корректно
вот я тоже не понял почему не работает
потому замолчал о причинах ошибки.
потом посмотрю
← →
Yuri2004 (2004-04-29 18:55) [14]Ошибка (Access violation) возникает в конце процедуры, то есть даже не на последнем Destroy"е а на end.
Если я использую только один класс, то все работает.
var
c1: TControl;
begin
c1:=TClass1.Create(Self);
ShowMessage((c1 as IMy).GetValue);
c1.Destroy;
Я привожу приведение к IMy для того чтобы не переберать все типы классов TClass1, TClass2, ...
Объясните пожалуйста причину ошибки более подробно, если возможно.
Страницы: 1 вся ветка
Текущий архив: 2004.05.16;
Скачать: CL | DM;
Память: 0.48 MB
Время: 0.04 c