Added a simple example where the current universal
Java wrapping mechanism doesn't work, showing the need to use a different way to wrap polymorphic classes. They are two runtime examples: one for java, which is failing, and one for python, which works fine. Detailed description of the case can be found in the three files committed. git-svn-id: https://swig.svn.sourceforge.net/svnroot/swig/trunk/SWIG@5582 626c5289-ae23-0410-ae9c-e8d60b6d4f22
This commit is contained in:
parent
708021a809
commit
c85521c002
3 changed files with 172 additions and 0 deletions
44
Examples/test-suite/java/virtual_poly_runme.java
Normal file
44
Examples/test-suite/java/virtual_poly_runme.java
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
// virtual_poly test
|
||||||
|
|
||||||
|
import virtual_poly.*;
|
||||||
|
|
||||||
|
public class virtual_poly_runme {
|
||||||
|
|
||||||
|
static {
|
||||||
|
try {
|
||||||
|
System.loadLibrary("virtual_poly");
|
||||||
|
} 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 argv[]) {
|
||||||
|
|
||||||
|
NDouble d = new NDouble(3.5);
|
||||||
|
NInt i = new NInt(2);
|
||||||
|
|
||||||
|
//
|
||||||
|
// These two natural 'copy' forms fail, only java and csharp
|
||||||
|
// because no polymorphic return types are supported.
|
||||||
|
// But we can live with this restriction, more or less.
|
||||||
|
//
|
||||||
|
// NDouble dc = d.copy();
|
||||||
|
// NInt ic = i.copy();
|
||||||
|
|
||||||
|
//
|
||||||
|
// These two 'copy' forms work, but we end with plain NNumbers
|
||||||
|
//
|
||||||
|
NNumber dc = d.copy();
|
||||||
|
NNumber ic = i.copy();
|
||||||
|
|
||||||
|
//
|
||||||
|
// The real problem is that there is no way to recover the
|
||||||
|
// original NInt or NDouble objects, even when you try
|
||||||
|
// to use the plain and natural C++ dynamic_cast operations,
|
||||||
|
// since they fail:
|
||||||
|
//
|
||||||
|
NDouble ddc = virtual_poly.NDouble_dynamic_cast(dc);
|
||||||
|
NInt idc = virtual_poly.NInt_dynamic_cast(dc);
|
||||||
|
}
|
||||||
|
}
|
||||||
19
Examples/test-suite/python/virtual_poly_runme.py
Normal file
19
Examples/test-suite/python/virtual_poly_runme.py
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
import virtual_poly
|
||||||
|
|
||||||
|
|
||||||
|
d = virtual_poly.NDouble(3.5)
|
||||||
|
i = virtual_poly.NInt(2)
|
||||||
|
|
||||||
|
dc = d.copy()
|
||||||
|
ic = i.copy()
|
||||||
|
|
||||||
|
if d.get() != dc.get():
|
||||||
|
raise RuntimeError
|
||||||
|
|
||||||
|
if i.get() != ic.get():
|
||||||
|
raise RuntimeError
|
||||||
|
|
||||||
|
|
||||||
|
ddc = virtual_poly.NDouble_dynamic_cast(dc)
|
||||||
|
if d.get() != ddc.get():
|
||||||
|
raise RuntimeError
|
||||||
109
Examples/test-suite/virtual_poly.i
Normal file
109
Examples/test-suite/virtual_poly.i
Normal file
|
|
@ -0,0 +1,109 @@
|
||||||
|
%module virtual_poly
|
||||||
|
|
||||||
|
|
||||||
|
%inline %{
|
||||||
|
struct NNumber
|
||||||
|
{
|
||||||
|
virtual ~NNumber() {};
|
||||||
|
virtual NNumber* copy() const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
NInt and NDouble are both NNumber derivated classes, but they
|
||||||
|
have more different than common attributes.
|
||||||
|
|
||||||
|
In particular the function 'get', that is type dependent, can't
|
||||||
|
be included in the NNumber abstract interface.
|
||||||
|
|
||||||
|
For this reason, the virtual 'copy' function has a polymorphic
|
||||||
|
return type, since in most of the cases we don't want to lost the
|
||||||
|
original object type, which is very very important.
|
||||||
|
|
||||||
|
Using the polymorphic return type reduced greatly the need of
|
||||||
|
using 'dynamic_cast' at the C++ side, and at the target languages
|
||||||
|
that support it. Python is a target language that support
|
||||||
|
this feature, Java and Csharp don't.
|
||||||
|
|
||||||
|
*/
|
||||||
|
struct NInt : NNumber
|
||||||
|
{
|
||||||
|
NInt(int v) : val(v)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
int get() const
|
||||||
|
{
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual NInt* copy() const
|
||||||
|
{
|
||||||
|
return new NInt(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
int val;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct NDouble : NNumber
|
||||||
|
{
|
||||||
|
NDouble(double v) : val(v)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
double get() const
|
||||||
|
{
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual NDouble* copy() const
|
||||||
|
{
|
||||||
|
return new NDouble(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
double val;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Java (and csharp) can not support the polymorphic return type for
|
||||||
|
'copy'. So, it just emit 'plain' copy functions for all the cases:
|
||||||
|
|
||||||
|
NNumber* NNumber::copy() const;
|
||||||
|
NNumber* NInt::copy() const;
|
||||||
|
NNumber* NDouble::copy() const;
|
||||||
|
|
||||||
|
In the last two cases, the original 'NInt' and 'NDouble' return
|
||||||
|
types are lost in the target side. This seems to be a restriction
|
||||||
|
of the language (strongly typed and 'by value' oriented), and
|
||||||
|
there is not much that can be done to work it around.
|
||||||
|
|
||||||
|
However, to improve the situation, and to be able to recover the
|
||||||
|
original data types, we try adding 'dynamic_cast' interfaces in
|
||||||
|
the target language sides. This is a natural mechanism since is
|
||||||
|
exactly the same you will do in the C++ side if is needed.
|
||||||
|
*/
|
||||||
|
inline NInt* NInt_dynamic_cast(NNumber* n) {
|
||||||
|
return dynamic_cast<NInt*>(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline NDouble* NDouble_dynamic_cast(NNumber* n) {
|
||||||
|
return dynamic_cast<NDouble*>(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
but they don't work either in Java (see the
|
||||||
|
java/virtual_poly_runme.java file), because of the current way
|
||||||
|
polymorphic types are wrapped. Using the wrapping method employed
|
||||||
|
with directors (which are also polymorphic types) should allows
|
||||||
|
to use the C++ dynamic_cast and recover the original types at the
|
||||||
|
Java side. And to do that, it is necessary to identify which
|
||||||
|
classes are polymorphic (the "polymorphic" attribute does that)
|
||||||
|
and apply the proper wrapping mechanism.
|
||||||
|
|
||||||
|
The dynamic_cast interfaces added to this module, currently work
|
||||||
|
great in languages like python, but in there the polymorphic
|
||||||
|
return type also works, so, you are not forced to use them as a
|
||||||
|
fixing mechanism (see the python/virtual_poly_runme.py file).
|
||||||
|
*/
|
||||||
|
%}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue