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

View file

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

View file

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

View file

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

View file

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

View file

@ -18,7 +18,7 @@ Classes</a> documentation subsection for an explanation of this example.
<p>
<ul>
<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="runme.go">runme.go</a>. Sample Go program.
</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="funcptr/index.html">funcptr</a>. Pointers to functions.
<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.
</ul>