diff --git a/SWIG/Examples/java/extend/Makefile b/SWIG/Examples/java/extend/Makefile new file mode 100644 index 000000000..69fb4e670 --- /dev/null +++ b/SWIG/Examples/java/extend/Makefile @@ -0,0 +1,18 @@ +TOP = ../.. +SWIG = $(TOP)/../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 diff --git a/SWIG/Examples/java/extend/example.cxx b/SWIG/Examples/java/extend/example.cxx new file mode 100644 index 000000000..450d75608 --- /dev/null +++ b/SWIG/Examples/java/extend/example.cxx @@ -0,0 +1,4 @@ +/* File : example.cxx */ + +#include "example.h" + diff --git a/SWIG/Examples/java/extend/example.h b/SWIG/Examples/java/extend/example.h new file mode 100644 index 000000000..b27ab9711 --- /dev/null +++ b/SWIG/Examples/java/extend/example.h @@ -0,0 +1,56 @@ +/* File : example.h */ + +#include +#include +#include +#include +#include + +class Employee { +private: + std::string name; +public: + Employee(const char* n): name(n) {} + virtual std::string getTitle() { return getPosition() + " " + getName(); } + virtual std::string getName() { return name; } + virtual std::string getPosition() const { return "Employee"; } + virtual ~Employee() { printf("~Employee() @ %p\n", this); } +}; + + +class Manager: public Employee { +public: + Manager(const char* n): Employee(n) {} + virtual std::string getPosition() const { return "Manager"; } +}; + + +class EmployeeList { + std::vector list; +public: + EmployeeList() { + list.push_back(new Employee("Bob")); + list.push_back(new Employee("Jane")); + list.push_back(new Manager("Ted")); + } + void addEmployee(Employee *p) { + list.push_back(p); + std::cout << "New employee added. Current employees are:" << std::endl; + std::vector::iterator i; + for (i=list.begin(); i!=list.end(); i++) { + std::cout << " " << (*i)->getTitle() << std::endl; + } + } + const Employee *get_item(int i) { + return list[i]; + } + ~EmployeeList() { + std::vector::iterator i; + std::cout << "~EmployeeList, deleting " << list.size() << " employees." << std::endl; + for (i=list.begin(); i!=list.end(); i++) { + delete *i; + } + std::cout << "~EmployeeList empty." << std::endl; + } +}; + diff --git a/SWIG/Examples/java/extend/example.i b/SWIG/Examples/java/extend/example.i new file mode 100644 index 000000000..c8ec32e09 --- /dev/null +++ b/SWIG/Examples/java/extend/example.i @@ -0,0 +1,15 @@ +/* File : example.i */ +%module(directors="1") example +%{ +#include "example.h" +%} + +%include "std_vector.i" +%include "std_string.i" + +/* turn on director wrapping for Manager */ +%feature("director") Employee; +%feature("director") Manager; + +%include "example.h" + diff --git a/SWIG/Examples/java/extend/index.html b/SWIG/Examples/java/extend/index.html new file mode 100644 index 000000000..b4ddbf244 --- /dev/null +++ b/SWIG/Examples/java/extend/index.html @@ -0,0 +1,21 @@ + + +SWIG:Examples:java:extend + + + + + +SWIG/Examples/java/extend/ +
+ +

Extending a simple C++ class in Java

+ +$Header
+ +

+This example illustrates the extending of a C++ class with cross language polymorphism. + +


+ + diff --git a/SWIG/Examples/java/extend/main.java b/SWIG/Examples/java/extend/main.java new file mode 100644 index 000000000..3924ec787 --- /dev/null +++ b/SWIG/Examples/java/extend/main.java @@ -0,0 +1,95 @@ +// This file illustrates the cross language polymorphism using directors. + + +// CEO class, which overrides Employee::getPosition(). + +class CEO extends Manager { + public CEO(String name) { + super(name); + } + public String getPosition() { + return "CEO"; + } +} + + +public class main { + 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 argv[]) + { + + // Create an instance of our employee extension class, CEO. The calls to + // getName() and getPosition() are standard, the call to getTitle() uses + // the director wrappers to call CEO.getPosition. e = CEO("Alice") + + CEO e = new CEO("Alice"); + System.out.println( e.getName() + " is a " + e.getPosition() ); + System.out.println( "Just call her \"" + e.getTitle() + "\"" ); + System.out.println( "----------------------" ); + + + // Create a new EmployeeList instance. This class does not have a C++ + // director wrapper, but can be used freely with other classes that do. + + EmployeeList list = new EmployeeList(); + + // EmployeeList owns its items, so we must surrender ownership of objects + // we add. This involves first calling the __disown__ method to tell the + // C++ director to start reference counting. We reassign the resulting + // weakref.proxy to e so that no hard references remain. This can also be + // done when the object is constructed, as in: e = + // CEO("Alice").__disown__() + +// e = e.__disown__(); + list.addEmployee(e); + System.out.println( "----------------------" ); + + // Now we access the first four items in list (three are C++ objects that + // EmployeeList's constructor adds, the last is our CEO). The virtual + // methods of all these instances are treated the same. For items 0, 1, and + // 2, both all methods resolve in C++. For item 3, our CEO, getTitle calls + // getPosition which resolves in Java. The call to getPosition is + // slightly different, however, from the e.getPosition() call above, since + // now the object reference has been "laundered" by passing through + // EmployeeList as an Employee*. Previously, Java resolved the call + // immediately in CEO, but now Java thinks the object is an instance of + // class Employee (actually EmployeePtr). So the call passes through the + // Employee proxy class and on to the C wrappers and C++ director, + // eventually ending up back at the CEO implementation of getPosition(). + // The call to getTitle() for item 3 runs the C++ Employee::getTitle() + // method, which in turn calls getPosition(). This virtual method call + // passes down through the C++ director class to the Java implementation + // in CEO. All this routing takes place transparently. + + System.out.println( "(position, title) for items 0-3:" ); + + System.out.println( " " + list.get_item(0).getPosition() + ", \"" + list.get_item(0).getTitle() + "\"" ); + System.out.println( " " + list.get_item(1).getPosition() + ", \"" + list.get_item(1).getTitle() + "\"" ); + System.out.println( " " + list.get_item(2).getPosition() + ", \"" + list.get_item(2).getTitle() + "\"" ); + System.out.println( " " + list.get_item(3).getPosition() + ", \"" + list.get_item(3).getTitle() + "\"" ); + System.out.println( "----------------------" ); + + // Time to delete the EmployeeList, which will delete all the Employee* + // items it contains. The last item is our CEO, which gets destroyed as its + // reference count goes to zero. The Java destructor runs, and is still + // able to call self.getName() since the underlying C++ object still + // exists. After this destructor runs the remaining C++ destructors run as + // usual to destroy the object. + + list.delete(); + System.out.println( "----------------------" ); + + // All done. + + System.out.println( "java exit" ); + + } +}