Глюки и наследование от MyInterface

Вопросы программирования на Free Pascal, использования компилятора и утилит.

Модератор: Модераторы

Глюки и наследование от MyInterface

Сообщение Stargazer » 16.10.2006 17:34:20

Здравствуйте!

Вот, решил использовать интерфейсы.
Создал простенький интерфейс
Код: Выделить всё
IAimKeeperInterface = Interface
        procedure SetAimPos(var pos : TVec);            
        function GetAimPos : TVec;
end;

и проунаследовал от него:
Код: Выделить всё
CSB_BotAttack = class(CSemanticBlock, IAimKeeperInterface)
естественно, реализовав методы интерфейса.

Далее, через переменную
Код: Выделить всё
aim : IAimKeeperInterface;
пытаюсь вызвать функцию GetAimPos - и программа падает с Access Violation.

А если объявить переменную
Код: Выделить всё
aim : CSB_BotAttack;
то всё нормально, вызов метода отрабатывается нормально.

Может, есть какие-то хитрости с этими интерфейсами? FPC 2.0.2
Stargazer
новенький
 
Сообщения: 52
Зарегистрирован: 30.05.2005 09:46:32

Сообщение Replicator » 16.10.2006 18:36:34

A razve voobsche vozmozhno vizivat' metodi u interfejsov? Ja dumal, chto interfeisi ne soderzhat realizatsij...
Replicator
постоялец
 
Сообщения: 154
Зарегистрирован: 30.04.2006 17:14:45
Откуда: Outer Heaven

Сообщение Stargazer » 17.10.2006 08:09:04

Насколько я понял, то вызываются методы не интерфейса, а объекта, ссылка на который хранится в переменной aim.
Мне-то как раз это и нужно - подставлять в переменную экземпляр любого класса, реализующий методы данного интерфейса.

Компилятор спокойно отнёсся к такому, а вот в рантайме - падает. Я боюсь, как бы это не глюк FPC.
Stargazer
новенький
 
Сообщения: 52
Зарегистрирован: 30.05.2005 09:46:32

Сообщение Sergei I. Gorelkin » 17.10.2006 11:18:37

В FPC были глюки, связанные с интерфейсами. Рекомендую обновиться до 2.0.4 - один из глюков был исправлен как раз перед этим релизом.
Кроме того, AV можно запросто получить и без глюков компилятора - на интерфейсах автоматом считаются ссылки, поэтому объект, реализующий интерфейс, может быть освобожден в результате какой-нибудь с виду невинной операции, например:

Код: Выделить всё
var Obj: TMyInterfacedObject;

begin
  Obj := TMyInterfacedObject.Create(...);
  (Obj as IMyInterface).DoSomething;
  // здесь объекта Оbj уже нет...
end;
Аватара пользователя
Sergei I. Gorelkin
энтузиаст
 
Сообщения: 1406
Зарегистрирован: 24.07.2005 14:40:41
Откуда: Зеленоград

Сообщение Stargazer » 17.10.2006 13:30:48

В FPC были глюки, связанные с интерфейсами. Рекомендую обновиться до 2.0.4 - один из глюков был исправлен как раз перед этим релизом.


Попробовал, не помогло. Видно, я что-то делаю неправильно - хотя вроде бы ничего не освобождается.

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


Как это?
Stargazer
новенький
 
Сообщения: 52
Зарегистрирован: 30.05.2005 09:46:32

Сообщение ArtemUA » 18.10.2006 14:45:25

Извините, а объект вообще создавался?
Код: Выделить всё
aim : IAimKeeperInterface;
...
aim := CSB_BotAttack.Create(...);
...
aim.GetAimPos;
...
ArtemUA
незнакомец
 
Сообщения: 2
Зарегистрирован: 18.10.2006 14:35:07
Откуда: Львов, Украина

Сообщение Stargazer » 18.10.2006 21:13:03

Конечно, создавался.
Я ж написал, что если переменная типа интерфейс, то падает. А если обычный класс - то всё ОК.
Stargazer
новенький
 
Сообщения: 52
Зарегистрирован: 30.05.2005 09:46:32

Сообщение Mirage » 20.10.2006 08:31:56

Stargazer: Вы верите в телепатию? Нужен весь код. От объявления переменных до финализации.
Mirage
энтузиаст
 
Сообщения: 881
Зарегистрирован: 06.05.2005 20:29:07
Откуда: Russia

Сообщение Stargazer » 20.10.2006 13:27:21

Mirage писал(а):Stargazer: Вы верите в телепатию? Нужен весь код. От объявления переменных до финализации.


Наверное, стоит сперва объяснить, чего же я хочу добиться, используя интерфейсы.

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

Я, кажется, начинаю понимать в чём проблема (кстати, без телепатии тут точно не обошлось!) - у меня все объекты создаются и разрушаются автоматически. Сделав их наследниками TInterfacedObject, я не учёл того, что код разрушения объектов работает по-прежнему. Вполне возможно, что в какой-то момент у меня объект автоматически уничтожается, а потом происходит попытка вызвать деструктор несуществующего объекта.

Видимо, мне нужно заставить объекты жить, вне зависимости от того - есть на них ссылки или нет.
Stargazer
новенький
 
Сообщения: 52
Зарегистрирован: 30.05.2005 09:46:32

Сообщение ArtemUA » 20.10.2006 13:50:14

Можно пример как объекты создаются автоматически? Насколько мне известно, автоматически они только удаляются.
Код: Выделить всё
type
  ITest = interface
    function GetValue;
  end;
  TTest = class(TInterfacedObject, ITest)
    function GetValue;
  end;
...
function SomeFunc;
var
  MyInt: ITest;
begin
  MyInt := TTest.Create; // создаем
  MyInt.GetValue;
end;  // на выходе автоматом уничтожится (или позднее)

такой код у вас не работает? Если у вы не забываете создавать, но у вас AV, то возможно вы где-то смешали использование объектных и интерфейсных ссылок (чего очень не рекомендуется делать), так как можно случайно явно удалить объект, на который будет ссылаться интерфейсная переменная.
Кстати, в Lazarus у меня были проблемы с интерфейсами, если была включена опция "Range Check" настроек компилятора.
ArtemUA
незнакомец
 
Сообщения: 2
Зарегистрирован: 18.10.2006 14:35:07
Откуда: Львов, Украина

Сообщение Stargazer » 20.10.2006 14:45:33

ArtemUA писал(а):Можно пример как объекты создаются автоматически? Насколько мне известно, автоматически они только удаляются.


Я имел в виду фабрику. Естественно, она использует метод Create. А вот автоматическое удаление объектов у меня вызывает кучу вопросов. FPC ведь не использует автоматическую сборку мусора, значит - удаление объекта должно происходить тогда, когда обнуляется последняя ссылка на него, при вызове метода _Release. Или нет?

такой код у вас не работает? Если вы не забываете создавать, но у вас AV, то возможно вы где-то смешали использование объектных и интерфейсных ссылок (чего очень не рекомендуется делать), так как можно случайно явно удалить объект, на который будет ссылаться интерфейсная переменная.


Код-то работает, но вот в самом проекте вылезает AV, скорее всего именно из-за смешивания механизмов TInterfacedObject и моих собственных. Чтобы с этим разобраться, нужно точно знать, в какой момент удаляется объект типа TInterfacedObject, чего я пока не знаю :(.
Stargazer
новенький
 
Сообщения: 52
Зарегистрирован: 30.05.2005 09:46:32

Сообщение Mirage » 20.10.2006 21:11:43

Вроде все четко прописано в документации. Уничтожается когда число ссылок станет нулевым. Ссылки декрементируются методом _Release, который вызывается в случае присвоения переменной значения nil, или выхода из области определения переменной (например из процедуры, где она определена).
Mirage
энтузиаст
 
Сообщения: 881
Зарегистрирован: 06.05.2005 20:29:07
Откуда: Russia

Сообщение Stargazer » 21.10.2006 21:42:18

Mirage писал(а):Вроде все четко прописано в документации. Уничтожается когда число ссылок станет нулевым. Ссылки декрементируются методом _Release, который вызывается в случае присвоения переменной значения nil, или выхода из области определения переменной (например из процедуры, где она определена).


В том-то и дело, что придётся перепахивать весь код, связанный с уничтожением объектов. Ведь раньше я их уничтожал вручную, а теперь выясняется, что они это могут делать сами.
Stargazer
новенький
 
Сообщения: 52
Зарегистрирован: 30.05.2005 09:46:32

Сообщение Sergei I. Gorelkin » 23.10.2006 13:06:04

Stargazer писал(а):В том-то и дело, что придётся перепахивать весь код, связанный с уничтожением объектов. Ведь раньше я их уничтожал вручную, а теперь выясняется, что они это могут делать сами.


Если уже написан код, в котором все удаляется вручную, то можно попробовать использовать {$interfaces corba} в начале модуля. В таком режиме интерфейсы получаются без подсчета ссылок, от TInterfacedObject тоже наследоваться не нужно. Возможно, конечно, что вылезут совсем другие глюки...
Аватара пользователя
Sergei I. Gorelkin
энтузиаст
 
Сообщения: 1406
Зарегистрирован: 24.07.2005 14:40:41
Откуда: Зеленоград

Сообщение Stargazer » 05.11.2006 15:39:27

Спасибо за подсказку, мне как раз такой вариант и был нужен!

Я набросал маленький интерфейс-тест, который успешно отработал.
Попробовал сделать так же в проекте - при попытке вызвать интерфейсный метод программа молча падает.

Код: Выделить всё
aim : IAimInterface;
...
self.aim.GetPos(aimpos); // вот так падает


Но странная штука, если привести тип интерфейсной переменной прямо к классу, то всё нормально:

Код: Выделить всё
CSB_Aim(self.aim).GetPos(aimpos); // вот так не падает


Как можно докопаться до сути происходящего, не подскажете?
Stargazer
новенький
 
Сообщения: 52
Зарегистрирован: 30.05.2005 09:46:32

След.

Вернуться в Free Pascal Compiler

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 10

Рейтинг@Mail.ru