2009-07-03 2 views
3
에 입력 잃는다 C++ 승/

가능한 중복 :
SWIG Java Retaining Class information of the objects bouncing from C++꿀꺽 꿀꺽 자바 다형성 콜백 함수

질문 : 유형을 잃고 객체 swigged 내 C는 + + A를 전달하는 이유 자바 콜백 함수?

설정 : 나는 콜백을 수행하기위한 꿀꺽 꿀꺽 자바 예를 촬영하고 콜백 run(Parent p)에 전달 될 객체를 추가했습니다. 콜백은 예상대로 작동하지만 Child 객체를 전달하면 Java는 해당 유형을 잃어버린 것처럼 보이고 Child 일 때 Parent 유형을 생각합니다. 이는 Swig java callback example을 기반으로합니다.

시스템 정보 : 우분투 8.04/w 꿀꺽 꿀꺽 1.3.33 - 영향을 미치지 아니 - 최신 꿀꺽 꿀꺽가 나는 또한 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 클래스의 이름은 부모 - 잘못 ...

하는 경우 당신은 자바 콜백 run(Parent p)을 보면 자바 클래스를 가져 오는 곳을 볼 수 있습니다. 자바는 실제로이 객체가 Parent 유형이라고 생각합니다.이 객체를 자식에게 캐스팅하려고하면 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입니다. 불행히도 감독은이 간단한 경우조차도 처리 할 수없는 것처럼 보입니다. 나는 감독의 모든 조합을 시도했다 - 그

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

없음 전혀하지만 다음과 같은 해킹 확인 일 일을 도와 것 같았다 아래처럼 :

자바 클래스의 다음
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"; 
    } 
}; 

어떤 하위 유형을위한 과부하 아이언 자체가 필요합니다.

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# - 어쨌든 좋은 방향 일 수 있습니다.