Consideriamo che abbiamo una classe C++:
class iVehicle
{
public:
virtual void Run() {}; // not-pure virtual here for simplicity of a wrapper, but could be pure (see the end of the post)
virtual int GetSize() const; // we want to reuse it in Java
};
Vogliamo creare una classe Bot
in Java che estende la classe iVehicle
nel senso che chiama a super
invocare il codice C++ da iVehicle::GetSize()
e, dal C++ punto di vista, possiamo usare le istanze di Bot
come variabili iVehicle*
. È difficile da quando C++ non offre buone funzionalità integrate per la riflessione.
Ecco una possibile soluzione.
Per utilizzare la classe C++ in Java abbiamo bisogno di generare un wrapper Java, vale a dire:
class iVehicle
{
public void Run() { Native_Run(); }
public int GetSize() { return Native_GetSize(); }
private native void Native_Run();
private native int Native_GetSize();
// typecasted to pointer in C++
private int NativeObjectHolder;
// create C++ object
native static private int CreateNativeObject();
}
L'uso in Java è semplice:
class Bot extends iVehicle
{
public int GetSize()
{
if (condition) return 0;
// call C++ code
return super.GetSize();
}
}
Tuttavia, v'è un C parte ++ per questo codice:
static jfieldID gNativeObjectHolderFieldID;
JNIEXPORT void JNICALL Java_com_test_iVehicle_Run(JNIEnv* env, jobject thiz)
{
int Value = env->GetIntField(thiz, gNativeObjectHolderFieldID);
iVehicle* Obj = (iVehicle*)Obj;
// todo: add checks here, for NULL and for dynamic casting
Obj->Run();
}
Il codice simile è per GetSize()
.
Quindi, creando un'istanza di Java Bot
, è necessario chiamare CreateNativeObject()
e assegnare il valore restituito al campo NativeObjectHolder
.
JNIEXPORT int JNICALL Java_com_test_iVehicle_CreateNativeObject(JNIEnv* env, jobject thiz)
{
iVehicle* Obj = new iVehicle;
return (int)Obj;
}
Quindi, questo è lo schema. Per fare questo, dovrai aggiungere il codice di distruzione e analizzare le classi C++ per generare tutto questo codice di colla.
Aggiunto:
Nel caso in cui iVehicle
è in realtà astratta si dovrà generare un wrapper non astratta che si è in grado di creare un'istanza di:
class iVehicle
{
virtual void Run() = 0;
}
class iVehicle_Wrapper: public iVehicle
{
virtual void Run() { ERROR("Abstract method called"); };
}
E istanziare iVehicle_Wrapper
in CreateNativeObject()
. Vuala! Hai ereditato una classe C++ astratta in Java.
Inizio [qui] (http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/intro.html#wp725). Scoprirai che la colla JNI non lega le classi da Java a C++. Per questo, avresti bisogno di qualcosa costruito attorno a JNI.[Jace] (http://code.google.com/p/jace/wiki/Overview) è utile ma non si spinge fino in fondo. La mia scommessa è che non troverai nulla che ti impedisca di creare manualmente una classe concreta di C++ e di completarla. –
@TomBlodget: Grazie! Per creare wrapper, suggerisci qualche strumento come SWIG o c'è qualche altro modo per farlo? – vvid
Dai un'occhiata anche a [BridJ] (http://bridj.googlecode.com). –