Swig c ++ w / Java теряет тип при полиморфных функциях обратного вызова [дублировать]

StackOverflow https://stackoverflow.com/questions/1077387

Вопрос

Возможный Дубликат:
SWIG Java, сохраняющий информацию о классе объектов, исходящих из C ++

Вопрос:Почему мой загруженный объект C ++ теряет свой тип при передаче функции обратного вызова Java?

Настройка:Я взял пример Swig Java для выполнения обратных вызовов и добавил объект, который будет передан в обратный вызов run(Parent p).Обратный вызов работает, как и ожидалось, но когда я передаю Child объект Java, кажется, теряет свой тип и думает, что его тип Parent когда это должно быть Child.Это основано на Пример обратного вызова Swig java.

Информация о системе:Ubuntu 8.04 w / Swig 1.3.33 - на всякий случай, если последний 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()

Как вы можете видеть в выходных данных - объект действительно имеет тип Child, но его имя класса Java является Parent, что неверно...

Если вы посмотрите в обратном вызове 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 был какой-то действительно впечатляющий код, который мог бы помочь людям создавать карты типов с понижением производительности, которые устраняют проблему, но это оказалось очень сложным при небольшом объеме вывода...В любом случае, это было просто и непринужденно.

Если кто-нибудь может найти простое (человеческое) решение, мне было бы интересно услышать об этом.

Сегодня я наткнулся на запись в блоге, это в частности, речь идет о типах downcasting в SWIG, C ++, C# - в любом случае, это может быть хорошим направлением.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top