SWIG入门4: C/C++初级特性2

1 structure

我看来,structure乃是封装之源。SWIG对于strucure的封装非常自然。自然的意思就是,C语言里怎么用PYTHON就怎么用。水里水里来,火里火里去。不过第一个问题就是,PYTHON作为面向对象的语言, 它本身就是没有struct的。不过没关系,我们还有class。

使用的方法非常简单。直接把struct的定义写到SWIG脚本文件里面去就好了。

struct Vector {
	double x,y,z;
};

使用起来也非常的方便。

>>> v = example.Vector()
>>> v.x = 3.5
>>> v.y = 7.2
>>> print v.x, v.y, v.z
7.8 -4.5 0.0
>>>

如果你打印出v的值,你会发现这个实例只是对底层Vector结构体指针的封装。这个实例本身什么也不做,它只是一个代理类。可以用.this的方式访问Vector结构体的指针。

>>> print v
<C Vector instance at _18e31408_p_Vector>
>>> print v.this
_18e31408_p_Vector
>>>

像全局变量一样,你可以在结构体定义内部用%immutable和%mutable指令来告诉SWIG哪些字段不可被修改,那些可以被修改。这两条指令的作用范围是在结构体之内的。

struct Foo {
   ...
   %immutable;
   int x;        /* Read-only members */
   char *name;
   %mutable;
   ...
};

如果你在struct中拥有char* 这种类型的字段,SWIG会用malloc或者new来分配内存呢。具体用哪一种要看你在运行swig时候是否使用了-c++这个参数。假如在python中对char*字段重新赋值,会先释放掉内存再申请一块新的内存。如果你觉得这种行为不符合你的要求,你可以用typemap来自定义行为。不过以后才会介绍typemap这个特性。

如果有数组类型的字段,那么在python中一样是当作指针来处理的。比如有这样的结构体

struct Bar {
    int  x[16];
};

python中运行结果如下:

>>> b = example.Bar()
>>> print b.x
_801861a4_p_int
>>>

像全局变量一样,你也可以用另外一个数组给这个数组来赋值,实际上是执行的值拷贝操作。

>>> c = example.Bar()
>>> c.x = b.x             # Copy contents of b.x to c.x

对数组赋值时, python实际上拷贝了b.x的16个int型整数到c.x所指向的位置。不过要注意一点,PYTHON不会为你做边界检查,如果你传了一个错误的地址是很有可能导致段错的。

结构体本身可以作为其他结构体的字段。但在swig中,这种结构体类型的字段是作为指针来处理的。假如有结构体Foo和Bar:

struct Foo {
   int a;
};

struct Bar {
   Foo f;
};

PYTHON中在Bar中可以像访问一个普通的属性一样访问Foo结构体。一切都非常自然。

>>> b = Bar()
>>> x = b.f

在这个例子中,x其实只是一个指向Foo的指针。结构体类型的字段和结构体指针类型的字段在SWIG中的处理方式是一样的。将上面的代码翻译成C语言的代码,就像这样

Bar b;
Foo *x = &b->f;       /* Points inside b */

 

2 class

c++的class当然也会装到PYTHON的class的类中。比如下面这个类:

class List {
public:
  List();
  ~List();
  int  search(char *item);
  void insert(char *item);
  void remove(char *item);
  char *get(int n);
  int  length;
};

在PYTHON里面这样方便的使用它:

>>> l = example.List()
>>> l.insert("Ale")
>>> l.insert("Stout")
>>> l.insert("Lager")
>>> l.get(1)
'Stout'
>>> print l.length
3
>>>

类的数据成员的访问方式和struct中基本一样。除了静态成员。

静态成员和PYTHON的访问方式有些不大相同。SWIG提供两种访问类的类成员函数的方法。第一种是直接通过对象来访问,第二种是可以通过‘类名_函数名’ 作为global函数的使用的方式。

>>> example.Spam_foo()    # Spam::foo()
>>> s = example.Spam()
>>> s.foo()               # Spam::foo() via an instance

类数据成员如何访问,还记得全局变量是怎么访问的吗?  SWIG将全局变量放在一个cvar的模块对象中。类数据成员的访问方法也是类似的,也是作为模块的全局变量来访问。

>>> print example.cvar.Spam_bar
7

3 继承

SWIG完全支持C++的继承方式。假如有这样的类的继承关系

class Foo {
...
};

class Bar : public Foo {
...
};

你就可以惊奇的发现在python里也可以拥有相同的继承关系:

>>> b = Bar()
>>> instance(b,Foo)
1
>>> issubclass(Bar,Foo)
1
>>> issubclass(Foo,Bar)
0

 你可以在此处下载本文中的例子, https://dl.dropbox.com/u/35106490/swig4.tgz

    原文作者:python入门
    原文地址: https://my.oschina.net/costaxu/blog/73481
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞