Ok, es gibt ein Keyword, das ich bewusst von den Tags und dem Titel entfernt habe. Das ist "Android", aber das liegt daran, dass, obwohl das Projekt in Android ist, meine Frage nicht damit zu tun hat und ich keine Menschen ohne Erfahrung in Android erschrecken möchte.
Also, das übliche Problem mit dem Schluck. Ich habe eine virtuelle Methode in einer C ++ - Klasse, die ich in Java überladbar gemacht habe, indem ich der Klasse das Feature director
hinzugefügt habe und es funktioniert. Das Problem ist, dass die Methode ein polymorphes Argument erhält, das auch auf der Java-Seite erweitert wird, und während des Aufrufs der virtuellen Methode in Java wird das Objekt mit allen polymorphen Informationen versehen.
Um die genaue Situation zu präsentieren; Ich schreibe eine Spielengine in C ++, und ich möchte sie gerne in Java verwenden. Die Spielengine hat eine Klasse GameObject
, die CollisionListener
s registriert und wenn die Kollisionsmaschine ein Kollisionsereignis erkennt, ruft sie die Methode collidedWith(GameObject & collidee)
aller registrierten collisionListener
s auf, die sie mit dem kollidierten Objekt übergeben.
Ich gebe diese Klasse zusammen mit der Klasse GameObject
für Java mit der folgenden Schnittstellendatei Bridge.i
Nun, wenn ich von CollisionListener
in Java erwerbe und collidedWith
überbetreibe, wird es mit einem Objekt auf der Java-Seite GameObject
aufgerufen. Zum Beispiel, wenn ich von der Java-Seite GameObject
-Klasse erben und eine Bullet
-Klasse definieren, wenn dieses Aufzählungszeichen mit einem anderen Objekt mit einem Listener kollidiert, bekomme ich im collidedWith
-Methodenaufruf ein blank GameObject
, damit (object instanceof Bullet)
nicht funktioniert. Keine Überraschung, ich habe in den erzeugten swg BridgeJNI.java
gegraben und folgendes gefunden:
Damit wird vor dem Aufruf der Java-Überladungen ein neues Objekt um den Zeiger gelegt.
Die Hauptfrage ist also, wie man ein Objekt Bullet
bei einer Kollision erhält?
Ich habe mir einen Weg ausgedacht, um das leicht zu erreichen, aber ich muss die automatisch erzeugten Dateien modifizieren, was eine schlechte Idee ist. Ich hoffe also, dass mir ein Swig-Master helfen könnte, die Änderungen an den swig-generierten Dateien vorzunehmen.
Mein kleiner Hack ist, ein jobject * self
in jedem C ++ Side GameObject
-Objekt zu behalten und die Adresse des realen Java-Objekts während der Konstruktion der realen Java-Seite GameObject
zuzuordnen (und nicht die, die nur umschließt der Zeiger). Auf diese Weise könnte ich eine polymorphe getSelf
Methode in C ++ Seite GameObject
definieren und das Ergebnis glücklich in Java verwenden. Gibt es eine Möglichkeit, den swig-generierten Dateien den notwendigen Code hinzuzufügen?
Danke
Hinweis: Wenn Sie Regisseure auf Android ausprobiert haben und sie nicht funktioniert haben, liegt das daran, dass die aktuelle stabile Version dies nicht unterstützt. Laden Sie den Bleeding Edge von der Swig-Website herunter. Aber ich schreibe dies in 22/03/2012 und diese Notiz wird bald unnötig sein. Der Grund, warum der Destruktor nicht virtuell ist, liegt darin, dass die Bleeding Edge-Version das Programm im Destruktor zum Absturz bringt und es dadurch nicht virtuell macht, es vorerst unter Kontrolle zu halten.
Ich habe eine Lösung für dieses Problem zusammengestellt. Es ist nicht ganz die Lösung, die Sie in Ihrer Frage vorgeschlagen haben, es ist mehr Code auf der Java-Seite und kein Extra auf der JNI / C ++ - Seite. (Ich fand es so, wie du es vorgeschlagen hast ziemlich schwierig, in all den möglichen Fällen richtig zu sein).
Ich habe Ihre Klassen auf eine einzelne Header-Datei reduziert:
%Vor% was auch makeCall
hinzugefügt hat, um das Problem offensichtlich zu machen.
Der Trick, den ich verwendet habe, besteht darin, alle Java-abgeleiteten Instanzen von GameObject
in einer HashMap
automatisch zum Zeitpunkt der Erstellung zu registrieren. Dann ist es beim Absenden des Director-Calls nur eine Frage des Nachschlagens in der HashMap.
Dann die Moduldatei:
%Vor% Beachten Sie, dass wir, da alle Java-Instanzen in einer HashMap
gespeichert werden, eine WeakReference
verwenden müssen, um sicher zu sein, dass wir ihre Lebensdauer nicht verlängern und die Garbage Collection verhindern. Wenn Ihnen Threads wichtig sind, fügen Sie die Synchronisation entsprechend hinzu.
Ich habe das getestet mit:
%Vor% Wo JCollisionListener
ist:
und JGameObject
ist:
(Als Referenz, wenn Sie den anderen Ansatz machen wollten, würden Sie eine directorin
typemap schreiben).
Tags und Links java swig polymorphism