Merge pull request #493 from michael-schaller/dir-examples

[Go] Undelete and updated the 'callback' and 'extend' examples.
This commit is contained in:
Ian Lance Taylor 2015-08-09 07:31:09 -07:00
commit 01edfef3b8
22 changed files with 552 additions and 145 deletions

View file

@ -606,22 +606,22 @@ completely to avoid common pitfalls with directors in Go.
<H4><a name="Go_director_example_cpp_code"></a>23.4.7.1 Example C++ code</H4> <H4><a name="Go_director_example_cpp_code"></a>23.4.7.1 Example C++ code</H4>
<p> <p>
The step by step guide is based on two example C++ classes. FooBarAbs is an The step by step guide is based on two example C++ classes. FooBarAbstract is
abstract C++ class and the FooBarCpp class inherits from it. This guide an abstract C++ class and the FooBarCpp class inherits from it. This guide
explains how to implement a FooBarGo class similar to the FooBarCpp class. explains how to implement a FooBarGo class similar to the FooBarCpp class.
</p> </p>
<p> <p>
<tt>FooBarAbs</tt> abstract C++ class: <tt>FooBarAbstract</tt> abstract C++ class:
</p> </p>
<div class="code"> <div class="code">
<pre> <pre>
class FooBarAbs class FooBarAbstract
{ {
public: public:
FooBarAbs() {}; FooBarAbstract() {};
virtual ~FooBarAbs() {}; virtual ~FooBarAbstract() {};
std::string FooBar() { std::string FooBar() {
return this->Foo() + ", " + this->Bar(); return this->Foo() + ", " + this->Bar();
@ -643,11 +643,11 @@ protected:
<div class="code"> <div class="code">
<pre> <pre>
class FooBarCpp : public FooBarAbs class FooBarCpp : public FooBarAbstract
{ {
protected: protected:
virtual std::string Foo() { virtual std::string Foo() {
return "C++ " + FooBarAbs::Foo(); return "C++ " + FooBarAbstract::Foo();
} }
virtual std::string Bar() { virtual std::string Bar() {
@ -691,14 +691,14 @@ directive, like this:
<p> <p>
Second, you must use the %feature("director") directive to tell SWIG which Second, you must use the %feature("director") directive to tell SWIG which
classes should get directors. In the example the FooBarAbs class needs the classes should get directors. In the example the FooBarAbstract class needs the
director feature enabled so that the FooBarGo class can inherit from it, like director feature enabled so that the FooBarGo class can inherit from it, like
this: this:
</p> </p>
<div class="code"> <div class="code">
<pre> <pre>
%feature("director") FooBarAbs; %feature("director") FooBarAbstract;
</pre> </pre>
</div> </div>
@ -782,21 +782,21 @@ As an example see part of the <tt>FooBarGo</tt> class:
<div class="code"> <div class="code">
<pre> <pre>
type overwrittenMethodsOnFooBarAbs struct { type overwrittenMethodsOnFooBarAbstract struct {
fb FooBarAbs fb FooBarAbstract
} }
func (om *overwrittenMethodsOnFooBarAbs) Foo() string { func (om *overwrittenMethodsOnFooBarAbstract) Foo() string {
... ...
} }
func (om *overwrittenMethodsOnFooBarAbs) Bar() string { func (om *overwrittenMethodsOnFooBarAbstract) Bar() string {
... ...
} }
func NewFooBarGo() FooBarGo { func NewFooBarGo() FooBarGo {
om := &amp;overwrittenMethodsOnFooBarAbs{} om := &amp;overwrittenMethodsOnFooBarAbstract{}
fb := NewDirectorFooBarAbs(om) fb := NewDirectorFooBarAbstract(om)
om.fb = fb om.fb = fb
... ...
} }
@ -806,25 +806,25 @@ func NewFooBarGo() FooBarGo {
<p> <p>
The complete example, including the <tt>FooBarGoo</tt> class implementation, can The complete example, including the <tt>FooBarGoo</tt> class implementation, can
be found in <a href="#Go_director_foobargo_class">the end of the guide</a>. In be found in <a href="#Go_director_foobargo_class">the end of the guide</a>. In
this part of the example the virtual methods <tt>FooBarAbs::Foo</tt> and this part of the example the virtual methods <tt>FooBarAbstract::Foo</tt> and
<tt>FooBarAbs::Bar</tt> have been overwritten with Go methods similarly to how <tt>FooBarAbstract::Bar</tt> have been overwritten with Go methods similarly to
the <tt>FooBarAbs</tt> virtual methods are overwritten by the <tt>FooBarCpp</tt> how the <tt>FooBarAbstract</tt> virtual methods are overwritten by the
class. <tt>FooBarCpp</tt> class.
</p> </p>
<p> <p>
The <tt>DirectorInterface</tt> in the example is implemented by the The <tt>DirectorInterface</tt> in the example is implemented by the
<tt>overwrittenMethodsOnFooBarAbs</tt> Go struct type. A pointer to a <tt>overwrittenMethodsOnFooBarAbstract</tt> Go struct type. A pointer to a
<tt>overwrittenMethodsOnFooBarAbs</tt> struct instance will be given to the <tt>overwrittenMethodsOnFooBarAbstract</tt> struct instance will be given to the
<tt>NewDirectorFooBarAbs</tt> constructor function. The constructor return <tt>NewDirectorFooBarAbstract</tt> constructor function. The constructor return
value implements the <tt>FooBarAbs</tt> interface. value implements the <tt>FooBarAbstract</tt> interface.
<tt>overwrittenMethodsOnFooBarAbs</tt> could in theory be any Go type but in <tt>overwrittenMethodsOnFooBarAbstract</tt> could in theory be any Go type but
practice a struct is used as it typically contains at least a value of the in practice a struct is used as it typically contains at least a value of the
C++ class interface so that the overwritten methods can use the rest of the C++ class interface so that the overwritten methods can use the rest of the
C++ class. If the <tt>FooBarGo</tt> class would receive additional constructor C++ class. If the <tt>FooBarGo</tt> class would receive additional constructor
arguments then these would also typically be stored in the arguments then these would also typically be stored in the
<tt>overwrittenMethodsOnFooBarAbs</tt> struct so that they can be used by the <tt>overwrittenMethodsOnFooBarAbstract</tt> struct so that they can be used by
Go methods. the Go methods.
</p> </p>
@ -840,7 +840,7 @@ the method in the base class. This is also the case for the
<div class="code"> <div class="code">
<pre> <pre>
virtual std::string Foo() { virtual std::string Foo() {
return "C++ " + FooBarAbs::Foo(); return "C++ " + FooBarAbstract::Foo();
} }
</pre> </pre>
</div> </div>
@ -853,8 +853,8 @@ The <tt>FooBarGo.Foo</tt> implementation in the example looks like this:
<div class="code"> <div class="code">
<pre> <pre>
func (om *overwrittenMethodsOnFooBarAbs) Foo() string { func (om *overwrittenMethodsOnFooBarAbstract) Foo() string {
return "Go " + DirectorFooBarAbsFoo(om.fb) return "Go " + DirectorFooBarAbstractFoo(om.fb)
} }
</pre> </pre>
</div> </div>
@ -887,31 +887,31 @@ this:
<div class="code"> <div class="code">
<pre> <pre>
type FooBarGo interface { type FooBarGo interface {
FooBarAbs FooBarAbstract
deleteFooBarAbs() deleteFooBarAbstract()
IsFooBarGo() IsFooBarGo()
} }
type fooBarGo struct { type fooBarGo struct {
FooBarAbs FooBarAbstract
} }
func (fbgs *fooBarGo) deleteFooBarAbs() { func (fbgs *fooBarGo) deleteFooBarAbstract() {
DeleteDirectorFooBarAbs(fbgs.FooBarAbs) DeleteDirectorFooBarAbstract(fbgs.FooBarAbstract)
} }
func (fbgs *fooBarGo) IsFooBarGo() {} func (fbgs *fooBarGo) IsFooBarGo() {}
func NewFooBarGo() FooBarGo { func NewFooBarGo() FooBarGo {
om := &amp;overwrittenMethodsOnFooBarAbs{} om := &amp;overwrittenMethodsOnFooBarAbstract{}
fb := NewDirectorFooBarAbs(om) fb := NewDirectorFooBarAbstract(om)
om.fb = fb om.fb = fb
return &amp;fooBarGo{FooBarAbs: fb} return &amp;fooBarGo{FooBarAbstract: fb}
} }
func DeleteFooBarGo(fbg FooBarGo) { func DeleteFooBarGo(fbg FooBarGo) {
fbg.deleteFooBarAbs() fbg.deleteFooBarAbstract()
} }
</pre> </pre>
</div> </div>
@ -921,12 +921,12 @@ func DeleteFooBarGo(fbg FooBarGo) {
The complete example, including the <tt>FooBarGoo</tt> class implementation, can The complete example, including the <tt>FooBarGoo</tt> class implementation, can
be found in <a href="#Go_director_foobargo_class">the end of the guide</a>. In be found in <a href="#Go_director_foobargo_class">the end of the guide</a>. In
this part of the example the private <tt>fooBarGo</tt> struct embeds <tt> this part of the example the private <tt>fooBarGo</tt> struct embeds <tt>
FooBarAbs</tt> which lets the <tt>fooBarGo</tt> Go type "inherit" all the FooBarAbstract</tt> which lets the <tt>fooBarGo</tt> Go type "inherit" all the
methods of the <tt>FooBarAbs</tt> C++ class by means of embedding. The public methods of the <tt>FooBarAbstract</tt> C++ class by means of embedding. The
<tt>FooBarGo</tt> interface type includes the <tt>FooBarAbs</tt> interface and public <tt>FooBarGo</tt> interface type includes the <tt>FooBarAbstract</tt>
hence <tt>FooBarGo</tt> can be used as a drop in replacement for interface and hence <tt>FooBarGo</tt> can be used as a drop in replacement for
<tt>FooBarAbs</tt> while the reverse isn't possible and would raise a compile <tt>FooBarAbstract</tt> while the reverse isn't possible and would raise a
time error. Furthemore the constructor and destructor functions <tt> compile time error. Furthemore the constructor and destructor functions <tt>
NewFooBarGo</tt> and <tt>DeleteFooBarGo</tt> take care of all the director NewFooBarGo</tt> and <tt>DeleteFooBarGo</tt> take care of all the director
specifics and to the user the class appears as any other SWIG wrapped C++ specifics and to the user the class appears as any other SWIG wrapped C++
class. class.
@ -946,13 +946,13 @@ in the <tt>FooBarGo</tt> class is here:
<div class="code"> <div class="code">
<pre> <pre>
type overwrittenMethodsOnFooBarAbs struct { type overwrittenMethodsOnFooBarAbstract struct {
fb FooBarAbs fb FooBarAbstract
} }
func NewFooBarGo() FooBarGo { func NewFooBarGo() FooBarGo {
om := &amp;overwrittenMethodsOnFooBarAbs{} om := &amp;overwrittenMethodsOnFooBarAbstract{}
fb := NewDirectorFooBarAbs(om) // fb.v = om fb := NewDirectorFooBarAbstract(om) // fb.v = om
om.fb = fb // Backlink causes cycle as fb.v = om! om.fb = fb // Backlink causes cycle as fb.v = om!
... ...
} }
@ -963,27 +963,27 @@ func NewFooBarGo() FooBarGo {
In order to be able to use <tt>runtime.SetFinalizer</tt> nevertheless the In order to be able to use <tt>runtime.SetFinalizer</tt> nevertheless the
finalizer needs to be set on something that isn't in a cycle and that references finalizer needs to be set on something that isn't in a cycle and that references
the director object instance. In the <tt>FooBarGo</tt> class example the <tt> the director object instance. In the <tt>FooBarGo</tt> class example the <tt>
FooBarAbs</tt> director instance can be automatically deleted by setting the FooBarAbstract</tt> director instance can be automatically deleted by setting
finalizer on <tt>fooBarGo</tt>: the finalizer on <tt>fooBarGo</tt>:
</p> </p>
<div class="code"> <div class="code">
<pre> <pre>
type fooBarGo struct { type fooBarGo struct {
FooBarAbs FooBarAbstract
} }
type overwrittenMethodsOnFooBarAbs struct { type overwrittenMethodsOnFooBarAbstract struct {
fb FooBarAbs fb FooBarAbstract
} }
func NewFooBarGo() FooBarGo { func NewFooBarGo() FooBarGo {
om := &amp;overwrittenMethodsOnFooBarAbs{} om := &amp;overwrittenMethodsOnFooBarAbstract{}
fb := NewDirectorFooBarAbs(om) fb := NewDirectorFooBarAbstract(om)
om.fb = fb // Backlink causes cycle as fb.v = om! om.fb = fb // Backlink causes cycle as fb.v = om!
fbgs := &amp;fooBarGo{FooBarAbs: fb} fbgs := &amp;fooBarGo{FooBarAbstract: fb}
runtime.SetFinalizer(fbgs, FooBarGo.deleteFooBarAbs) runtime.SetFinalizer(fbgs, FooBarGo.deleteFooBarAbstract)
return fbgs return fbgs
} }
</pre> </pre>
@ -1007,73 +1007,75 @@ The complete and annotated <tt>FooBarGo</tt> class looks like this:
<div class="code"> <div class="code">
<pre> <pre>
// FooBarGo is a superset of FooBarAbs and hence FooBarGo can be used as a drop // FooBarGo is a superset of FooBarAbstract and hence FooBarGo can be used as a
// in replacement for FooBarAbs but the reverse causes a compile time error. // drop in replacement for FooBarAbstract but the reverse causes a compile time
// error.
type FooBarGo interface { type FooBarGo interface {
FooBarAbs FooBarAbstract
deleteFooBarAbs() deleteFooBarAbstract()
IsFooBarGo() IsFooBarGo()
} }
// Via embedding fooBarGo "inherits" all methods of FooBarAbs. // Via embedding fooBarGo "inherits" all methods of FooBarAbstract.
type fooBarGo struct { type fooBarGo struct {
FooBarAbs FooBarAbstract
} }
func (fbgs *fooBarGo) deleteFooBarAbs() { func (fbgs *fooBarGo) deleteFooBarAbstract() {
DeleteDirectorFooBarAbs(fbgs.FooBarAbs) DeleteDirectorFooBarAbstract(fbgs.FooBarAbstract)
} }
// The IsFooBarGo method ensures that FooBarGo is a superset of FooBarAbs. // The IsFooBarGo method ensures that FooBarGo is a superset of FooBarAbstract.
// This is also how the class hierarchy gets represented by the SWIG generated // This is also how the class hierarchy gets represented by the SWIG generated
// wrapper code. For an instance FooBarCpp has the IsFooBarAbs and IsFooBarCpp // wrapper code. For an instance FooBarCpp has the IsFooBarAbstract and
// methods. // IsFooBarCpp methods.
func (fbgs *fooBarGo) IsFooBarGo() {} func (fbgs *fooBarGo) IsFooBarGo() {}
// Go type that defines the DirectorInterface. It contains the Foo and Bar // Go type that defines the DirectorInterface. It contains the Foo and Bar
// methods that overwrite the respective virtual C++ methods on FooBarAbs. // methods that overwrite the respective virtual C++ methods on FooBarAbstract.
type overwrittenMethodsOnFooBarAbs struct { type overwrittenMethodsOnFooBarAbstract struct {
// Backlink to FooBarAbs so that the rest of the class can be used by the // Backlink to FooBarAbstract so that the rest of the class can be used by
// overridden methods. // the overridden methods.
fb FooBarAbs fb FooBarAbstract
// If additional constructor arguments have been given they are typically // If additional constructor arguments have been given they are typically
// stored here so that the overriden methods can use them. // stored here so that the overriden methods can use them.
} }
func (om *overwrittenMethodsOnFooBarAbs) Foo() string { func (om *overwrittenMethodsOnFooBarAbstract) Foo() string {
// DirectorFooBarAbsFoo calls the base method FooBarAbs::Foo. // DirectorFooBarAbstractFoo calls the base method FooBarAbstract::Foo.
return "Go " + DirectorFooBarAbsFoo(om.fb) return "Go " + DirectorFooBarAbstractFoo(om.fb)
} }
func (om *overwrittenMethodsOnFooBarAbs) Bar() string { func (om *overwrittenMethodsOnFooBarAbstract) Bar() string {
return "Go Bar" return "Go Bar"
} }
func NewFooBarGo() FooBarGo { func NewFooBarGo() FooBarGo {
// Instantiate FooBarAbs with selected methods overridden. The methods that // Instantiate FooBarAbstract with selected methods overridden. The methods
// will be overwritten are defined on overwrittenMethodsOnFooBarAbs and have // that will be overwritten are defined on
// a compatible signature to the respective virtual C++ methods. // overwrittenMethodsOnFooBarAbstract and have a compatible signature to the
// Furthermore additional constructor arguments will be typically stored in // respective virtual C++ methods. Furthermore additional constructor
// the overwrittenMethodsOnFooBarAbs struct. // arguments will be typically stored in the
om := &amp;overwrittenMethodsOnFooBarAbs{} // overwrittenMethodsOnFooBarAbstract struct.
fb := NewDirectorFooBarAbs(om) om := &amp;overwrittenMethodsOnFooBarAbstract{}
fb := NewDirectorFooBarAbstract(om)
om.fb = fb // Backlink causes cycle as fb.v = om! om.fb = fb // Backlink causes cycle as fb.v = om!
fbgs := &amp;fooBarGo{FooBarAbs: fb} fbgs := &amp;fooBarGo{FooBarAbstract: fb}
// The memory of the FooBarAbs director object instance can be automatically // The memory of the FooBarAbstract director object instance can be
// freed once the FooBarGo instance is garbage collected by uncommenting the // automatically freed once the FooBarGo instance is garbage collected by
// following line. Please make sure to understand the runtime.SetFinalizer // uncommenting the following line. Please make sure to understand the
// specific gotchas before doing this. Furthemore DeleteFooBarGo should be // runtime.SetFinalizer specific gotchas before doing this. Furthemore
// deleted if a finalizer is in use or the fooBarGo struct needs additional // DeleteFooBarGo should be deleted if a finalizer is in use or the fooBarGo
// data to prevent double deletion. // struct needs additional data to prevent double deletion.
// runtime.SetFinalizer(fbgs, FooBarGo.deleteFooBarAbs) // runtime.SetFinalizer(fbgs, FooBarGo.deleteFooBarAbstract)
return fbgs return fbgs
} }
// Recommended to be removed if runtime.SetFinalizer is in use. // Recommended to be removed if runtime.SetFinalizer is in use.
func DeleteFooBarGo(fbg FooBarGo) { func DeleteFooBarGo(fbg FooBarGo) {
fbg.deleteFooBarAbs() fbg.deleteFooBarAbstract()
} }
</pre> </pre>
</div> </div>
@ -1094,11 +1096,11 @@ For comparison the <tt>FooBarCpp</tt> class looks like this:
<div class="code"> <div class="code">
<pre> <pre>
class FooBarCpp : public FooBarAbs class FooBarCpp : public FooBarAbstract
{ {
protected: protected:
virtual std::string Foo() { virtual std::string Foo() {
return "C++ " + FooBarAbs::Foo(); return "C++ " + FooBarAbstract::Foo();
} }
virtual std::string Bar() { virtual std::string Bar() {

View file

@ -0,0 +1,24 @@
TOP = ../..
SWIG = $(TOP)/../preinst-swig
CXXSRCS = callback.cxx
GOSRCS = gocallback.go
TARGET = example
INTERFACE = example.i
SWIGOPT =
check: build
$(MAKE) -f $(TOP)/Makefile SRCDIR='$(SRCDIR)' CXXSRCS='$(CXXSRCS)' TARGET='$(TARGET)' INTERFACE='$(INTERFACE)' go_run
build:
if [ -n '$(SRCDIR)' ]; then \
cp $(GOSRCS:%=$(SRCDIR)/%) .; \
fi
@# Note: example.go gets generated by SWIG
$(MAKE) -f $(TOP)/Makefile SRCDIR='$(SRCDIR)' CXXSRCS='$(CXXSRCS)' GOSRCS='example.go $(GOSRCS)' \
SWIG='$(SWIG)' SWIGOPT='$(SWIGOPT)' TARGET='$(TARGET)' INTERFACE='$(INTERFACE)' go_cpp
clean:
if [ -n '$(SRCDIR)' ]; then \
rm $(GOSRCS) || true; \
fi
$(MAKE) -f $(TOP)/Makefile SRCDIR='$(SRCDIR)' INTERFACE='$(INTERFACE)' go_clean

View file

@ -0,0 +1,4 @@
/* File : example.cxx */
#include "example.h"

View file

@ -0,0 +1,22 @@
/* File : example.h */
#include <cstdio>
#include <iostream>
class Callback {
public:
virtual ~Callback() { std::cout << "Callback::~Callback()" << std:: endl; }
virtual void run() { std::cout << "Callback::run()" << 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() { if (_callback) _callback->run(); }
};

View file

@ -0,0 +1,11 @@
/* File : example.i */
%module(directors="1") example
%{
#include "example.h"
%}
/* turn on director wrapping Callback */
%feature("director") Callback;
%include "example.h"

View file

@ -0,0 +1,41 @@
package example
import (
"fmt"
)
type GoCallback interface {
Callback
deleteCallback()
IsGoCallback()
}
type goCallback struct {
Callback
}
func (p *goCallback) deleteCallback() {
DeleteDirectorCallback(p.Callback)
}
func (p *goCallback) IsGoCallback() {}
type overwrittenMethodsOnCallback struct {
p Callback
}
func NewGoCallback() GoCallback {
om := &overwrittenMethodsOnCallback{}
p := NewDirectorCallback(om)
om.p = p
return &goCallback{Callback: p}
}
func DeleteGoCallback(p GoCallback) {
p.deleteCallback()
}
func (p *goCallback) Run() {
fmt.Println("GoCallback.Run")
}

View file

@ -0,0 +1,31 @@
<html>
<head>
<title>SWIG:Examples:go:callback</title>
</head>
<body bgcolor="#ffffff">
<tt>SWIG/Examples/go/callback/</tt>
<hr>
<H2>Implementing C++ callbacks in Go</H2>
<p>
This example illustrates how to use directors to implement C++ callbacks in Go.
See the <a href="../../../Doc/Manual/Go.html#Go_director_classes">Go Director
Classes</a> documentation subsection for an in-depth explanation how to use the
director feature.
</p>
<p>
<ul>
<li><a href="example.h">example.h</a>. Header with the definition of the Caller and Callback classes.
<li><a href="example.i">example.i</a>. SWIG interface file.
<li><a href="gocallback.go">gocallback.go</a>. Go source with the definition of the GoCallback class.
<li><a href="runme.go">runme.go</a>. Sample Go program.
</ul>
<hr>
</body>
</html>

View file

@ -0,0 +1,33 @@
package main
import (
. "./example"
"fmt"
)
func main() {
fmt.Println("Adding and calling a normal C++ callback")
fmt.Println("----------------------------------------")
caller := NewCaller()
callback := NewCallback()
caller.SetCallback(callback)
caller.Call()
caller.DelCallback()
go_callback := NewGoCallback()
fmt.Println()
fmt.Println("Adding and calling a Go callback")
fmt.Println("--------------------------------")
caller.SetCallback(go_callback)
caller.Call()
caller.DelCallback()
DeleteGoCallback(go_callback)
fmt.Println()
fmt.Println("Go exit")
}

View file

@ -1,8 +1,10 @@
# see top-level Makefile.in # see top-level Makefile.in
callback
class class
constants constants
director director
enum enum
extend
funcptr funcptr
multimap multimap
pointer pointer

View file

@ -1,7 +1,7 @@
TOP = ../.. TOP = ../..
SWIG = $(TOP)/../preinst-swig SWIG = $(TOP)/../preinst-swig
CXXSRCS = CXXSRCS =
GOSRCS = example.go director.go # example.go gets generated by SWIG GOSRCS = director.go
TARGET = example TARGET = example
INTERFACE = example.i INTERFACE = example.i
SWIGOPT = SWIGOPT =
@ -11,13 +11,14 @@ check: build
build: build:
if [ -n '$(SRCDIR)' ]; then \ if [ -n '$(SRCDIR)' ]; then \
cp $(SRCDIR)/director.go .; \ cp $(GOSRCS:%=$(SRCDIR)/%) .; \
fi fi
$(MAKE) -f $(TOP)/Makefile SRCDIR='$(SRCDIR)' CXXSRCS='$(CXXSRCS)' GOSRCS='$(GOSRCS)' \ @# Note: example.go gets generated by SWIG
$(MAKE) -f $(TOP)/Makefile SRCDIR='$(SRCDIR)' CXXSRCS='$(CXXSRCS)' GOSRCS='example.go $(GOSRCS)' \
SWIG='$(SWIG)' SWIGOPT='$(SWIGOPT)' TARGET='$(TARGET)' INTERFACE='$(INTERFACE)' go_cpp SWIG='$(SWIG)' SWIGOPT='$(SWIGOPT)' TARGET='$(TARGET)' INTERFACE='$(INTERFACE)' go_cpp
clean: clean:
if [ -n '$(SRCDIR)' ]; then \ if [ -n '$(SRCDIR)' ]; then \
rm director.go || true; \ rm $(GOSRCS) || true; \
fi fi
$(MAKE) -f $(TOP)/Makefile SRCDIR='$(SRCDIR)' INTERFACE='$(INTERFACE)' go_clean $(MAKE) -f $(TOP)/Makefile SRCDIR='$(SRCDIR)' INTERFACE='$(INTERFACE)' go_clean

View file

@ -1,70 +1,72 @@
package example package example
// FooBarGo is a superset of FooBarAbs and hence FooBarGo can be used as a drop // FooBarGo is a superset of FooBarAbstract and hence FooBarGo can be used as a
// in replacement for FooBarAbs but the reverse causes a compile time error. // drop in replacement for FooBarAbstract but the reverse causes a compile time
// error.
type FooBarGo interface { type FooBarGo interface {
FooBarAbs FooBarAbstract
deleteFooBarAbs() deleteFooBarAbstract()
IsFooBarGo() IsFooBarGo()
} }
// Via embedding fooBarGo "inherits" all methods of FooBarAbs. // Via embedding fooBarGo "inherits" all methods of FooBarAbstract.
type fooBarGo struct { type fooBarGo struct {
FooBarAbs FooBarAbstract
} }
func (fbgs *fooBarGo) deleteFooBarAbs() { func (fbgs *fooBarGo) deleteFooBarAbstract() {
DeleteDirectorFooBarAbs(fbgs.FooBarAbs) DeleteDirectorFooBarAbstract(fbgs.FooBarAbstract)
} }
// The IsFooBarGo method ensures that FooBarGo is a superset of FooBarAbs. // The IsFooBarGo method ensures that FooBarGo is a superset of FooBarAbstract.
// This is also how the class hierarchy gets represented by the SWIG generated // This is also how the class hierarchy gets represented by the SWIG generated
// wrapper code. For an instance FooBarCpp has the IsFooBarAbs and IsFooBarCpp // wrapper code. For an instance FooBarCpp has the IsFooBarAbstract and
// methods. // IsFooBarCpp methods.
func (fbgs *fooBarGo) IsFooBarGo() {} func (fbgs *fooBarGo) IsFooBarGo() {}
// Go type that defines the DirectorInterface. It contains the Foo and Bar // Go type that defines the DirectorInterface. It contains the Foo and Bar
// methods that overwrite the respective virtual C++ methods on FooBarAbs. // methods that overwrite the respective virtual C++ methods on FooBarAbstract.
type overwrittenMethodsOnFooBarAbs struct { type overwrittenMethodsOnFooBarAbstract struct {
// Backlink to FooBarAbs so that the rest of the class can be used by the // Backlink to FooBarAbstract so that the rest of the class can be used by
// overridden methods. // the overridden methods.
fb FooBarAbs fb FooBarAbstract
// If additional constructor arguments have been given they are typically // If additional constructor arguments have been given they are typically
// stored here so that the overriden methods can use them. // stored here so that the overriden methods can use them.
} }
func (om *overwrittenMethodsOnFooBarAbs) Foo() string { func (om *overwrittenMethodsOnFooBarAbstract) Foo() string {
// DirectorFooBarAbsFoo calls the base method FooBarAbs::Foo. // DirectorFooBarAbstractFoo calls the base method FooBarAbstract::Foo.
return "Go " + DirectorFooBarAbsFoo(om.fb) return "Go " + DirectorFooBarAbstractFoo(om.fb)
} }
func (om *overwrittenMethodsOnFooBarAbs) Bar() string { func (om *overwrittenMethodsOnFooBarAbstract) Bar() string {
return "Go Bar" return "Go Bar"
} }
func NewFooBarGo() FooBarGo { func NewFooBarGo() FooBarGo {
// Instantiate FooBarAbs with selected methods overridden. The methods that // Instantiate FooBarAbstract with selected methods overridden. The methods
// will be overwritten are defined on overwrittenMethodsOnFooBarAbs and have // that will be overwritten are defined on
// a compatible signature to the respective virtual C++ methods. // overwrittenMethodsOnFooBarAbstract and have a compatible signature to the
// Furthermore additional constructor arguments will be typically stored in // respective virtual C++ methods. Furthermore additional constructor
// the overwrittenMethodsOnFooBarAbs struct. // arguments will be typically stored in the
om := &overwrittenMethodsOnFooBarAbs{} // overwrittenMethodsOnFooBarAbstract struct.
fb := NewDirectorFooBarAbs(om) om := &overwrittenMethodsOnFooBarAbstract{}
fb := NewDirectorFooBarAbstract(om)
om.fb = fb // Backlink causes cycle as fb.v = om! om.fb = fb // Backlink causes cycle as fb.v = om!
fbgs := &fooBarGo{FooBarAbs: fb} fbgs := &fooBarGo{FooBarAbstract: fb}
// The memory of the FooBarAbs director object instance can be automatically // The memory of the FooBarAbstract director object instance can be
// freed once the FooBarGo instance is garbage collected by uncommenting the // automatically freed once the FooBarGo instance is garbage collected by
// following line. Please make sure to understand the runtime.SetFinalizer // uncommenting the following line. Please make sure to understand the
// specific gotchas before doing this. Furthemore DeleteFooBarGo should be // runtime.SetFinalizer specific gotchas before doing this. Furthemore
// deleted if a finalizer is in use or the fooBarGo struct needs additional // DeleteFooBarGo should be deleted if a finalizer is in use or the fooBarGo
// data to prevent double deletion. // struct needs additional data to prevent double deletion.
// runtime.SetFinalizer(fbgs, FooBarGo.deleteFooBarAbs) // runtime.SetFinalizer(fbgs, FooBarGo.deleteFooBarAbstract)
return fbgs return fbgs
} }
// Recommended to be removed if runtime.SetFinalizer is in use. // Recommended to be removed if runtime.SetFinalizer is in use.
func DeleteFooBarGo(fbg FooBarGo) { func DeleteFooBarGo(fbg FooBarGo) {
fbg.deleteFooBarAbs() fbg.deleteFooBarAbstract()
} }

View file

@ -6,11 +6,11 @@
#include <string> #include <string>
class FooBarAbs class FooBarAbstract
{ {
public: public:
FooBarAbs() {}; FooBarAbstract() {};
virtual ~FooBarAbs() {}; virtual ~FooBarAbstract() {};
std::string FooBar() { std::string FooBar() {
return this->Foo() + ", " + this->Bar(); return this->Foo() + ", " + this->Bar();
@ -25,11 +25,11 @@ protected:
}; };
class FooBarCpp : public FooBarAbs class FooBarCpp : public FooBarAbstract
{ {
protected: protected:
virtual std::string Foo() { virtual std::string Foo() {
return "C++ " + FooBarAbs::Foo(); return "C++ " + FooBarAbstract::Foo();
} }
virtual std::string Bar() { virtual std::string Bar() {

View file

@ -7,5 +7,5 @@
#include "director.h" #include "director.h"
%} %}
%feature("director") FooBarAbs; %feature("director") FooBarAbstract;
%include "director.h" %include "director.h"

View file

@ -18,7 +18,7 @@ Classes</a> documentation subsection for an explanation of this example.
<p> <p>
<ul> <ul>
<li><a href="director.go">director.go</a>. Go source with the definition of the FooBarGo class. <li><a href="director.go">director.go</a>. Go source with the definition of the FooBarGo class.
<li><a href="director.h">director.h</a>. Header with the definition of the FooBarAbs and FooBarCpp classes. <li><a href="director.h">director.h</a>. Header with the definition of the FooBarAbstract and FooBarCpp classes.
<li><a href="example.i">example.i</a>. SWIG interface file. <li><a href="example.i">example.i</a>. SWIG interface file.
<li><a href="runme.go">runme.go</a>. Sample Go program. <li><a href="runme.go">runme.go</a>. Sample Go program.
</ul> </ul>

View file

@ -0,0 +1,24 @@
TOP = ../..
SWIG = $(TOP)/../preinst-swig
CXXSRCS = extend.cxx
GOSRCS = ceo.go
TARGET = example
INTERFACE = example.i
SWIGOPT =
check: build
$(MAKE) -f $(TOP)/Makefile SRCDIR='$(SRCDIR)' CXXSRCS='$(CXXSRCS)' TARGET='$(TARGET)' INTERFACE='$(INTERFACE)' go_run
build:
if [ -n '$(SRCDIR)' ]; then \
cp $(GOSRCS:%=$(SRCDIR)/%) .; \
fi
@# Note: example.go gets generated by SWIG
$(MAKE) -f $(TOP)/Makefile SRCDIR='$(SRCDIR)' CXXSRCS='$(CXXSRCS)' GOSRCS='example.go $(GOSRCS)' \
SWIG='$(SWIG)' SWIGOPT='$(SWIGOPT)' TARGET='$(TARGET)' INTERFACE='$(INTERFACE)' go_cpp
clean:
if [ -n '$(SRCDIR)' ]; then \
rm $(GOSRCS) || true; \
fi
$(MAKE) -f $(TOP)/Makefile SRCDIR='$(SRCDIR)' INTERFACE='$(INTERFACE)' go_clean

37
Examples/go/extend/ceo.go Normal file
View file

@ -0,0 +1,37 @@
package example
type CEO interface {
Manager
deleteManager()
IsCEO()
}
type ceo struct {
Manager
}
func (p *ceo) deleteManager() {
DeleteDirectorManager(p.Manager)
}
func (p *ceo) IsCEO() {}
type overwrittenMethodsOnManager struct {
p Manager
}
func NewCEO(name string) CEO {
om := &overwrittenMethodsOnManager{}
p := NewDirectorManager(om, name)
om.p = p
return &ceo{Manager: p}
}
func DeleteCEO(p CEO) {
p.deleteManager()
}
func (p *ceo) GetPosition() string {
return "CEO"
}

View file

@ -0,0 +1,56 @@
/* File : example.h */
#include <cstdio>
#include <iostream>
#include <vector>
#include <string>
#include <cmath>
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", (void *)this); }
};
class Manager: public Employee {
public:
Manager(const char* n): Employee(n) {}
virtual std::string getPosition() const { return "Manager"; }
};
class EmployeeList {
std::vector<Employee*> 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<Employee*>::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<Employee*>::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;
}
};

View file

@ -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"

View file

@ -0,0 +1,4 @@
/* File : example.cxx */
#include "example.h"

View file

@ -0,0 +1,30 @@
<html>
<head>
<title>SWIG:Examples:go:extend</title>
</head>
<body bgcolor="#ffffff">
<tt>SWIG/Examples/go/extend/</tt>
<hr>
<H2>Extending a simple C++ class in Go</H2>
<p>
This example illustrates how to inherit from a C++ class in Go.
See the <a href="../../../Doc/Manual/Go.html#Go_director_classes">Go Director
Classes</a> documentation subsection for an in-depth explanation how to use the
director feature.
<p>
<ul>
<li><a href="ceo.go">ceo.go</a>. Go source with the definition of the CEO class.
<li><a href="example.h">example.h</a>. Header with the definition of the Employee, Manager and EmployeeList classes.
<li><a href="example.i">example.i</a>. SWIG interface file.
<li><a href="runme.go">runme.go</a>. Sample Go program.
</ul>
<hr>
</body>
</html>

View file

@ -0,0 +1,66 @@
// This file illustrates the cross language polymorphism using directors.
package main
import (
. "./example"
"fmt"
)
func main() {
// Create an instance of CEO, a class derived from the Go
// proxy of the underlying C++ class. The calls to getName()
// and getPosition() are standard, the call to getTitle() uses
// the director wrappers to call CEO.getPosition().
e := NewCEO("Alice")
fmt.Println(e.GetName(), " is a ", e.GetPosition())
fmt.Println("Just call her \"", e.GetTitle(), "\"")
fmt.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.
list := NewEmployeeList()
// EmployeeList owns its items, so we must surrender ownership
// of objects we add.
// e.DisownMemory()
list.AddEmployee(e)
fmt.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, all methods
// resolve in C++. For item 3, our CEO, GetTitle calls
// GetPosition which resolves in Go. The call to GetPosition
// is slightly different, however, because of the overridden
// GetPosition() call, since now the object reference has been
// "laundered" by passing through EmployeeList as an
// Employee*. Previously, Go resolved the call immediately in
// CEO, but now Go thinks the object is an instance of class
// Employee. So the call passes through the Employee proxy
// class and on to the C wrappers and C++ director, eventually
// ending up back at the Go 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 Go implementation
// in CEO. All this routing takes place transparently.
fmt.Println("(position, title) for items 0-3:")
fmt.Println(" ", list.Get_item(0).GetPosition(), ", \"", list.Get_item(0).GetTitle(), "\"")
fmt.Println(" ", list.Get_item(1).GetPosition(), ", \"", list.Get_item(1).GetTitle(), "\"")
fmt.Println(" ", list.Get_item(2).GetPosition(), ", \"", list.Get_item(2).GetTitle(), "\"")
fmt.Println(" ", list.Get_item(3).GetPosition(), ", \"", list.Get_item(3).GetTitle(), "\"")
fmt.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 well and hence there is no need to
// call DeleteCEO.
DeleteEmployeeList(list)
fmt.Println("----------------------")
// All done.
fmt.Println("Go exit")
}

View file

@ -21,6 +21,8 @@ certain C declarations are turned into constants.
<li><a href="pointer/index.html">pointer</a>. Simple pointer handling. <li><a href="pointer/index.html">pointer</a>. Simple pointer handling.
<li><a href="funcptr/index.html">funcptr</a>. Pointers to functions. <li><a href="funcptr/index.html">funcptr</a>. Pointers to functions.
<li><a href="template/index.html">template</a>. C++ templates. <li><a href="template/index.html">template</a>. C++ templates.
<li><a href="callback/index.html">callback</a>. C++ callbacks using directors.
<li><a href="extend/index.html">extend</a>. Polymorphism using directors.
<li><a href="director/index.html">director</a>. Example how to utilize the director feature. <li><a href="director/index.html">director</a>. Example how to utilize the director feature.
</ul> </ul>