2013-08-07 16 views
5

私は既存のAndroid実装で使用しなければならないC++ライブラリを持っています。私はAndroid NDKを使用しており、JNI経由でC++クラスを使用しています。JNIを使​​用してJavaでC++抽象クラスをサブクラス化する

しかし、JNIを使​​用してJavaでC++抽象クラスをサブクラス化する方法を見つけることができません。

私が直面する問題: 私の目的は、抽象的なC++クラスをサブクラス化することによって、C++の仮想メソッドにJava実装を提供することです。 私はネイティブライブラリを読み込んでおり、ネイティブメソッドを宣言しようとしています。 C++メソッドにはキーワード 'virtual'があります。 C++ライブラリをロードした後にJavaでネイティブ関数を宣言すると、 'virtual'は認識されません。ここで何が間違っていますか?

何か助けていただければ幸いです。私はJNIの初心者です。前もって感謝します。

+1

[こちら](http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/intro.html#wp725)を開始してください。あなたは、JNI接着剤がJavaをC++クラスに束縛していないことがわかります。そのためには、JNIの周りに構築されたものが必要です。[Jace](http://code.google.com/p/jace/wiki/Overview)は便利ですが、あなたが描いた限りではありません。私は、あなたが手作業で具体的なC++クラスを作成してラップするのを避けるためのものは何も見つけられないと考えています。 –

+0

@TomBlodget:ありがとう!ラッパーを作成するには、SWIGのようなツールをお勧めしますか、それを行うには他の方法がありますか? – vvid

+0

[BridJ](http://bridj.googlecode.com)もご覧ください。 –

答えて

5

のは、我々は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 
}; 

我々はsuperへの呼び出し意味でクラスiVehicleを拡張するJavaにおけるクラスBotを作成したいCから、iVehicle::GetSize()からC++コードを呼び出し、++私たちは、BotのインスタンスをiVehicle*という変数として使用することができます。 C++はリフレクションのための優れた組み込み機能を提供していないので難しいです。

ここに1つの解決策があります。

たちはすなわち、Javaラッパーを生成する必要がJavaでC++クラスを使用するには、次の

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

Javaで使い方は簡単です:

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

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

しかし、C++の部分はにありこのコード:

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

同様のコードはGetSize()です。

次に、JavaのBotのインスタンスを作成するには、CreateNativeObject()を呼び出して、NativeObjectHolderフィールドに戻り値を割り当てる必要があります。

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

これはスキームです。この作業を行うには、破壊コードを追加し、C++クラスを解析してこのすべてのグルーコードを生成する必要があります。

を追加しました:

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

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

そしてCreateNativeObject()iVehicle_Wrapperをインスタンス化:iVehicleはあなたがインスタンス化することができます非抽象ラッパーを生成する必要があります実際に抽象的である場合には

。 Vuala! Javaで抽象的なC++クラスを継承しています。

+0

詳細な返信をありがとうございます。しかし、C++クラスの抽象メソッドにJava実装を提供し、このJavaサブクラスをC++で再度使用したい場合はどうなりますか? – vvid

+0

C++でJavaサブクラスを使用することは、このストーリーの続編です。 Javaのオブジェクト/メソッドのIDを保持し、それを呼び出すためにJNIを使​​用するラッパー '' iVehicle_Wrapper''を生成する必要があります。 –

+0

*ピアクラス*を調べることをお勧めします。 'IVehicle'のJavaプロキシクラス - C++メソッドをミラーリングするもののJava側の抽象クラスです。 C++の終わりでは、すべての抽象仮想関数を実装する 'iVehicle'の具体的な実装を望み、JNIでそれらをJavaプロキシに転送します。 – marko

関連する問題