SWIG/Examples/go/class/
Wrapping a simple C++ class
This example illustrates the most primitive form of C++ class wrapping
performed by SWIG. In this case, C++ classes are simply transformed
into a collection of C-style functions that provide access to class
members.
The C++ Code
Suppose you have some C++ classes described by the following (and
admittedly lame) header file:
/* File : example.h */
class Shape {
public:
Shape() {
nshapes++;
}
virtual ~Shape() {
nshapes--;
}
double x, y;
void move(double dx, double dy);
virtual double area() = 0;
virtual double perimeter() = 0;
static int nshapes;
};
class Circle : public Shape {
private:
double radius;
public:
Circle(double r) : radius(r) { }
virtual double area();
virtual double perimeter();
};
class Square : public Shape {
private:
double width;
public:
Square(double w) : width(w) { }
virtual double area();
virtual double perimeter();
};
The SWIG interface
A simple SWIG interface for this can be built by simply grabbing the
header file like this:
/* File : example.i */
%module example
%{
#include "example.h"
%}
/* Let's just grab the original header file here */
%include "example.h"
Note: when creating a C++ extension, you must run SWIG with
the -c++ option like this:
% swig -c++ -go example.i
A sample Go script
See example.go for a program that calls the
C++ functions from Go.
Key points
- To create a new object, you call a constructor like this:
c := example.NewCircle(10.0)
The name of the constructor is New followed by the name of
the class, capitalized.
-
The constructor returns a value of interface type. The methods of the
interface will be the methods of the C++ class, plus member accessor
functions.
- To access member data, a pair of accessor methods are used. For
example:
c.SetX(15) # Set member data
x := c.GetX() # Get member data.
These are methods on the type returned by the constructor. The getter
is named Get followed by the name of the member,
capitalized. The setter is similar but uses Set.
- To invoke a member function, you simply do this
fmt.Println("The area is", example.c.Area())
- To invoke a destructor, simply do this
example.DeleteShape(c) # Deletes a shape
The name of the destructor is Delete followed by the name of
the class, capitalized. (Note: destructors are currently not
inherited. This might change later).
- Static member variables are wrapped much like C global variables.
For example:
n := GetShapeNshapes() # Get a static data member
SetShapeNshapes(13) # Set a static data member
The name is Get or Set, followed by the name of the
class, capitalized, followed by the name of the member, capitalized.
General Comments
- This low-level interface is not the only way to handle C++ code.
Director classes provide a much higher-level interface.
- Because C++ and Go implement inheritance quite differently, you
can not simply upcast an object in Go code when using multiple
inheritance. When using only single inheritance, you can simply pass
a class to a function expecting a parent class. When using multiple
inheritance, you have to call an automatically generated getter
function named Get followed by the capitalized name of the
immediate parent. This will return the same object converted to the
parent class.
-
Overloaded methods should normally work. However, when calling an
overloaded method you must explicitly convert constants to the
expected type when it is not int or float. In
particular, a floating point constant will default to
type float, but C++ functions typically expect the C++
type double which is equivalent to the Go
type float64 So calling an overloaded method with a floating
point constant typically requires an explicit conversion
to float64.
- Namespaces are not supported in any very coherent way.