문제

가능한 복제 :
Swig Java C ++에서 튀는 물체의 클래스 정보를 유지합니다.

의문: 왜 내 C ++ swigged 객체가 Java 콜백 함수로 전달 될 때 유형을 잃어 버리는가?

설정: 콜백을 수행하기 위해 Swig Java 예제를 가져 와서 콜백에 전달할 객체를 추가했습니다. run(Parent p). 콜백은 예상대로 작동하지만 내가 통과 할 때 Child 객체 Java는 유형을 잃어버린 것 같습니다. Parent 해야 할 때 Child. 이것은 기준입니다 Swig Java 콜백 예제.

시스템 정보: Ubuntu 8.04 w/ swig 1.3.33- Off Chance에서 최신 SWIG는 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 - 이것을 어린이에게 캐스팅하려고하면 던질 것입니다 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

이것은 SWIG의 버그일지도 모릅니다. 그러나 나는 이것이 C ++ 유형/캐스팅으로 바보가되기를 바라고 ...

어떤 생각도 대단히 감사 할 것입니다!

도움이 되었습니까?

해결책

주말 동안이 문제를 파헤친 후 SWIG가 C ++ 클래스와 Java 사이에있는 "일반적인"문제라고 생각합니다. 문제를 호출합니다 다운 캐스팅 그리고 일반적인 문제입니다 감독. 불행히도 감독들은이 간단한 사건조차도 처리 할 수없는 것 같습니다. 아래와 같이 감독의 모든 조합을 시도했습니다

%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";
    }
};

그런 다음 하위 유형에 대한 Java 클래스에서 과부하 아이런 자체가 필요합니다.

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

이 작업을 수행하는 더 좋은 방법이있을 수 있지만 SWIG 문서 중 어느 것도 제대로 수행하는 방법에 대한 명확한 예를 제시하지 않았습니다. LibSBML 라이브러리에는 사람들이 문제를 해결하는 다운 캐스팅 유형 맵을 만드는 데 도움이 될 수있는 정말 인상적인 코드가 있었지만 출력이 거의 없기 때문에 매우 복잡한 것으로 판명되었습니다. 어쨌든 이것은 간단하고 쉬웠습니다.

누구든지 쉬운 (인간) 솔루션을 알아낼 수 있다면 그것에 대해 듣는 데 관심이 있습니다.

나는 오늘 블로그 게시물을 만났다 특히 SWIG, C ++, C#의 다운 캐스팅 유형에 대해 이야기하고 있습니다. - 어쨌든 좋은 방향 일 수 있습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top