2013-08-07 13 views
5

Ho una libreria C++ che devo usare in un'implementazione Android esistente. Sto usando Android NDK e uso le classi C++ tramite JNI.Sottoclasse una classe astratta C++ in Java usando JNI

Tuttavia, non sono in grado di trovare la sottoclasse di una classe astratta C++ in Java utilizzando JNI.

I problemi che devo affrontare: Il mio obiettivo è fornire un'implementazione Java per i metodi virtuali in C++ sottoclassando la classe C++ astratta. Ho caricato la libreria nativa e sto cercando di dichiarare i metodi nativi. I metodi C++ hanno la parola chiave 'virtuale'. Quando dichiaro le funzioni native in Java dopo aver caricato la libreria C++, "virtuale" non viene riconosciuto. Cosa c'è di sbagliato qui?

Qualsiasi aiuto è apprezzato. Sono un novizio di JNI. Grazie in anticipo.

+1

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. –

+0

@TomBlodget: Grazie! Per creare wrapper, suggerisci qualche strumento come SWIG o c'è qualche altro modo per farlo? – vvid

+0

Dai un'occhiata anche a [BridJ] (http://bridj.googlecode.com). –

risposta

5

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.

+0

Grazie per la risposta dettagliata. Ma, cosa succede se voglio fornire un'implementazione Java per i metodi astratti della classe C++ e voglio usare ancora questa sottoclasse Java in C++? – vvid

+0

L'utilizzo di sottoclassi Java in C++ è un seguito di questa storia. È necessario generare un wrapper '' iVehicle_Wrapper'' che conserverà un ID dell'oggetto/metodo Java e userà JNI per chiamarlo. –

+0

Ti suggerisco di investigare * classi peer *. Sarai una classe proxy Java per 'IVehicle' - che è una classe astratta sul lato Java delle cose che rispecchiano i metodi C++. Sul lato C++, si desidera un'implementazione concreta di 'iVehicle' che implementa tutte le funzioni virtuali astratte, inoltrandole con JNI al proxy Java. – marko

Problemi correlati