Merge pull request #447 from michael-schaller/doc
Fleshed out Go's documentation about the director feature and added a director example.
This commit is contained in:
commit
17b1c1c2d3
8 changed files with 746 additions and 25 deletions
|
|
@ -29,6 +29,16 @@
|
||||||
</ul>
|
</ul>
|
||||||
<li><a href="#Go_templates">Go Templates</a>
|
<li><a href="#Go_templates">Go Templates</a>
|
||||||
<li><a href="#Go_director_classes">Go Director Classes</a>
|
<li><a href="#Go_director_classes">Go Director Classes</a>
|
||||||
|
<ul>
|
||||||
|
<li><a href="#Go_director_example_cpp_code">Example C++ code</a>
|
||||||
|
<li><a href="#Go_director_enable">Enable director feature</a>
|
||||||
|
<li><a href="#Go_director_ctor_dtor">Constructor and destructor</a>
|
||||||
|
<li><a href="#Go_director_overriding">Override virtual methods</a>
|
||||||
|
<li><a href="#Go_director_base_methods">Call base methods</a>
|
||||||
|
<li><a href="#Go_director_subclass">Subclass via embedding</a>
|
||||||
|
<li><a href="#Go_director_finalizer">Memory management with runtime.SetFinalizer</a>
|
||||||
|
<li><a href="#Go_director_foobargo_class">Complete FooBarGo example class</a>
|
||||||
|
</ul>
|
||||||
<li><a href="#Go_primitive_type_mappings">Default Go primitive type mappings</a>
|
<li><a href="#Go_primitive_type_mappings">Default Go primitive type mappings</a>
|
||||||
<li><a href="#Go_output_arguments">Output arguments</a>
|
<li><a href="#Go_output_arguments">Output arguments</a>
|
||||||
<li><a href="#Go_adding_additional_code">Adding additional go code</a>
|
<li><a href="#Go_adding_additional_code">Adding additional go code</a>
|
||||||
|
|
@ -574,49 +584,547 @@ In order to use C++ templates in Go, you must tell SWIG to create
|
||||||
wrappers for a particular template instantation. To do this, use
|
wrappers for a particular template instantation. To do this, use
|
||||||
the <tt>%template</tt> directive.
|
the <tt>%template</tt> directive.
|
||||||
|
|
||||||
|
|
||||||
<H3><a name="Go_director_classes"></a>23.4.7 Go Director Classes</H3>
|
<H3><a name="Go_director_classes"></a>23.4.7 Go Director Classes</H3>
|
||||||
|
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
SWIG's director feature permits a Go type to act as the subclass of a
|
SWIG's director feature permits a Go type to act as the subclass of a C++ class.
|
||||||
C++ class with virtual methods. This is complicated by the fact that
|
This is complicated by the fact that C++ and Go define inheritance differently.
|
||||||
C++ and Go define inheritance differently. In Go, structs can inherit
|
SWIG normally represents the C++ class inheritance automatically in Go via
|
||||||
methods via anonymous field embedding. However, when a method is
|
interfaces but with a Go type representing a subclass of a C++ class some manual
|
||||||
called for an embedded struct, if that method calls any other methods,
|
work is necessary.
|
||||||
they are called for the embedded struct, not for the original type.
|
<p>
|
||||||
Therefore, SWIG must use Go interfaces to represent C++ inheritance.
|
|
||||||
|
<p>
|
||||||
|
This subchapter gives a step by step guide how to properly sublass a C++ class
|
||||||
|
with a Go type. In general it is strongly recommended to follow this guide
|
||||||
|
completely to avoid common pitfalls with directors in Go.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
|
||||||
|
<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
|
||||||
|
explains how to implement a FooBarGo class similar to the FooBarCpp class.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
In order to use the director feature in Go, you must define a type in
|
<tt>FooBarAbs</tt> abstract C++ class:
|
||||||
your Go code. You must then add methods for the type. Define a
|
|
||||||
method in Go for each C++ virtual function that you want to override.
|
|
||||||
You must then create a value of your new type, and pass a pointer to
|
|
||||||
it to the function <tt>NewDirectorClassName</tt>,
|
|
||||||
where <tt>ClassName</tt> is the name of the C++ class. That will
|
|
||||||
return a value of type <tt>ClassName</tt>.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
For example:
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div class="code">
|
<div class="code">
|
||||||
<pre>
|
<pre>
|
||||||
type GoClass struct { }
|
class FooBarAbs
|
||||||
func (p *GoClass) VirtualFunction() { }
|
{
|
||||||
func MakeClass() ClassName {
|
public:
|
||||||
return NewDirectorClassName(&GoClass{})
|
FooBarAbs() {};
|
||||||
|
virtual ~FooBarAbs() {};
|
||||||
|
|
||||||
|
std::string FooBar() {
|
||||||
|
return this->Foo() + ", " + this->Bar();
|
||||||
|
};
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual std::string Foo() {
|
||||||
|
return "Foo";
|
||||||
|
};
|
||||||
|
|
||||||
|
virtual std::string Bar() = 0;
|
||||||
|
};
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<tt>FooBarCpp</tt> C++ class:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="code">
|
||||||
|
<pre>
|
||||||
|
class FooBarCpp : public FooBarAbs
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
virtual std::string Foo() {
|
||||||
|
return "C++ " + FooBarAbs::Foo();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual std::string Bar() {
|
||||||
|
return "C++ Bar";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Returned string by the <tt>FooBarCpp::FooBar</tt> method is:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="code">
|
||||||
|
<pre>
|
||||||
|
C++ Foo, C++ Bar
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<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>.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
|
||||||
|
<H4><a name="Go_director_enable"></a>23.4.7.2 Enable director feature</H4>
|
||||||
|
|
||||||
|
|
||||||
|
<p>
|
||||||
|
The director feature is disabled by default. To use directors you must make two
|
||||||
|
changes to the interface file. First, add the "directors" option to the %module
|
||||||
|
directive, like this:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="code">
|
||||||
|
<pre>
|
||||||
|
%module(directors="1") modulename
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<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
|
||||||
|
director feature enabled so that the FooBarGo class can inherit from it, like
|
||||||
|
this:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="code">
|
||||||
|
<pre>
|
||||||
|
%feature("director") FooBarAbs;
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
For a more detailed documentation of the director feature and how to enable or
|
||||||
|
disable it for specific classes and virtual methods see SWIG's Java
|
||||||
|
documentation on directors.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
|
||||||
|
<H4><a name="Go_director_ctor_dtor"></a>23.4.7.3 Constructor and destructor</H4>
|
||||||
|
|
||||||
|
|
||||||
|
<p>
|
||||||
|
SWIG creates an additional set of constructor and destructor functions once the
|
||||||
|
director feature has been enabled for a C++ class.
|
||||||
|
<tt>NewDirectorClassName</tt> allows overriding virtual methods on the new
|
||||||
|
object instance and <tt>DeleteDirectorClassName</tt> needs to be used to free a
|
||||||
|
director object instance created with <tt>NewDirectorClassName</tt>.
|
||||||
|
More on overriding virtual methods follows later in this guide under
|
||||||
|
<a href="#Go_director_overriding">overriding virtual methods</a>.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
The default constructor and destructor functions <tt>NewClassName</tt> and
|
||||||
|
<tt>DeleteClassName</tt> can still be used as before so that existing code
|
||||||
|
doesn't break just because the director feature has been enabled for a C++
|
||||||
|
class. The behavior is undefined if the default and director constructor and
|
||||||
|
destructor functions get mixed and so great care needs to be taken that only one
|
||||||
|
of the constructor and destructor function pairs is used for any object
|
||||||
|
instance. Both constructor functions, the default and the director one, return
|
||||||
|
the same interface type. This makes it potentially hard to know which
|
||||||
|
destructor function, the default or the director one, needs to be called to
|
||||||
|
delete an object instance.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
In <b>theory</b> the <tt>DirectorInterface</tt> method could be used to
|
||||||
|
determine if an object instance was created via <tt>NewDirectorClassName</tt>:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="code">
|
||||||
|
<pre>
|
||||||
|
if o.DirectorInterface() != nil {
|
||||||
|
DeleteDirectorClassName(o)
|
||||||
|
} else {
|
||||||
|
DeleteClassName(o)
|
||||||
}
|
}
|
||||||
</pre>
|
</pre>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Any call in C++ code to the virtual function will wind up calling the
|
In <b>practice</b> it is strongly recommended to embed a director object
|
||||||
method defined in Go. The Go code may of course call other methods on
|
instance in a Go struct so that a director object instance will be represented
|
||||||
itself, and those methods may be defined either in Go or in C++.
|
as a distinct Go type that subclasses a C++ class. For this Go type custom
|
||||||
|
constructor and destructor functions take care of the director constructor and
|
||||||
|
destructor function calls and the resulting Go class will appear to the user as
|
||||||
|
any other SWIG wrapped C++ class. More on properly subclassing a C++ class
|
||||||
|
follows later in this guide under <a href="#Go_director_subclass">subclass via
|
||||||
|
embedding</a>.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
|
||||||
|
<H4><a name="Go_director_overriding"></a>23.4.7.4 Override virtual methods</H4>
|
||||||
|
|
||||||
|
|
||||||
|
<p>
|
||||||
|
In order to override virtual methods on a C++ class with Go methods the
|
||||||
|
<tt>NewDirectorClassName</tt> constructor functions receives a
|
||||||
|
<tt>DirectorInterface</tt> argument. The methods in the <tt>
|
||||||
|
DirectorInterface</tt> are a subset of the public and protected virtual methods
|
||||||
|
of the C++ class. If the <tt>DirectorInterface</tt> contains a method with a
|
||||||
|
matching signature to a virtual method of the C++ class then the virtual C++
|
||||||
|
method will be overwritten with the Go method. As Go doesn't support protected
|
||||||
|
methods all overriden protected virtual C++ methods will be public in Go.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
As an example see part of the <tt>FooBarGo</tt> class:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="code">
|
||||||
|
<pre>
|
||||||
|
type overwrittenMethodsOnFooBarAbs struct {
|
||||||
|
fb FooBarAbs
|
||||||
|
}
|
||||||
|
|
||||||
|
func (om *overwrittenMethodsOnFooBarAbs) Foo() string {
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
func (om *overwrittenMethodsOnFooBarAbs) Bar() string {
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewFooBarGo() FooBarGo {
|
||||||
|
om := &overwrittenMethodsOnFooBarAbs{}
|
||||||
|
fb := NewDirectorFooBarAbs(om)
|
||||||
|
om.fb = fb
|
||||||
|
...
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<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.
|
||||||
|
</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
|
||||||
|
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.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
|
||||||
|
<H4><a name="Go_director_base_methods"></a>23.4.7.5 Call base methods</H4>
|
||||||
|
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Often a virtual method will be overwritten to extend the original behavior of
|
||||||
|
the method in the base class. This is also the case for the
|
||||||
|
<tt>FooBarCpp::Foo</tt> method of the example code:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="code">
|
||||||
|
<pre>
|
||||||
|
virtual std::string Foo() {
|
||||||
|
return "C++ " + FooBarAbs::Foo();
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
To use base methods the <tt>DirectorClassNameMethodName</tt> wrapper functions
|
||||||
|
are automatically generated by SWIG for public and protected virtual methods.
|
||||||
|
The <tt>FooBarGo.Foo</tt> implementation in the example looks like this:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="code">
|
||||||
|
<pre>
|
||||||
|
func (om *overwrittenMethodsOnFooBarAbs) Foo() string {
|
||||||
|
return "Go " + DirectorFooBarAbsFoo(om.fb)
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<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>.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
|
||||||
|
<H4><a name="Go_director_subclass"></a>23.4.7.6 Subclass via embedding</H4>
|
||||||
|
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<a href="#Go_director_ctor_dtor">As previously mentioned in this guide</a> the
|
||||||
|
default and director constructor functions return the same interface type. To
|
||||||
|
properly subclass a C++ class with a Go type the director object instance
|
||||||
|
returned by the <tt>NewDirectorClassName</tt> constructor function should be
|
||||||
|
embedded into a Go struct so that it represents a distinct but compatible type
|
||||||
|
in Go's type system. This Go struct should be private and the constructor and
|
||||||
|
destructor functions should instead work with a public interface type so that
|
||||||
|
the Go class that subclasses a C++ class can be used as a compatible drop in.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
The subclassing part of the <tt>FooBarGo</tt> class for an example looks like
|
||||||
|
this:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="code">
|
||||||
|
<pre>
|
||||||
|
type FooBarGo interface {
|
||||||
|
FooBarAbs
|
||||||
|
deleteFooBarAbs()
|
||||||
|
IsFooBarGo()
|
||||||
|
}
|
||||||
|
|
||||||
|
type fooBarGo struct {
|
||||||
|
FooBarAbs
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fbgs *fooBarGo) deleteFooBarAbs() {
|
||||||
|
DeleteDirectorFooBarAbs(fbgs.FooBarAbs)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fbgs *fooBarGo) IsFooBarGo() {}
|
||||||
|
|
||||||
|
func NewFooBarGo() FooBarGo {
|
||||||
|
om := &overwrittenMethodsOnFooBarAbs{}
|
||||||
|
fb := NewDirectorFooBarAbs(om)
|
||||||
|
om.fb = fb
|
||||||
|
|
||||||
|
return &fooBarGo{FooBarAbs: fb}
|
||||||
|
}
|
||||||
|
|
||||||
|
func DeleteFooBarGo(fbg FooBarGo) {
|
||||||
|
fbg.deleteFooBarAbs()
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<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 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>
|
||||||
|
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.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
|
||||||
|
<H4><a name="Go_director_finalizer"></a>23.4.7.7 Memory management with runtime.SetFinalizer</H4>
|
||||||
|
|
||||||
|
|
||||||
|
<p>
|
||||||
|
In general all guidelines for <a href="#Go_class_memory">C++ class memory
|
||||||
|
management</a> apply as well to director classes. One often overlooked
|
||||||
|
limitation with <tt>runtime.SetFinalizer</tt> is that a finalizer doesn't run
|
||||||
|
in case of a cycle and director classes typically have a cycle. The cycle
|
||||||
|
in the <tt>FooBarGo</tt> class is here:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="code">
|
||||||
|
<pre>
|
||||||
|
type overwrittenMethodsOnFooBarAbs struct {
|
||||||
|
fb FooBarAbs
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewFooBarGo() FooBarGo {
|
||||||
|
om := &overwrittenMethodsOnFooBarAbs{}
|
||||||
|
fb := NewDirectorFooBarAbs(om) // fb.v = om
|
||||||
|
om.fb = fb // Backlink causes cycle as fb.v = om!
|
||||||
|
...
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
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>:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="code">
|
||||||
|
<pre>
|
||||||
|
type fooBarGo struct {
|
||||||
|
FooBarAbs
|
||||||
|
}
|
||||||
|
|
||||||
|
type overwrittenMethodsOnFooBarAbs struct {
|
||||||
|
fb FooBarAbs
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewFooBarGo() FooBarGo {
|
||||||
|
om := &overwrittenMethodsOnFooBarAbs{}
|
||||||
|
fb := NewDirectorFooBarAbs(om)
|
||||||
|
om.fb = fb // Backlink causes cycle as fb.v = om!
|
||||||
|
|
||||||
|
fbgs := &fooBarGo{FooBarAbs: fb}
|
||||||
|
runtime.SetFinalizer(fbgs, FooBarGo.deleteFooBarAbs)
|
||||||
|
return fbgs
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Furthermore if <tt>runtime.SetFinalizer</tt> is in use either the <tt>
|
||||||
|
DeleteClassName</tt> destructor function needs to be removed or the <tt>
|
||||||
|
fooBarGo</tt> struct needs additional data to prevent double deletion. Please
|
||||||
|
read the <a href="#Go_class_memory">C++ class memory management</a> subchapter
|
||||||
|
before using <tt>runtime.SetFinalizer</tt> to know all of its gotchas.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
|
||||||
|
<H4><a name="Go_director_foobargo_class"></a>23.4.7.8 Complete FooBarGo example class</H4>
|
||||||
|
|
||||||
|
|
||||||
|
<p>
|
||||||
|
The complete and annotated <tt>FooBarGo</tt> class looks like this:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<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.
|
||||||
|
type FooBarGo interface {
|
||||||
|
FooBarAbs
|
||||||
|
deleteFooBarAbs()
|
||||||
|
IsFooBarGo()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Via embedding fooBarGo "inherits" all methods of FooBarAbs.
|
||||||
|
type fooBarGo struct {
|
||||||
|
FooBarAbs
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fbgs *fooBarGo) deleteFooBarAbs() {
|
||||||
|
DeleteDirectorFooBarAbs(fbgs.FooBarAbs)
|
||||||
|
}
|
||||||
|
|
||||||
|
// The IsFooBarGo method ensures that FooBarGo is a superset of FooBarAbs.
|
||||||
|
// 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.
|
||||||
|
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
|
||||||
|
|
||||||
|
// 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 *overwrittenMethodsOnFooBarAbs) 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)
|
||||||
|
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)
|
||||||
|
return fbgs
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recommended to be removed if runtime.SetFinalizer is in use.
|
||||||
|
func DeleteFooBarGo(fbg FooBarGo) {
|
||||||
|
fbg.deleteFooBarAbs()
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Returned string by the <tt>FooBarGo.FooBar</tt> method is:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="code">
|
||||||
|
<pre>
|
||||||
|
Go Foo, Go Bar
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
For comparison the <tt>FooBarCpp</tt> class looks like this:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="code">
|
||||||
|
<pre>
|
||||||
|
class FooBarCpp : public FooBarAbs
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
virtual std::string Foo() {
|
||||||
|
return "C++ " + FooBarAbs::Foo();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual std::string Bar() {
|
||||||
|
return "C++ Bar";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
For comparison the returned string by the <tt>FooBarCpp::FooBar</tt> method is:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="code">
|
||||||
|
<pre>
|
||||||
|
C++ Foo, C++ Bar
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
The complete source of this example can be found under
|
||||||
|
<a href="https://github.com/swig/swig/tree/master/Examples/go/director">
|
||||||
|
SWIG/Examples/go/director/</a>.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
|
||||||
<H3><a name="Go_primitive_type_mappings"></a>23.4.8 Default Go primitive type mappings</H3>
|
<H3><a name="Go_primitive_type_mappings"></a>23.4.8 Default Go primitive type mappings</H3>
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
callback
|
callback
|
||||||
class
|
class
|
||||||
constants
|
constants
|
||||||
|
director
|
||||||
enum
|
enum
|
||||||
extend
|
extend
|
||||||
funcptr
|
funcptr
|
||||||
|
|
|
||||||
23
Examples/go/director/Makefile
Normal file
23
Examples/go/director/Makefile
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
TOP = ../..
|
||||||
|
SWIG = $(TOP)/../preinst-swig
|
||||||
|
CXXSRCS =
|
||||||
|
GOSRCS = example.go director.go # example.go gets generated by SWIG
|
||||||
|
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 $(SRCDIR)/director.go .; \
|
||||||
|
fi
|
||||||
|
$(MAKE) -f $(TOP)/Makefile SRCDIR='$(SRCDIR)' CXXSRCS='$(CXXSRCS)' GOSRCS='$(GOSRCS)' \
|
||||||
|
SWIG='$(SWIG)' SWIGOPT='$(SWIGOPT)' TARGET='$(TARGET)' INTERFACE='$(INTERFACE)' go_cpp
|
||||||
|
|
||||||
|
clean:
|
||||||
|
if [ -n '$(SRCDIR)' ]; then \
|
||||||
|
rm director.go || true; \
|
||||||
|
fi
|
||||||
|
$(MAKE) -f $(TOP)/Makefile SRCDIR='$(SRCDIR)' INTERFACE='$(INTERFACE)' go_clean
|
||||||
70
Examples/go/director/director.go
Normal file
70
Examples/go/director/director.go
Normal file
|
|
@ -0,0 +1,70 @@
|
||||||
|
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.
|
||||||
|
type FooBarGo interface {
|
||||||
|
FooBarAbs
|
||||||
|
deleteFooBarAbs()
|
||||||
|
IsFooBarGo()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Via embedding fooBarGo "inherits" all methods of FooBarAbs.
|
||||||
|
type fooBarGo struct {
|
||||||
|
FooBarAbs
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fbgs *fooBarGo) deleteFooBarAbs() {
|
||||||
|
DeleteDirectorFooBarAbs(fbgs.FooBarAbs)
|
||||||
|
}
|
||||||
|
|
||||||
|
// The IsFooBarGo method ensures that FooBarGo is a superset of FooBarAbs.
|
||||||
|
// 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.
|
||||||
|
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
|
||||||
|
|
||||||
|
// 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 *overwrittenMethodsOnFooBarAbs) 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)
|
||||||
|
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)
|
||||||
|
return fbgs
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recommended to be removed if runtime.SetFinalizer is in use.
|
||||||
|
func DeleteFooBarGo(fbg FooBarGo) {
|
||||||
|
fbg.deleteFooBarAbs()
|
||||||
|
}
|
||||||
41
Examples/go/director/director.h
Normal file
41
Examples/go/director/director.h
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
#ifndef DIRECTOR_H
|
||||||
|
#define DIRECTOR_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
|
||||||
|
class FooBarAbs
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
FooBarAbs() {};
|
||||||
|
virtual ~FooBarAbs() {};
|
||||||
|
|
||||||
|
std::string FooBar() {
|
||||||
|
return this->Foo() + ", " + this->Bar();
|
||||||
|
};
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual std::string Foo() {
|
||||||
|
return "Foo";
|
||||||
|
};
|
||||||
|
|
||||||
|
virtual std::string Bar() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class FooBarCpp : public FooBarAbs
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
virtual std::string Foo() {
|
||||||
|
return "C++ " + FooBarAbs::Foo();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual std::string Bar() {
|
||||||
|
return "C++ Bar";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
11
Examples/go/director/example.i
Normal file
11
Examples/go/director/example.i
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
/* File : example.i */
|
||||||
|
%module(directors="1") example
|
||||||
|
|
||||||
|
%include "std_string.i"
|
||||||
|
|
||||||
|
%header %{
|
||||||
|
#include "director.h"
|
||||||
|
%}
|
||||||
|
|
||||||
|
%feature("director") FooBarAbs;
|
||||||
|
%include "director.h"
|
||||||
28
Examples/go/director/index.html
Normal file
28
Examples/go/director/index.html
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>SWIG:Examples:go:director</title>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body bgcolor="#ffffff">
|
||||||
|
|
||||||
|
<tt>SWIG/Examples/go/director/</tt>
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<H2>How to subclass a C++ class with a Go type</H2>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
See the <a href="../../../Doc/Manual/Go.html#Go_director_classes">Go Director
|
||||||
|
Classes</a> documentation subsection for an explanation of this example.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<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="example.i">example.i</a>. SWIG interface file.
|
||||||
|
<li><a href="runme.go">runme.go</a>. Sample Go program.
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
39
Examples/go/director/runme.go
Normal file
39
Examples/go/director/runme.go
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"./example"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Compare(name string, got string, exp string) error {
|
||||||
|
fmt.Printf("%s; Got: '%s'; Expected: '%s'\n", name, got, exp)
|
||||||
|
if got != exp {
|
||||||
|
return fmt.Errorf("%s returned unexpected string! Got: '%s'; Expected: '%s'\n", name, got, exp)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFooBarCpp() error {
|
||||||
|
fb := example.NewFooBarCpp()
|
||||||
|
defer example.DeleteFooBarCpp(fb)
|
||||||
|
return Compare("FooBarCpp.FooBar()", fb.FooBar(), "C++ Foo, C++ Bar")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFooBarGo() error {
|
||||||
|
fb := example.NewFooBarGo()
|
||||||
|
defer example.DeleteFooBarGo(fb)
|
||||||
|
return Compare("FooBarGo.FooBar()", fb.FooBar(), "Go Foo, Go Bar")
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
fmt.Println("Test output:")
|
||||||
|
fmt.Println("------------")
|
||||||
|
err := TestFooBarCpp()
|
||||||
|
err = TestFooBarGo()
|
||||||
|
fmt.Println("------------")
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "Tests failed! Last error: %s\n", err.Error())
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue