2013-08-07 9 views
5

Mam bibliotekę C++, której muszę użyć w istniejącej implementacji systemu Android. Używam Androida NDK i korzystam z klas C++ przez JNI.Podklasa klasy abstrakcyjnej C++ w Javie przy użyciu JNI

Jednak nie jestem w stanie znaleźć podklasy klasy abstrakcyjnej C++ w Javie przy użyciu JNI.

Problemy, które napotykam: Moim celem jest zapewnienie implementacji Java dla metod wirtualnych w C++ poprzez podklasowanie abstrakcyjnej klasy C++. Załadowałem bibliotekę macierzystą i próbuję zadeklarować metody natywne. Metody C++ mają słowo kluczowe "wirtualne". Kiedy deklaruję funkcje natywne w Javie po załadowaniu biblioteki C++, "wirtualny" nie jest rozpoznawany. Co jest nie tak?

Każda pomoc jest doceniana. Jestem początkującym użytkownikiem JNI. Z góry dziękuję.

+1

Rozpocznij [tutaj] (http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/intro.html#wp725). Przekonasz się, że klej JNI nie wiąże klas Java z C++. W tym celu potrzebujesz czegoś zbudowanego wokół JNI.[Jace] (http://code.google.com/p/jace/wiki/Overview) jest przydatny, ale nie idzie tak daleko, jak opisujesz. Zakładam, że nie znajdziesz niczego, co pozwoli ci uniknąć ręcznego tworzenia konkretnej klasy C++ i zawijania tego. –

+0

@TomBlodget: Dzięki! Do tworzenia wrapperów, czy sugerujesz jakieś narzędzie, takie jak SWIG, czy jest jakiś inny sposób na zrobienie tego? – vvid

+0

Zobacz również [BridJ] (http://bridj.googlecode.com). –

Odpowiedz

5

Rozważmy mamy klasa 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 
}; 

chcemy utworzyć klasę Bot w Javie, który rozciąga się klasę iVehicle w tym sensie, że nazywa się super powołać się na kod C++ z iVehicle::GetSize() a od C++ punktu widzenia, możemy użyć instancji Bot jako zmiennych iVehicle*. To trudne, ponieważ C++ nie zapewnia dobrej wbudowanej funkcjonalności do refleksji.

Oto jedno z możliwych rozwiązań.

Aby użyć klasy C++, Java musimy wygenerować otoki Java, czyli:

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(); 
} 

Wykorzystanie w Javie jest prosta:

class Bot extends iVehicle 
{ 
    public int GetSize() 
    { 
     if (condition) return 0; 

     // call C++ code 
     return super.GetSize(); 
    } 
} 

Jednakże, istnieje C++ część do ten kod:

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(); 
} 

Podobny kod jest dla GetSize().

Następnie tworząc instancję Javy Bot należy wywołać CreateNativeObject() i przypisać zwróconą wartość do pola NativeObjectHolder.

JNIEXPORT int JNICALL Java_com_test_iVehicle_CreateNativeObject(JNIEnv* env, jobject thiz) 
{ 
    iVehicle* Obj = new iVehicle; 
    return (int)Obj;  
} 

To jest schemat. Aby to zadziałało, musisz dodać kod zniszczenia i parsować klasy C++, aby wygenerować cały ten kod kleju.

Dodano:

W przypadku, gdy jest rzeczywiście iVehicle streszczenie trzeba będzie generować non-abstrakcyjne owijkę, że jesteś w stanie instancję:

class iVehicle 
{ 
    virtual void Run() = 0; 
} 

class iVehicle_Wrapper: public iVehicle 
{ 
    virtual void Run() { ERROR("Abstract method called"); }; 
} 

I instancji iVehicle_Wrapper w CreateNativeObject(). Vuala! Odziedziczyłeś abstrakcyjną klasę C++ w Javie.

+0

Dziękuję za szczegółową odpowiedź. Ale, co jeśli chcę dostarczyć implementację Java dla abstrakcyjnych metod klasy C++ i chcę ponownie użyć tej podklasy Java w C++? – vvid

+0

Używanie podklas Java w C++ jest kontynuacją tej historii. Musisz wygenerować wrapper '' iVehicle_Wrapper'', który będzie zawierał identyfikator obiektu/metody Java i używał JNI do wywołania go. –

+0

Sugeruję, abyś zbadał * klasy rówieśnicze *. Będziesz mieć klasę proxy Java dla 'IVehicle' - która jest abstrakcyjną klasą po stronie Java, która odzwierciedla metody C++. Na końcu C++ potrzebujesz konkretnej implementacji 'iVehicle', która implementuje wszystkie abstrakcyjne funkcje wirtualne, przekazując je za pomocą JNI do proxy Java. – marko