Swig c ++ w / Java丢失多态回调函数上的类型 [英] Swig c++ w/ Java loses type on polymorphic callback functions

查看:529
本文介绍了Swig c ++ w / Java丢失多态回调函数上的类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述


可能重复:


问题
为什么我的C ++ swigged对象在传递给Java回调函数时会丢失它的类型?



设置
我使用了Swig Java示例来执行回调,并添加了一个传递给回调的对象 run父p)。回调的工作原理如预期,但当我通过一个 Child 对象时,Java似乎失去了它的类型,并认为它的类型 Parent 何时应该 Child 。这是基于
Swig java回调示例



系统信息
Ubuntu 8.04 w / Swig 1.3.33 -



<$ p $

p>
bash $ java -Djava.library.path =。 runme
添加和调用正常的C ++回调
---------------------------------- ------
Callback :: run(5Child)
Callback ::〜Callback()

添加和调用Java回调
---- --------------------------------
JavaCallback.run(Parent)
Callback :: run (5Child)
Callback ::〜Callback()

正如你可以在输出中看到的 - - 如果你看一下Java回调函数 run(Parent p)

/ code>你可以看到我在获取Java类,并且Java确实认为这个对象是 Parent 类型 - 试图把这个转换为Child >

$


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

%includestd_string.i

/ *打开导演包装回调* /
% (director)回调;

%includeexample.h




/ *文件: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 {
};



类回调{
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(){
父* p = new Child();
if(_callback)
_callback-> run(* p);
delete p;
}
};



/ *文件:runme.java * /
public class runme
{
static {
try {
System.loadLibrary(example);
} catch(UnsatisfiedLinkError e){
System.err.println(本机代码库无法加载。有关帮助,请参见SWIG Java文档中的动态链接问题一章。\\\
+ e );
System.exit(1);
}
}

public static void main(String [] args)
{
System.out.println(添加和调用普通C ++回电话);
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(添加和调用Java回调);
System.out.println(------------------------------------);

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

//测试双重删除不会发生,因为对象已经从C ++层中删除。
//注意垃圾收集器也可以通过finalizer(callback.finalize())
//调用delete()方法,在这之后的任何点。
callback.delete();

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

类JavaCallback extends回调
{
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 =
$ b b 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

检查:all

这可能是Swig中的一个错误 - 但我希望这是我的愚蠢与C + +类型/铸造...



任何想法非常感谢!

解决方案

在解决这个问题的周末后,我想这是一个常见的问题,Swig C ++类和Java之间。此问题称为向下转换,是一个常见问题,董事。不幸的是,导演似乎不能处理这个简单的情况。

 %feature(director)回调; 
%feature(director)父母;
%feature(director)儿童;

没有一个似乎有帮助,但做以下hack工作确定:

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

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

然后在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
添加和调用正常的C ++回调
---------------------------------- ------
make child
子类型类父
Callback :: run2(5Child)
Callback ::〜Callback()
添加和调用Java回调
------------------------------------
JavaCallback.run Child)
p.getName()= 5Child
Callback :: run2(5Child)
Callback ::〜Callback()
java exit

应该有一个更好的方法来做到这一点,但没有一个Swig文档给我一个清楚的例子,如何正确地这样做。有一些非常令人印象深刻的代码在libsbml库,可能会帮助人们创建downcasting typemaps解决这个问题,但这被证明非常复杂的小输出...无论如何这是简单和容易。



如果任何人能找出一个简单的(人类)解决方案,我有兴趣听到它。



今天我碰到一个博客,它具体说的是SWIG,C ++,C#中的向下转换类型 - 无论如何,这可能是一个很好的方向。


Possible Duplicate:
SWIG Java Retaining Class information of the objects bouncing from C++

Question: Why is my C++ swigged object losing its type when passed to a Java callback function?

Setup: I've taken the Swig Java example for doing callbacks and added an object to be passed to the callback run(Parent p). The callback works as expected but when I pass a Child object the Java seems to lose its type and think its of type Parent when it should be Child. This is based on the Swig java callback example.

System Info: Ubuntu 8.04 w/ Swig 1.3.33 - on the off chance the latest Swig made a difference I also tested 1.3.39 - which had no effect.

Outputs:

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

As you can see in the outputs - the object is really of type Child - but its Java class name is Parent - which is wrong...

If you look in the Java callback run(Parent p) you can see where I'm fetching the Java class, and Java really does think this object is of type Parent - trying to cast this to Child will throw ClassCastException as expected.

Code:

/* 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

This might be a bug in Swig - but I'm hoping that this is my being stupid with C++ types/casting...

Any thoughts would be greatly appreciated!

解决方案

After digging around on this problem for the weekend I guess this is a "common" problem that Swig has between C++ classes and Java. The issue is called downcasting and is a common problem of directors. Unfortunately the directors don't seem to be able to handle even this simple case. I've tried every combination of director - like below

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

None of that seemed to help at all but doing the following hack worked ok:

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

Then in the java class for whatever subtype you need the overload irons itself out.

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

Then magically the output works

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

There should probably be a better way to do this, but none of the Swig documentation presented me a clear example of how to do this properly. There was some really impressive code in the libsbml library which might help people create downcasting typemaps which fix the problem, but that was proving very complex for little output... Anyway this was simple and easy.

If anyone can figure out an easy (human) solution I'd be interested in hearing about it.

I ran into a blog post today, it specifically is talking about downcasting types in SWIG, C++, C# - anyway, it might be a good direction.

这篇关于Swig c ++ w / Java丢失多态回调函数上的类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆