파이썬 마을 게시판 인덱스 파이썬 마을
우리나라 파이썬 사용자들의 이야기 마을
 
 FAQFAQ   검색검색   멤버리스트멤버리스트   사용자 그룹사용자 그룹   사용자 등록하기사용자 등록하기 
 개인 정보개인 정보   비공개 메시지를 확인하려면 로그인하십시오비공개 메시지를 확인하려면 로그인하십시오   로그인로그인 
Google
python.or.kr Web

[SWIG강좌] 3.3 C++에서의 사용 (3)

 
글 쓰기   답변 달기    파이썬 마을 게시판 인덱스 -> 파이썬 팁/강좌/모듈소개 모음
이전 주제 보기 :: 다음 주제 보기  
글쓴이 메시지
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,Cool
>>> 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
위로
사용자 정보 보기 비밀 메시지 보내기    
이전 글 표시:   
글 쓰기   답변 달기    파이썬 마을 게시판 인덱스 -> 파이썬 팁/강좌/모듈소개 모음 시간대: GMT + 9 시간(한국)
페이지 11

 
건너뛰기:  
새로운 주제를 올릴 수 없습니다
답글을 올릴 수 없습니다
주제를 수정할 수 없습니다
올린 글을 삭제할 수 없습니다
투표를 할 수 없습니다



Powered by phpBB © 2001, 2005 phpBB Group
회선/장비: Daum DNA , 관리: 장혜식,서상현