2009-07-03 4 views
3
に入力失うC++/wの

可能性の重複:
SWIG Java Retaining Class information of the objects bouncing from C++ガブガブ飲むJavaは多型のコールバック関数

質問: その型を失うオブジェクトswigged私のC++が渡されるのはなぜJavaのコールバック関数?

セットアップ: 私は、コールバックを行うためガブガブ飲むJavaの例をとると、コールバックrun(Parent p)に渡されるオブジェクトを追加しました。コールバックは期待どおりに機能しますが、Childオブジェクトを渡すと、Javaはその型を失い、ChildのときにはParentと考えられます。これはSwig java callback exampleに基づいています。

システム情報:/ガブガブ飲む1.3.33 のUbuntu 8.04ワット - 影響を与えなかった - 最新ガブガブ飲むが、私はまた、1.3.39をテストした違いを作っオフのチャンスに。

出力

 
bash$ java -Djava.library.path=. runme 
Adding and calling a normal C++ callback 
---------------------------------------- 
Callback::run(5Child) 
Callback::~Callback() 

Adding and calling a Java callback 
------------------------------------ 
JavaCallback.run(Parent) 
Callback::run(5Child) 
Callback::~Callback() 

あなたは出力で見ることができるように - オブジェクトの型は、子供の実際にある - が、そのJavaクラス名は、親会社である - 間違っている...

の場合あなたはJavaコールバックrun(Parent p)を見て、私はJavaクラスをフェッチしている場所を見ることができます。そしてJavaは実際にこのオブジェクトがParentタイプのものだと思います - これをChildにキャストしようとすると、期待どおりにClassCastExceptionが投げられます。

コード

/* File : example.i */ 
%module(directors="1") example 
%{ 
#include "example.h" 
%} 

%include "std_string.i" 

/* turn on director wrapping Callback */ 
%feature("director") Callback; 

%include "example.h" 




/* File : example.h */ 
#include <string> 
#include <cstdio> 
#include <iostream> 
#include <typeinfo> 

class Parent { 
public: 
    virtual const char* getName() { 
     return typeid(*this).name(); 
    } 
}; 


class Child : virtual public Parent { 
}; 



class Callback { 
public: 
    virtual ~Callback() { std::cout << "Callback::~Callback()" << std:: endl; } 
    virtual void run(Parent& p) { std::cout << "Callback::run(" << p.getName() << ")" << std::endl; } 
}; 


class Caller { 
private: 
    Callback *_callback; 
public: 
    Caller(): _callback(0) {} 
    ~Caller() { delCallback(); } 
    void delCallback() { delete _callback; _callback = 0; } 
    void setCallback(Callback *cb) { delCallback(); _callback = cb; } 
    void call() { 
     Parent *p = new Child(); 
     if (_callback) 
      _callback->run(*p); 
     delete p; 
    } 
}; 



/* File: runme.java */ 
public class runme 
{ 
    static { 
    try { 
     System.loadLibrary("example"); 
    } catch (UnsatisfiedLinkError e) { 
     System.err.println("Native code library failed to load. See the chapter on Dynamic Linking Problems in the SWIG Java documentation for help.\n" + e); 
     System.exit(1); 
    } 
    } 

    public static void main(String[] args) 
    { 
    System.out.println("Adding and calling a normal C++ callback"); 
    System.out.println("----------------------------------------"); 

    Caller    caller = new Caller(); 
    Callback   callback = new Callback(); 

    caller.setCallback(callback); 
    caller.call(); 
    caller.delCallback(); 

    callback = new JavaCallback(); 

    System.out.println(); 
    System.out.println("Adding and calling a Java callback"); 
    System.out.println("------------------------------------"); 

    caller.setCallback(callback); 
    caller.call(); 
    caller.delCallback(); 

    // Test that a double delete does not occur as the object has already been deleted from the C++ layer. 
    // Note that the garbage collector can also call the delete() method via the finalizer (callback.finalize()) 
    // at any point after here. 
    callback.delete(); 

    System.out.println(); 
    System.out.println("java exit"); 
    } 
} 

class JavaCallback extends Callback 
{ 
    public JavaCallback() 
    { 
    super(); 
    } 

    public void run(Parent p) 
    { 
    System.out.println("JavaCallback.run("+p.getClass().getSimpleName()+")"); 
    super.run(p); 
    } 
} 




# File: Makefile 
TOP  = ../.. 
SWIG  = $(TOP)/../preinst-swig 
CXXSRCS = example.cxx 
TARGET  = example 
INTERFACE = example.i 
SWIGOPT = 

all:: java 

java:: 
    $(MAKE) -f $(TOP)/Makefile CXXSRCS='$(CXXSRCS)' SWIG='$(SWIG)' \ 
    SWIGOPT='$(SWIGOPT)' TARGET='$(TARGET)' INTERFACE='$(INTERFACE)' java_cpp 
    javac *.java 

clean:: 
    $(MAKE) -f $(TOP)/Makefile java_clean 

check: all 

これはガブガブ飲むのバグかもしれない - しかし、私は、これはC++の型/キャストと私のこと愚かであることを願っています...

任意の考えは次のようになり非常に感謝!

答えて

1

この問題を週末に掘り起こした後、これはSwigがC++クラスとJavaの間に持つ「共通の」問題だと思います。この問題はdowncastingと呼ばれ、よくある問題はdirectorsです。残念ながら、取締役はこの単純なケースでも対処できないようです。あなたは

class Callback { 
public: 
    virtual ~Callback() { std::cout << "Callback::~Callback()" << std:: endl; } 
    virtual void run(Parent& p) { 
     std::cout << "Callback::run1(" << p.getName() << ")\n"; 
    } 

    virtual void run(Child& c) { 
     std::cout << "Callback::run2(" << c.getName() << ")\n"; 
    } 
}; 

を次にJavaクラスにどんなサブタイプについて:その

%feature("director") Callback; 
%feature("director") Parent; 
%feature("director") Child; 

以下のどれも全く助けるように見えていないようですが、以下のハックを行うと、[OK]を働いていた - 私はディレクターのすべての組み合わせを試してみましたオーバーロードアイロン自体が必要です。

class JavaCallback extends Callback 
{ 
    public void run(Child p) 
    { 
    out.p("JavaCallback.run("+p.getClass().getSimpleName()+")"); 
    out.p("p.getName() = "+p.getName()); 
    super.run(p); 
    } 
} 

は、その後魔法の出力が

 
bash$ java -Djava.library.path=. runme 
Adding and calling a normal C++ callback 
---------------------------------------- 
make child 
child type class Parent 
Callback::run2(5Child) 
Callback::~Callback() 
Adding and calling a Java callback 
------------------------------------ 
JavaCallback.run(Child) 
p.getName() = 5Child 
Callback::run2(5Child) 
Callback::~Callback() 
java exit 

の作品、おそらくこれを行うには良い方法があるはずですが、ガブガブ飲むのドキュメントのどれもが私に適切にこれを行う方法の明確な例を提示していません。 libsbmlライブラリには本当に印象的なコードがいくつかありましたが、これは人々が問題を修正するダウンキャスト型のtypemapを作成するのに役立つかもしれませんが、それは出力がほとんどないために非常に複雑であることが証明されていました...とにかく簡単で簡単でした。

誰かが簡単な(人間の)解決策を見つけ出すことができたら、私はそれについて聞きたいと思うだろう。

今日私はブログ投稿をしましたが、それはspecifically is talking about downcasting types in SWIG, C++, C#です - とにかく、良い方向かもしれません。

関連する問題