阿酷尔工作室

V1

2022/08/13阅读:14主题:默认主题

swig封装C/C++实战-实现go调用C++然后C++在调用go

实战

代码组织结构

img
img

以下所有文件生成指令都是:

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(3742))
    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 = { 1020 };

/* 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 {
    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(37))
   fmt.Println(example.Maxdouble(3.142.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(intintint *);
%}

/* 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 {
    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(3742, r)
   fmt.Println("     37 - 42 = ", r[0])
   // Now try the version with return value
   fmt.Println("Testing return value")
   q := example.Divide(4237, 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(345)
   b := example.NewVector(101112)

   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,intint (*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)(intint));

/* 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 stringexp 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

分类:

后端

标签:

后端

作者介绍

阿酷尔工作室
V1

恒生研究院