【发布时间】:2012-03-22 06:33:57
【问题描述】:
好的,有一个关键字我故意远离标签和标题。那是“Android”,但那是因为即使该项目是在 Android 中的,我认为我的问题与它没有任何关系,并且我不想吓到没有 Android 经验的人。
所以,swig 的常见问题。我在 C++ 类中有一个虚拟方法,我通过在类中添加 director 功能使其在 Java 中可重载,并且它可以工作。问题是该方法接收到一个多态参数,该参数也在Java端进行了扩展,并且在Java中的虚拟方法调用期间,该对象带有所有多态信息。
呈现准确的情况;我正在用 C++ 编写一个游戏引擎,我想在 Java 中愉快地使用它。游戏引擎有一个GameObject 类,它注册CollisionListeners,当碰撞引擎检测到碰撞事件时,它调用所有已注册collisionListeners 的collidedWith(GameObject & collidee) 方法,将它们与碰撞的对象一起传递给它们。
class CollisionListener {
public:
virtual bool collidedWith(GameObject &){};
~CollisionListener(){} // I know this needs to be virtual but let's forget about that now
};
我使用以下接口文件Bridge.i 将这个类以及GameObject 类公开给java
%module(directors="1") Bridge
%feature("director") CollisionListener;
%include "CollisionListener";
%feature("director") GameObject;
%include "GameObject.h"
现在,当我从 java 中的 CollisionListener 继承并重载 collidedWith 时,它会被 java 端 GameObject 对象调用。例如,如果我从 java 端 GameObject 类继承并定义一个 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 生成的文件中。
我的小窍门是在每个 C++ 端 GameObject 对象中保留一个 jobject * self,并在构建真正的 java 端 GameObject 期间分配真正的 java 对象的地址(而不是仅仅包装的那个)指针)。这样,我可以在 C++ 端 GameObject 中定义一个多态 getSelf 方法,并在 java 中愉快地使用结果。有没有办法将必要的代码注入到 swig 生成的文件中?
谢谢
注意:如果您在 Android 上尝试过 Director 并没有成功,那是因为当前的稳定版本不支持它。从 swig 网站下载 Bleeding Edge。但我在 2012 年 3 月 22 日写这篇文章,很快就不需要了。析构函数不是虚拟的原因是 Bleeding Edge 版本使程序在析构函数中崩溃,并且使其非虚拟似乎暂时可以控制它。
【问题讨论】:
-
所以你的问题的简短版本是你希望能够(例如)在 Java 中派生
GameObject并且当派生类型被传递给 Java 实现时仍然能够在 Java 中进行转换collidedWith的?如果是这样的话,很确定你的小技巧可以被包装在一个类型映射中。 -
没错!我以为 swig 会有一种注入代码的方法,但我对 swig 还是很陌生。我会检查类型映射。
-
我希望明天写一个答案。
标签: java polymorphism swig