Хорошо, есть ключевое слово, которое я намеренно убрал из тегов и заголовка. Это "Android", но это потому, что хотя проект и на Android, я не думаю, что мой вопрос имеет к нему какое-то отношение, и я не хочу пугать людей без опыта работы с Android.
Итак, обычная проблема с swig. У меня есть виртуальный метод в классе С++, который я сделал перегружаемым в Java, добавив в класс функцию director
, и он работает. Проблема в том, что метод получает полиморфный аргумент, который также расширяется на стороне java, и во время вызова виртуального метода в Java объект приходит с удаленной всей полиморфной информацией.
Чтобы представить точную ситуацию; Я пишу игровой движок на C++ и хочу успешно использовать его на Java. В игровом движке есть класс GameObject
, который регистрирует CollisionListener
, и когда механизм столкновений обнаруживает событие столкновения, он вызывает метод collidedWith(GameObject & collidee)
для всех зарегистрированных collisionListener
, передавая им объект, с которым они столкнулись.
class CollisionListener {
public:
virtual bool collidedWith(GameObject &){};
~CollisionListener(){} // I know this needs to be virtual but let's forget about that now
};
Я открываю этот класс вместе с классом GameObject
для java, используя следующий файл интерфейса Bridge.i
%module(directors="1") Bridge
%feature("director") CollisionListener;
%include "CollisionListener";
%feature("director") GameObject;
%include "GameObject.h"
Теперь, когда я наследую от CollisionListener
в java и перегружаю collidedWith
, он вызывается с объектом GameObject
на стороне java. Например, если я наследую класс GameObject
со стороны Java и определяю класс Bullet
, когда эта пуля сталкивается с другим объектом с прослушивателем, в вызове метода collidedWith
все, что я получаю, — это голый GameObject
, так что (object instanceof Bullet)
не работает. Неудивительно, я покопался в сгенерированном swig BridgeJNI.java
и нашел это:
public static boolean SwigDirector_CollisionListener_collidedWith(CollisionListener self, long arg0) {
return self.collidedWith(new GameObject(arg0, false));
}
Таким образом, он оборачивает новый объект вокруг указателя перед вызовом перегрузок Java.
Итак, главный вопрос в том, как получить объект Bullet
при столкновении?
Я придумал способ легко добиться этого, но мне нужно изменить автоматически сгенерированные файлы, что является плохой идеей. Поэтому я надеюсь, что какой-нибудь мастер swig поможет мне внести изменения в файлы, сгенерированные swig.
Мой маленький хак состоит в том, чтобы сохранить jobject * self
в каждом объекте GameObject
стороны C++ и назначить адрес реального объекта java во время создания реальной стороны java GameObject
(а не той, которая просто обертывает указатель). Таким образом, я мог бы определить полиморфный метод getSelf
на стороне C++ GameObject
и успешно использовать результат в java. Есть ли способ внедрить необходимый код в сгенерированные файлы swig?
Спасибо
Примечание. Если вы попробовали режиссеры на Android, и они не сработали, это связано с тем, что текущая стабильная версия их не поддерживает. Загрузите Bleeding Edge с веб-сайта swig. Но я пишу это 22.03.2012 и эта заметка скоро станет ненужной. Причина, по которой деструктор не является виртуальным, заключается в том, что версия Bleeding Edge приводит к сбою программы в деструкторе, а создание невиртуального режима, похоже, пока держит его под контролем.
GameObject
в Java и по-прежнему иметь возможность приводить в Java, когда этот производный тип передается в реализацию JavacollidedWith
? Почти уверен, что ваш маленький хак может быть обернут в карту типов, если это так. - person Flexo   schedule 23.03.2012