 |
파이썬 마을 우리나라 파이썬 사용자들의 이야기 마을
|
|
| 이전 주제 보기 :: 다음 주제 보기 |
| 글쓴이 |
메시지 |
jrcho
가입: 올린 글: 56
|
올려짐: 2004 5월 12 7:18 pm 주제: [SWIG강좌] 3.3 C++에서의 사용 (3) |
|
|
3.3.5. C++ Inheritance
SWIG는 C++ 상속을 지원하며, Python의 instance(), issubclass() 함수 역시 사용할 수 있다. SWIG는 inheritance hierarchies를 run-time type checker 가 inheritance hierarchy를 알도록 엔코딩한다. 다음 예(example/inheritance)를 보길 바란다
| 코드: |
// example.i
%module example
%{
class Shape {
public:
virtual double area() = 0;
};
class Circle : public Shape {
public:
Circle(double radius) : r(radius) {}
~Circle(){}
double area(){ return r*r*3.141592; }
private:
double r;
};
class Rectangle : public Shape{
public:
Rectangle(double xsize,double ysize) : x(xsize), y(ysize) {}
~Rectangle(){}
double area(){ return x*y; }
private:
double x,y;
};
void draw(Shape* s) {
printf("draw\n");
}
%}
class Shape {
public:
virtual double area() = 0;
};
class Circle : public Shape {
public:
Circle(double radius);
~Circle();
double area();
};
class Rectangle : public Shape{
public:
Rectangle(double xsize,double ysize);
~Rectangle();
double area();
};
void draw(Shape* s);
|
Python에서의 사용예는 다음과 같다.
>>> from example import *
>>> s = Shape()
Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "example.py", line 38, in __init__
def __init__(self): raise RuntimeError, "No constructor defined"
RuntimeError: No constructor defined
>>> c = Circle(10.)
>>> print c
<C Circle instance at _b8c98000_p_Circle>
>>> r = Rectangle(2.,3.)
>>> print r
<C Rectangle instance at _08498700_p_Rectangle>
>>> c.area()
314.1592
>>> r.area()
6.0
>>> draw(c)
draw
>>> isinstance(c,Shape)
True
>>> issubclass(Circle,Shape)
True
>>>
위 예에서 isinstance(), issubclass()와 같은 Python 명령이 실행됨을 알 수 있고, void draw(Shape* s)와 같이 함수 인자로 Shape에서 상속받은 객체 포인터를 지정할 수 있도록 지원하고 있다.
만약 가상클래스가 base 클래스가 아닌 경우 overriding한 사실에 대해 swig에 알려줄 필요는 없다. 다음 예를 보기로 하자.
| 코드: |
// example.i
%module example
%{
class Shape {
public:
virtual double area(){ return 0.;}
};
class Circle : public Shape {
public:
Circle(double radius) : r(radius) {}
~Circle(){}
double area(){ return r*r*3.141592; }
private:
double r;
};
class Rectangle : public Shape{
public:
Rectangle(double xsize,double ysize) : x(xsize), y(ysize) {}
~Rectangle(){}
double area(){ return x*y; }
private:
double x,y;
};
void draw(Shape* s) {
printf("draw\n");
}
%}
class Shape {
public:
virtual double area();
};
class Circle : public Shape {
public:
Circle(double radius);
~Circle();
double area();
};
class Rectangle : public Shape{
public:
Rectangle(double xsize,double ysize);
~Rectangle();
double area();
};
void draw(Shape* s);
|
위 코드에서 SWIG는 Shape, Circle, Rectangle의 area() 함수에 대한 wrapper를 만든다. 즉, 다음과 같다.
| 코드: |
// low level wrapper에서
_wrap_Shape_area(), _wrap_Circle_area(), _wrap_Rectangle_area() 모두 존재
static PyMethodDef SwigMethods[] = {
...
{ (char *)"Shape_area", _wrap_Shape_area, METH_VARARGS },
{ (char *)"Circle_area", _wrap_Circle_area, METH_VARARGS },
{ (char *)"Rectangle_area", _wrap_Rectangle_area, METH_VARARGS },
...
};
// high level wrapper에서
class Shape(_object):
...
def area(*args): return _example.Shape_area(*args)
class Circle(Shape):
...
def area(*args): return _example.Circle_area(*args)
class Rectangle(Shape):
...
def area(*args): return _example.Rectangle_area(*args)
|
하지만, 많은 가상 함수가 존재하여 모두 SWIG 인터페이스화일에 쓰기 힘든 경우가 있다. 즉,
| 코드: |
// example.i
%module example
%{
class Shape {
public:
virtual double area(){ return 0.;}
};
class Circle : public Shape {
public:
Circle(double radius) : r(radius) {}
~Circle(){}
double area(){ return r*r*3.141592; }
private:
double r;
};
class Rectangle : public Shape{
public:
Rectangle(double xsize,double ysize) : x(xsize), y(ysize) {}
~Rectangle(){}
double area(){ return x*y; }
private:
double x,y;
};
void draw(Shape* s) {
printf("draw\n");
}
%}
class Shape {
public:
virtual double area();
};
class Circle : public Shape {
public:
Circle(double radius);
~Circle();
};
class Rectangle : public Shape{
public:
Rectangle(double xsize,double ysize);
~Rectangle();
};
void draw(Shape* s);
|
위 코드는 동일한 클래스에 대해 Circle()과 Rectangle()에 대한 area() 함수 선언을 SWIG에 알려 주지 않았다. 이 경우 생성되는 wrapper 코드는 다음과 같다.
| 코드: |
// low level wrapper에서
_wrap_Shape_area() 만 존재, _wrap_Circle_area(), _wrap_Rectangle_area() 는 없음.
static PyMethodDef SwigMethods[] = {
...
{ (char *)"Shape_area", _wrap_Shape_area, METH_VARARGS },
...
};
// high level wrapper에서
class Shape(_object):
...
def area(*args): return _example.Shape_area(*args)
class Circle(Shape):
...
// def area(*args) 가 없음
class Rectangle(Shape):
...
// def area(*args) 가 없음
|
하지만, 실행하면 아무 이상이 없이 돌아 간다. 왜냐하면, Shape::area()의 wrapper 코드에서 포인터를 이용해 area()을 호출하기 때문에 올바른 C++ 클래스의 호출이 이루어 지기 때문이다.
3.3.6. C++ overloaded functions
C++ overloaded functions, methods, and constructors 들은 대부분 SWIG가 지원한다. 예를 들어,
void foo(int);
void foo(char *c);
>>> foo(3) # foo(int)
>>> foo("Hello") # foo(char *c)
이와 동일하게 클래스의 생성자에서
class Foo {
public:
Foo();
Foo(const Foo &);
...
};
>>> f = Foo() # Create a Foo
>>> g = Foo(f) # Copy f
Overloading support가 C++만큼 유연하지 않다. 경우에 따라서는 SWIG가 인식하지 못하는 메쏘드가 있다. 예를 들어,
void spam(int);
void spam(short);
또는
void foo(Bar *b);
void foo(Bar &b);
이와 같은 정의가 발견되면, SWIG는 다음과 같은 warning message를 출력한다.
example.i:12: Warning(509): Overloaded spam(short) is shadowed by spam(int) at example.i:11.
이를 해결하기 위해서 한 메쏘드를 무시하거나(ignore) 또는 이름을 바꾸어야할(rename) 필요가 있다. 즉,
%rename(spam_short) spam(short);
...
void spam(int);
void spam(short); // Accessed as spam_short
또는
%ignore spam(short)
...
void spam(int);
void spam(short); //ignored
3.3.7. C++ operator
SWIG는 C++ overloaded operators에 대해 제한적으로 지원한다. SWIG는 클래스의 멤버함수로 정의된 operator에 대해서는 지원하지만, 그냥 외부 함수로 정의된 operator는 인식하지 못한다. 이말은 friend로 정의된 operator를 무시한다는 것이다. 또한 assignment operator를 무시하는 데, 그 이유는 모든 객체를 레퍼런스(즉, 포인터)로 처리하는 Python으로 이 연산자를 매핑할 수 없기 때문이다. 다음 예(example/operator)를 보길 바란다.
| 코드: |
// example.i
%module example
%{
class Complex {
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)
{
if(this != &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{ return Complex(-rpart,-ipart); }
friend Complex operator+(double a, const Complex& c);
double re() const { return rpart; }
double im() const { return ipart; }
private:
double rpart, ipart;
};
Complex operator+(double a, const Complex& c) { return (c.rpart+a,c.ipart); }
%}
class Complex {
public:
Complex(double r = 0, double i = 0);
Complex(const Complex &c);
Complex &operator=(const Complex &c); // this is ignored by SWIG
Complex operator+(const Complex &c) const;
Complex operator-(const Complex &c) const;
Complex operator-() const;
double re() const;
double im() const;
};
%rename(Complex_add_dc) operator+(double a,const Complex& c);
Complex operator+(double a, const Complex& c);
|
위 인터페이스 파일을 수행하면 example.i:40: Warning(362): operator= ignored과 같이 assignment operator가 무시된다는 메시지가 화면에 출력된다. 그리고 friend 함수 역시 SWIG에서 무시되기 때문에 클래스의 선언에서 이 함수를 삭제하고, %rename 명령으로 함수명을 바꿈을 알 수 있다. 이러한 연산자를 처리하기 위해 %extend 명령을 사용할 수도 있다. %extend 명령은 매뉴얼을 참고하길 바란다. Python 인터프리터에서의 사용예는 다음과 같다.
>>> from example import *
>>> c = Complex(3,4)
>>> d = Complex(7,
>>> e = c+d
>>> e.re()
10.0
>>> e.im()
12.0
>>> f = 8.+d
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: unsupported operand type(s) for +: 'float' and 'Complex'
>>> f = Complex_add_dc(8.,d)
>>> f.re()
8.0
>>> f.im()
0.0
>>>
3.3.8. C++ template
C++ templates 에 대한 지원이 최근 SWIG에 반영되었다. Template를 사용하기 위해서는 특정 template instantiation에 대한 wrapper를 생성할 것인지 SWIG에게 알려주어야 한다. 이때 사용되는 명령이 %template 명령이다. 다음 예(exmaple/template)을 보길 바란다.
| 코드: |
%module example
%{
template<class T1, class T2>
struct pair {
T1 first;
T2 second;
pair() : first(T1(0)), second(T2(0)) {}
pair(const T1& e1, const T2& e2) : first(e1), second(e2) {}
~pair(){}
};
%}
template<class T1, class T2>
struct pair {
T1 first;
T2 second;
pair();
pair(const T1&, const T2&);
~pair();
};
%template(pairii) pair<int,int>;
|
Python 인터프리터에서의 사용예는 다음과 같다.
>>> from example import *
>>> a = pairii(1,2)
>>> a.first
1
>>> a.second
2 |
|
| 위로 |
|
 |
|
|
새로운 주제를 올릴 수 없습니다 답글을 올릴 수 없습니다 주제를 수정할 수 없습니다 올린 글을 삭제할 수 없습니다 투표를 할 수 없습니다
|
|