Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Основная";
Текущий архив: 2004.05.16;
Скачать: [xml.tar.bz2];

Вниз

Проблема с 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;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.49 MB
Время: 0.058 c
4-1080636512
Jul
2004-03-30 12:48
2004.05.16
Хороший help file или справочник по Win Api


6-1080020097
NAlexey
2004-03-23 08:34
2004.05.16
Подтверждение о доставке сообщения.


14-1082953057
AGAMEMNUM
2004-04-26 08:17
2004.05.16
photoshop


7-1081068563
_dEMOn
2004-04-04 12:49
2004.05.16
LPT Порт


1-1083671069
ЁПРСТ
2004-05-04 15:44
2004.05.16
Как убить компонент при выходе из него





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
Английский Французский Немецкий Итальянский Португальский Русский Испанский