Domanda

Possibile Duplicare:
SORSO Java Trattenere le informazioni sulla Classe di oggetti che rimbalzano da C++

Domanda:Perché è il mio C++ swigged oggetto di perdere il suo tipo quando viene passato a un Java funzione di callback?

Installazione:Ho preso il Sorso Java esempio per fare richiamate e aggiunto un oggetto per essere passato per il callback run(Parent p).Richiamata, come previsto, ma quando mi passa un Child oggetto Java sembra perdere il suo tipo e pensare che è di tipo Parent quando dovrebbe essere Child.Questo è basato sul Sorso java richiamata esempio.

Info:Ubuntu 8.04 w/ Sorso 1.3.33 - nella denegata l'ultimo Sorso fatto la differenza l'ho testato anche 1.3.39 - che non ha avuto alcun effetto.

Uscite:

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

Come si può vedere nelle uscite - l'oggetto è effettivamente di tipo Bambino, ma anche il nome della classe Java è Padre - che è sbagliato...

Se si guarda in Java richiamata run(Parent p) si può vedere dove sto recuperando la classe Java, Java e davvero non credo che questo oggetto è di tipo Parent - cercando di lanciare questo per Bambino buttare ClassCastException come previsto.

Codice:

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

Questo potrebbe essere un bug di Sorso - ma spero che questo mio essere stupido con C++/tipi di casting...

Ogni pensiero sarebbe molto apprezzato!

È stato utile?

Soluzione

Dopo aver scavato in giro su questo problema per il fine settimana credo che questa è una "comune": il problema che Sorso ha tra le classi in C++ e Java.Il problema si chiama downcast ed è un problema comune amministrazione.Purtroppo l'amministrazione non sembrano essere in grado di gestire anche questo semplice caso.Ho provato ogni combinazione di direttore, come di seguito

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

Nessuno di quello che sembrava per aiutare a tutti, ma facendo il seguente trucco ha funzionato 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";
    }
};

Poi nella classe java per qualsiasi sottotipo è necessario il sovraccarico di ferro da sé.

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

Poi magicamente l'uscita funziona

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

Probabilmente ci dovrebbe essere un modo migliore per fare questo, ma nessuno dei Sorso documentazione mi ha presentato un chiaro esempio di come farlo correttamente.C'era davvero impressionante codice libsbml libreria che potrebbe aiutare le persone a creare il downcast typemaps che risolvere il problema, ma che si era dimostrato molto complesso per un po ' di uscita...Comunque questo è stato semplice e facile.

Se qualcuno riesce a capire un facile (umana) soluzione sarei interessato a sentire su di esso.

Mi sono imbattuto in un post del blog di oggi, è nello specifico, parlando di downcast tipi di SORSO, C++, C# - in ogni caso, potrebbe essere una buona direzione.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top