6.16 包装重载操作符

SWIG可以包装C++重载操作符。例如,考虑如下的类:

class Complex {
private:
    double rpart, ipart;
public:
  Complex(double r = 0, double i = 0) : rpart(r), ipart(i){ }

  Complex(const Complex &c) : rpart(c.rpart), ipart(c.ipart) { }

  Complex &operator=(const Complex &c) {
    rpart = c.rpart;
    ipart = c.ipart;
    return *this;
  }

  Complex operator+(const Complex &c) const {
      return Complex(rpart+c.rpart, ipart+c.ipart);
  }

  Complex operator-(const Complex &c) const {
      return Complex(rpart-c.rpart, ipart-c.ipart);
  }

  Complex operator*(const Complex &c) const {
    return Complex(rpart*c.rpart - ipart*c.ipart,rpart*c.ipart + c.rpart*ipart);
  }

  Complex operator-() const {
      return Complex(-rpart, -ipart);
  }

  double re() const { return rpart; }
  double im() const { return ipart; }
};

当出现操作符时,处理他们的方式与处理常规方法一致。但,这些方法的名字被设置成类似operator +operator -的形式。这些名字的问题是,在脚本语言中不合法。比如,不能再Python中调用operator +

有些语言模块知道如何自动处理某些操作符(将它们映射到目标语言的操作符)。但是,底层的实现使用非常通用的方法,利用%rename指令。例如,在Python中:

%rename(__add__) Complex::operator+;

将+操作符绑定到__add__方法(Python中实现+操作符的惯用方法)。在内部,包装操作符的包装代码使用如下的类似代码:

_wrap_Complex___add__(args) {
  ... get args ...
  obj->operator+(args);
  ...
}

当在目标语言中使用时,可以像常规方式一样使用重载操作符。比如:

>>> a = Complex(3,4)
>>> b = Complex(5,2)
>>> c = a + b         # Invokes __add__ method

这里没有奇迹发生。只是使用%rename指令,选择了一个有效的名字而已。如果你写成这样:

%rename(add) operator+;

在脚本中就需要这样调用接口:

a = Complex(3,4)
b = Complex(5,2)
c = a.add(b)         # Call a.operator+(b)

前面介绍的用于重载函数的技术同样适用于操作符。例如:

%ignore Complex::operator=; // Ignore = in class Complex
%ignore *::operator=; // Ignore = in all classes
%ignore operator=; // Ignore = everywhere.
%rename(__sub__) Complex::operator-;
%rename(__neg__) Complex::operator-(); // Unary -

这个例子的后面演示了如何处理对operator-方法的多个定义。

使用这种方式处理重载操作符多数情况下都很直接。但是,有一些小问题需要记住:

  • 在C++中,为不同类型定义不同版本的操作符是很普遍的。例如,类可能还包含下面这样的友元函数:

    class Complex {
    public:
        friend Complex operator+(Complex &, double);
    };
    
    Complex operator+(Complex &, double);
    

    SWIG会简单忽略所有的友元声明。因此,就不知道如何在类中关联operator+了(因为它不是类的成员)。

    任然可能对这个操作符进行包装,但是不得不把它当做普通函数进行处理。例如:

    %rename(add_complex_double) operator+(Complex &, double);
    
  • 某些操作符默认情况下是被忽略的。比如,newdelete操作符都被忽略了。

  • 某些操作符的语义在目标语言中并没有匹配的表示方法。

results matching ""

    No results matching ""