Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 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.037 c
3-1082542290
stud
2004-04-21 14:11
2004.05.16
реализация запросов


1-1083023251
R
2004-04-27 03:47
2004.05.16
Обращение к ранее используемогу диску SaveDialog


14-1082924268
Piter
2004-04-26 00:17
2004.05.16
Определение времени


3-1082087860
Dark Man
2004-04-16 07:57
2004.05.16
А вот акаунт какой???


1-1082970081
HarryP
2004-04-26 13:01
2004.05.16
Unicode





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский