实战
代码组织结构
以下所有文件生成指令都是:
swig -go -cgo -intgosize 64 -c++ example.i
Goin
example.i 文件
/* File : example.i */
%module(directors="1") example
// // 具体见 Go typemaps 章节
// goin
// %{%}
%inline %{
// Helper functions for converting string arrays
#include <stdlib.h>
void *alloc_ptr_array(unsigned int len)
{
return calloc(len, sizeof(void *));
}
void set_ptr_array(void *ain, unsigned int pos, void *val)
{
void **a = (void **) ain;
a[pos] = val;
}
void *get_ptr_array(void *ain, unsigned int pos)
{
void **a = (void **) ain;
return a[pos];
}
void free_ptr_array(void *ain)
{
void **a = (void **) ain;
unsigned int i;
if (!a)
return;
for (i = 0; a[i]; i++) {
free(a[i]);
}
free(a);
}
char *uintptr_to_string(void *in)
{
return (char *) in;
}
void *string_to_uintptr(char *in)
{
return strdup(in);
}
%}
// These typemaps convert between an array of strings in Go and a
// const char** that is NULL terminated in C++.
%typemap(gotype) (const char * const *) "[]string";
%typemap(imtype) (const char * const *) "uintptr";
%typemap(goin) (const char * const *) {
if $input == nil || len($input) == 0 {
$result = 0
} else {
$result = Alloc_ptr_array(uint(len($input) + 1))
defer func() {
Free_ptr_array($result)
}()
var i uint
for i = 0; i < uint(len($input)); i++ {
Set_ptr_array($result, i, String_to_uintptr($input[i]))
}
}
}
// C++封装中类型转换
%typemap(in) (const char * const *) {
$1 = (char **) $input;
}
// go封装中类型转换
%typemap(godirectorin) (const char * const *) {
if ($input == 0) {
$result = nil
} else {
var i uint
for i = 0; ; i++ {
var v uintptr = Get_ptr_array($input, i)
if v == 0 {
break
}
}
if i == 0 {
$result = nil
} else {
$result = make([]string, i)
for i = 0; ; i++ {
var v uintptr = Get_ptr_array($input, i)
if v == 0 {
break
}
$result[i] = Uintptr_to_string(v)
}
}
}
}
%feature("director") callbacks;
%inline %{
// go -> C++ -> go
// 如何实现:
// 1. 定义callbacks 用于回调
// 2. 使用director指导swig将 callbacks
class callbacks {
public:
virtual bool call1(int v, const char * const *strarray);
virtual ~callbacks() {}
};
bool check1(callbacks *c, int v, const char * const *strarray) {
return c->call1(v, strarray);
}
bool callbacks::call1(int v, const char * const *strarray) {
// siwg 封装的时候,前面需要判断是否走代理,代理非空就走代理那边(go)
return false;
}
%}
mian.go测试文件
package main
import (
"basic/swig/example"
"fmt"
)
type mycallbacks struct {
example.Callbacks
}
var tststrs = []string{ "A", "BCD", "EFGH" }
var tstint int = 5
func (v *mycallbacks) Call1(val int, strarray []string) bool {
var rv bool = true
for i, s := range strarray {
fmt.Printf("%d: %s\n", i, s)
if s != tststrs[i] {
fmt.Printf(" ***Mismatch, expected %s\n", tststrs[i])
rv = false
}
}
if val != tstint {
rv = false
}
return rv
}
func main() {
cbs := &mycallbacks{}
cbs.Callbacks = example.NewDirectorCallbacks(cbs)
// go -> C++ -> go
worked := example.Check1(cbs, tstint, tststrs)
if !worked {
panic("Data mismatch")
}
}
Example
example.i
%module example
%{
#include "example.h"
%}
%include "example.h"
example.h
#ifndef __EXAMPLE__H__
#define __EXAMPLE__H__
extern double Foo;
/* Compute the greatest common divisor of positive integers */
int gcd(int x, int y);
#endif // __EXAMPLE__H__
example.cpp
/* A global variable */
double Foo = 3.0;
/* Compute the greatest common divisor of positive integers */
int gcd(int x, int y) {
int g;
g = y;
while (x > 0) {
g = x;
x = y % x;
y = g;
}
return g;
}
main.go
package main
import (
"basic/swig/example"
"fmt"
)
func main() {
// Call our gcd() function
// go -> C函数接口
x := 42
y := 105
g := example.Gcd(x, y)
fmt.Println("The gcd of", x, "and", y, "is", g)
// Manipulate the Foo global variable
// Output its current value
fmt.Println("Foo =", example.GetFoo())
// Change its value
example.SetFoo(3.1415926)
// See if the change took effect
fmt.Println("Foo =", example.GetFoo())
}
Variables
main.go
// This example illustrates global variable access from Go.
package main
import (
"fmt"
"swigtests/example"
)
func main() {
// Try to set the values of some global variables
example.SetIvar(42)
example.SetSvar(-31000)
example.SetLvar(65537)
example.SetUivar(123456)
example.SetUsvar(61000)
example.SetUlvar(654321)
example.SetScvar(-13)
example.SetUcvar(251)
example.SetCvar('S')
example.SetFvar(3.14159)
example.SetDvar(2.1828)
example.SetStrvar("Hello World")
example.SetIptrvar(example.New_int(37))
example.SetPtptr(example.New_Point(37, 42))
example.SetName("Bill")
// Now print out the values of the variables
fmt.Println("Variables (values printed from Go)")
fmt.Println("ivar =", example.GetIvar())
fmt.Println("svar =", example.GetSvar())
fmt.Println("lvar =", example.GetLvar())
fmt.Println("uivar =", example.GetUivar())
fmt.Println("usvar =", example.GetUsvar())
fmt.Println("ulvar =", example.GetUlvar())
fmt.Println("scvar =", example.GetScvar())
fmt.Println("ucvar =", example.GetUcvar())
fmt.Println("fvar =", example.GetFvar())
fmt.Println("dvar =", example.GetDvar())
fmt.Printf("cvar = %c\n", example.GetCvar())
fmt.Println("strvar =", example.GetStrvar())
fmt.Println("cstrvar =", example.GetCstrvar())
fmt.Println("iptrvar =", example.GetIptrvar())
fmt.Println("name =", example.GetName())
fmt.Println("ptptr =", example.GetPtptr(), example.Point_print(example.GetPtptr()))
fmt.Println("pt =", example.GetPt(), example.Point_print(example.GetPt()))
fmt.Println("\nVariables (values printed from C)")
example.Print_vars()
// This line would not compile: since status is marked with
// %immutable, there is no SetStatus function.
// fmt.Println("\nNow I'm going to try and modify some read only variables")
// example.SetStatus(0)
fmt.Println("\nI'm going to try and update a structure variable.\n")
example.SetPt(example.GetPtptr())
fmt.Println("The new value is")
example.Pt_print()
fmt.Println("You should see the value", example.Point_print(example.GetPtptr()))
}
example.i
/* File : example.i */
%module example
%{
#include "example.h"
%}
/* Some global variable declarations */
%inline %{
extern int ivar;
extern short svar;
extern long lvar;
extern unsigned int uivar;
extern unsigned short usvar;
extern unsigned long ulvar;
extern signed char scvar;
extern unsigned char ucvar;
extern char cvar;
extern float fvar;
extern double dvar;
extern char *strvar;
extern const char cstrvar[];
extern int *iptrvar;
extern char name[256];
extern Point *ptptr;
extern Point pt;
%}
/* Some read-only variables */
%immutable;
%inline %{
extern int status;
extern char path[256];
%}
%mutable;
/* Some helper functions to make it easier to test */
%inline %{
extern void print_vars();
extern int *new_int(int value);
extern Point *new_Point(int x, int y);
extern char *Point_print(Point *p);
extern void pt_print();
%}
example.h
/* File: example.h */
typedef struct {
int x,y;
} Point;
example.c
/* File : example.c */
/* I'm a file containing some C global variables */
/* Deal with Microsoft's attempt at deprecating C standard runtime functions */
#if !defined(SWIG_NO_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER)
# define _CRT_SECURE_NO_DEPRECATE
#endif
#include <stdio.h>
#include <stdlib.h>
#include "example.h"
int ivar = 0;
short svar = 0;
long lvar = 0;
unsigned int uivar = 0;
unsigned short usvar = 0;
unsigned long ulvar = 0;
signed char scvar = 0;
unsigned char ucvar = 0;
char cvar = 0;
float fvar = 0;
double dvar = 0;
char *strvar = 0;
const char cstrvar[] = "Goodbye";
int *iptrvar = 0;
char name[256] = "Dave";
char path[256] = "/home/beazley";
/* Global variables involving a structure */
Point *ptptr = 0;
Point pt = { 10, 20 };
/* A variable that we will make read-only in the interface */
int status = 1;
/* A debugging function to print out their values */
void print_vars() {
printf("ivar = %d\n", ivar);
printf("svar = %d\n", svar);
printf("lvar = %ld\n", lvar);
printf("uivar = %u\n", uivar);
printf("usvar = %u\n", usvar);
printf("ulvar = %lu\n", ulvar);
printf("scvar = %d\n", scvar);
printf("ucvar = %u\n", ucvar);
printf("fvar = %g\n", fvar);
printf("dvar = %g\n", dvar);
printf("cvar = %c\n", cvar);
printf("strvar = %s\n", strvar ? strvar : "(null)");
printf("cstrvar = %s\n", cstrvar);
printf("iptrvar = %p\n", iptrvar);
printf("name = %s\n", name);
printf("ptptr = %p (%d, %d)\n", ptptr, ptptr ? ptptr->x : 0, ptptr ? ptptr->y : 0);
printf("pt = (%d, %d)\n", pt.x, pt.y);
printf("status = %d\n", status);
}
/* A function to create an integer (to test iptrvar) */
int *new_int(int value) {
int *ip = (int *) malloc(sizeof(int));
*ip = value;
return ip;
}
/* A function to create a point */
Point *new_Point(int x, int y) {
Point *p = (Point *) malloc(sizeof(Point));
p->x = x;
p->y = y;
return p;
}
char * Point_print(Point *p) {
static char buffer[256];
if (p) {
sprintf(buffer,"(%d,%d)", p->x,p->y);
} else {
sprintf(buffer,"null");
}
return buffer;
}
void pt_print() {
printf("(%d, %d)\n", pt.x, pt.y);
}
枚举型变量封装
example.i
%module example
%{
#include "example.h"
%}
%include "example.h"
example.h
/* File : example.h */
enum color { RED, BLUE, GREEN };
class Foo {
public:
Foo() { }
enum speed { IMPULSE=10, WARP=20, LUDICROUS=30 };
void enum_test(speed s);
};
void enum_test(color c, Foo::speed s);
example.cpp
/* File : example.cxx */
#include "example.h"
#include <stdio.h>
void Foo::enum_test(speed s) {
if (s == IMPULSE) {
printf("IMPULSE speed\n");
} else if (s == WARP) {
printf("WARP speed\n");
} else if (s == LUDICROUS) {
printf("LUDICROUS speed\n");
} else {
printf("Unknown speed\n");
}
}
void enum_test(color c, Foo::speed s) {
if (c == RED) {
printf("color = RED, ");
} else if (c == BLUE) {
printf("color = BLUE, ");
} else if (c == GREEN) {
printf("color = GREEN, ");
} else {
printf("color = Unknown color!, ");
}
if (s == Foo::IMPULSE) {
printf("speed = IMPULSE speed\n");
} else if (s == Foo::WARP) {
printf("speed = WARP speed\n");
} else if (s == Foo::LUDICROUS) {
printf("speed = LUDICROUS speed\n");
} else {
printf("speed = Unknown speed!\n");
}
}
main.go
package main
import (
"basic/swig/example"
"fmt"
)
func main() {
// Print out the value of some enums
fmt.Println("*** color ***")
fmt.Println(" RED = ", example.RED)
fmt.Println(" BLUE = ", example.BLUE)
fmt.Println(" GREEN = ", example.GREEN)
fmt.Println("\n*** Foo::speed ***")
fmt.Println(" Foo::IMPULSE = ", example.FooIMPULSE)
fmt.Println(" Foo::WARP = ", example.FooWARP)
fmt.Println(" Foo::LUDICROUS = ", example.FooLUDICROUS)
fmt.Println("\nTesting use of enums with functions\n")
example.Enum_test(example.RED, example.FooIMPULSE)
example.Enum_test(example.BLUE, example.FooWARP)
example.Enum_test(example.GREEN, example.FooLUDICROUS)
fmt.Println("\nTesting use of enum with class method")
f := example.NewFoo()
f.Enum_test(example.FooIMPULSE)
f.Enum_test(example.FooWARP)
f.Enum_test(example.FooLUDICROUS)
}
模板的封装示例
example.i
/* File : example.i */
%module example
%{
#include "example.h"
%}
/* Let's just grab the original header file here */
%include "example.h"
/* Now instantiate some specific template declarations */
%template(maxint) max<int>;
%template(maxdouble) max<double>;
%template(vecint) vector<int>;
%template(vecdouble) vector<double>;
example.h
/* File : example.h */
// Some template definitions
template<class T> T max(T a, T b) { return a>b ? a : b; }
template<class T>
class vector {
T *v;
int sz;
public:
vector(int _sz) {
v = new T[_sz];
sz = _sz;
}
T &get(int index) {
return v[index];
}
void set(int index, T &val) {
v[index] = val;
}
#ifdef SWIG
%extend {
T getitem(int index) {
return $self->get(index);
}
void setitem(int index, T val) {
$self->set(index,val);
}
}
#endif
};
main.go
package main
import (
"basic/swig/example"
"fmt"
)
func main() {
// Call some templated functions
fmt.Println(example.Maxint(3, 7))
fmt.Println(example.Maxdouble(3.14, 2.18))
// Create some class
iv := example.NewVecint(100)
dv := example.NewVecdouble(1000)
for i := 0; i < 100; i++ {
iv.Setitem(i, 2*i)
}
for i := 0; i < 1000; i++ {
dv.Setitem(i, 1.0/float64(i+1))
}
{
sum := 0
for i := 0; i < 100; i++ {
sum = sum + iv.Getitem(i)
}
fmt.Println(sum)
}
{
sum := float64(0.0)
for i := 0; i < 1000; i++ {
sum = sum + dv.Getitem(i)
}
fmt.Println(sum)
}
}
Poimter封装
example.i
/* File : example.i */
%module example
%{
extern void add(int *, int *, int *);
extern void sub(int *, int *, int *);
extern int divide(int, int, int *);
%}
/* This example illustrates a couple of different techniques
for manipulating C pointers */
/* First we'll use the pointer library */
extern void add(int *x, int *y, int *result);
%include cpointer.i
%pointer_functions(int, intp);
/* Next we'll use some typemaps */
%include typemaps.i
extern void sub(int *INPUT, int *INPUT, int *OUTPUT);
/* Next we'll use typemaps and the %apply directive */
%apply int *OUTPUT { int *r };
extern int divide(int n, int d, int *r);
example.h
/* File : example.h */
// Some template definitions
template<class T> T max(T a, T b) { return a>b ? a : b; }
template<class T>
class vector {
T *v;
int sz;
public:
vector(int _sz) {
v = new T[_sz];
sz = _sz;
}
T &get(int index) {
return v[index];
}
void set(int index, T &val) {
v[index] = val;
}
#ifdef SWIG
%extend {
T getitem(int index) {
return $self->get(index);
}
void setitem(int index, T val) {
$self->set(index,val);
}
}
#endif
};
example.cpp
/* File : example.c */
void add(int *x, int *y, int *result) {
*result = *x + *y;
}
void sub(int *x, int *y, int *result) {
*result = *x - *y;
}
int divide(int n, int d, int *r) {
int q;
q = n/d;
*r = n - q*d;
return q;
}
main.go
package main
import (
"basic/swig/example"
"fmt"
)
func main() {
// First create some objects using the pointer library.
fmt.Println("Testing the pointer library")
a := example.New_intp()
b := example.New_intp()
c := example.New_intp()
example.Intp_assign(a, 37)
example.Intp_assign(b, 42)
fmt.Println(" a =", a)
fmt.Println(" b =", b)
fmt.Println(" c =", c)
// Call the add() function with some pointers
example.Add(a, b, c)
// Now get the result
res := example.Intp_value(c)
fmt.Println(" 37 + 42 =", res)
// Clean up the pointers
example.Delete_intp(a)
example.Delete_intp(b)
example.Delete_intp(c)
// Now try the typemap library
// Now it is no longer necessary to manufacture pointers.
// Instead we use a single element slice which in Go is modifiable.
fmt.Println("Trying the typemap library")
r := []int{0}
example.Sub(37, 42, r)
fmt.Println(" 37 - 42 = ", r[0])
// Now try the version with return value
fmt.Println("Testing return value")
q := example.Divide(42, 37, r)
fmt.Println(" 42/37 = ", q, " remainder ", r[0])
}
Extend
example.h
/* File : example.h */
// 1. 对类的封装
// 2. 友元函数的封装
// 3. 操作符重载
class Vector {
private:
double x,y,z;
public:
// 初始化列表
Vector() : x(0), y(0), z(0) { }
Vector(double x, double y, double z) : x(x), y(y), z(z) { }
// 友元函数
friend Vector operator+(const Vector &a, const Vector &b);
// binary数据,或者是字符数组
char *print();
};
class VectorArray {
private:
Vector *items;
int maxsize;
public:
VectorArray(int maxsize);
~VectorArray();
// 操作符重载
Vector &operator[](int);
int size();
};
eaxmple.cpp
/* File : example.cxx */
/* Deal with Microsoft's attempt at deprecating C standard runtime functions */
#if !defined(SWIG_NO_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER)
# define _CRT_SECURE_NO_DEPRECATE
#endif
#include "example.h"
#include <stdio.h>
#include <stdlib.h>
Vector operator+(const Vector &a, const Vector &b) {
Vector r;
r.x = a.x + b.x;
r.y = a.y + b.y;
r.z = a.z + b.z;
return r;
}
char *Vector::print() {
static char temp[512];
sprintf(temp,"Vector %p (%g,%g,%g)", (void *)this, x,y,z);
return temp;
}
VectorArray::VectorArray(int size) {
items = new Vector[size];
maxsize = size;
}
VectorArray::~VectorArray() {
delete [] items;
}
Vector &VectorArray::operator[](int index) {
if ((index < 0) || (index >= maxsize)) {
printf("Panic! Array index out of bounds.\n");
exit(1);
}
return items[index];
}
int VectorArray::size() {
return maxsize;
}
example.i
/* File : example.i */
/* This file has a few "typical" uses of C++ references. */
%module example
// 只有一个头文件, inline 是没有用的
// %{%} 任何东西都会 不进行任何改动的复制xxx_wrap.cxx
// inline对于 %{%}这个定义的函数,1 进行封装 2 复制cxx文件中,如果没有inline,只复制到cxx文件
%{
#include "example.h"
%}
// 1. 如何对友元函数进行封装, go里面没有+这个函数
// 2. swig里面是覆盖的,所以重命名,需要在对应的函数引入之前
// %rename(op_j) ::operator+;
// %rename(op_i) VectorArray::operator[](int);
//
// %include "example.h"
class Vector {
public:
Vector(double x, double y, double z);
~Vector();
char *print();
};
//
/* This helper function calls an overloaded operator */
%inline %{
// 非成员函数直接定义
Vector addv(Vector &a, Vector &b) {
return a+b;
}
%}
/* Wrapper around an array of vectors class */
class VectorArray {
public:
// 需要封装的函数这里要列出来,不列出来的不会进行封装
VectorArray(int maxsize);
~VectorArray();
int size();
/* This wrapper provides an alternative to the [] operator */
%extend {
Vector &get(int index) {
return (*$self)[index];
}
void set(int index, Vector &a) {
(*$self)[index] = a;
}
}
};
main.go
package main
import (
"basic/swig/example"
"fmt"
)
func main() {
fmt.Println("Creating some objects:")
a := example.NewVector(3, 4, 5)
b := example.NewVector(10, 11, 12)
fmt.Println(" Created ", a.Print())
fmt.Println(" Created ", b.Print())
// ----- Call an overloaded operator -----
// This calls the wrapper we placed around
//
// operator+(const Vector &a, const Vector &)
//
// It returns a new allocated object.
fmt.Println("Adding a+b")
c := example.Addv(a, b)
fmt.Println(" a+b = " + c.Print())
// Because addv returns a reference, Addv will return a
// pointer allocated using Go's memory allocator. That means
// that it will be freed by Go's garbage collector, and we can
// not use DeleteVector to release it.
c = nil
// ----- Create a vector array -----
fmt.Println("Creating an array of vectors")
va := example.NewVectorArray(10)
fmt.Println(" va = ", va)
// ----- Set some values in the array -----
// These operators copy the value of Vector a and Vector b to
// the vector array
va.Set(0, a)
va.Set(1, b)
va.Set(2, example.Addv(a, b))
// Get some values from the array
fmt.Println("Getting some array values")
for i := 0; i < 5; i++ {
fmt.Println(" va(", i, ") = ", va.Get(i).Print())
}
// Watch under resource meter to check on this
fmt.Println("Making sure we don't leak memory.")
for i := 0; i < 1000000; i++ {
c = va.Get(i % 10)
}
// ----- Clean up ----- This could be omitted. The garbage
// collector would then clean up for us.
fmt.Println("Cleaning up")
example.DeleteVectorArray(va)
example.DeleteVector(a)
example.DeleteVector(b)
}
Funcptr
example.cpp
/* File : example.c */
int do_op(int a, int b, int (*op)(int,int)) {
return (*op)(a,b);
}
int add(int a, int b) {
return a+b;
}
int sub(int a, int b) {
return a-b;
}
int mul(int a, int b) {
return a*b;
}
int (*funcvar)(int,int) = add;
eaxmple.h
/* file: example.h */
extern int do_op(int,int, int (*op)(int,int));
extern int add(int,int);
extern int sub(int,int);
extern int mul(int,int);
extern int (*funcvar)(int,int);
example.i
/* File : example.i */
%module example
%{
#include "example.h"
%}
/* Wrap a function taking a pointer to a function */
extern int do_op(int a, int b, int (*op)(int, int));
/* Now install a bunch of "ops" as constants */
%constant int (*ADD)(int,int) = add;
%constant int (*SUB)(int,int) = sub;
%constant int (*MUL)(int,int) = mul;
extern int (*funcvar)(int,int);
main.go
package main
import (
"basic/swig/example"
"fmt"
)
func main() {
a := 37
b := 42
// Now call our C function with a bunch of callbacks
fmt.Println("Trying some C callback functions")
fmt.Println(" a = ", a)
fmt.Println(" b = ", b)
fmt.Println(" ADD(a,b) = ", example.Do_op(a, b, example.ADD))
fmt.Println(" SUB(a,b) = ", example.Do_op(a, b, example.SUB))
fmt.Println(" MUL(a,b) = ", example.Do_op(a, b, example.MUL))
fmt.Println("Here is what the C callback function classes are called in Go")
fmt.Println(" ADD = ", example.ADD)
fmt.Println(" SUB = ", example.SUB)
fmt.Println(" MUL = ", example.MUL)
}
Feature
example.h
/* 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;
}
};
ceo.go
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"
}
example.i
/* 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"
main.go
package main
import (
"basic/swig/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 := example.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 := example.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.
example.DeleteEmployeeList(list)
fmt.Println("----------------------")
// All done.
fmt.Println("Go exit")
}
Direct
内部实现技术,使用go实现对应的接口,并且只要go实现了就调用go的,这就是代理模式 – 》然后结合回调实现go -> C++ -> go
direct.go
package example
// FooBarGo 继承了 FooBarAbstract 因此可以将 FooBarGo 替代FooBarAbstract使用
// 但是这个只能是单向的,发过来会导致编译错误
type FooBarGo interface {
FooBarAbstract
deleteFooBarAbstract()
IsFooBarGo()
}
// Via embedding fooBarGo "inherits" all methods of FooBarAbstract.
type fooBarGo struct {
FooBarAbstract
}
func (fbgs *fooBarGo) deleteFooBarAbstract() {
DeleteDirectorFooBarAbstract(fbgs.FooBarAbstract)
}
// 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 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 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 overridden methods can use them.
}
func (om *overwrittenMethodsOnFooBarAbstract) Foo() string {
// DirectorFooBarAbstractFoo calls the base method FooBarAbstract::Foo.
return "Go " + DirectorFooBarAbstractFoo(om.fb)
}
func (om *overwrittenMethodsOnFooBarAbstract) Bar() string {
return "Go Bar"
}
func NewFooBarGo() FooBarGo {
// 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{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. Furthermore
// 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.deleteFooBarAbstract()
}
example.h
#ifndef DIRECTOR_H
#define DIRECTOR_H
#include <stdio.h>
#include <string>
class FooBarAbstract
{
public:
FooBarAbstract() {};
virtual ~FooBarAbstract() {};
std::string FooBar() {
return this->Foo() + ", " + this->Bar();
};
protected:
virtual std::string Foo() {
return "Foo";
};
virtual std::string Bar() = 0;
};
class FooBarCpp : public FooBarAbstract
{
protected:
virtual std::string Foo() {
return "C++ " + FooBarAbstract::Foo();
}
virtual std::string Bar() {
return "C++ Bar";
}
};
#endif
example.i
/* File : example.i */
%module(directors="1") example
%include "std_string.i"
%header %{
#include "example.h"
%}
%feature("director") FooBarAbstract;
%include "example.h"
main.go
package main
import (
"basic/swig/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)
}
}
callback
example.h
/* 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(); }
};
callback.go
package example
import (
"fmt"
)
type GoCallback interface {
Callback
deleteCallback()
IsGoCallback()
}
// 如果一个结构体中有一个interface 那么只要这个interface的值,实现了Callback的所有接口,兵且
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 *overwrittenMethodsOnCallback) Run() {
fmt.Println("GoCallback.Run")
}
example.i
// go -> C++ -> go
%module(directors="1") example
%{
#include "example.h"
%}
%feature("director") Callback;
%include "example.h"
package main
import (
"basic/swig/example"
"fmt"
)
func main() {
fmt.Println("Adding and calling a normal C++ callback")
fmt.Println("----------------------------------------")
caller := example.NewCaller()
callback := example.NewCallback()
caller.SetCallback(callback)
caller.Call()
caller.DelCallback()
go_callback := example.NewGoCallback()
fmt.Println()
fmt.Println("Adding and calling a Go callback")
fmt.Println("--------------------------------")
caller.SetCallback(go_callback)
caller.Call()
caller.DelCallback()
example.DeleteGoCallback(go_callback)
fmt.Println()
fmt.Println("Go exit")
}
飞书文档:飞书文档
对应视频课件: https://www.bilibili.com/video/BV19F411c7LM?spm_id_from=333.999.0.0&vd_source=d0f1fc53c13a7dcbda92faa2e368b71e