5

問題:SWIGを使用してPythonでいくつかのc++コードをラップしました。Python側では、ラップされたc ++ポインターを取得し、それをサブクラスへのポインターとしてダウンキャストしたいと思います。このダウンキャストを行う新しいc++関数をSWIG.iファイルに追加しましたが、Pythonから呼び出すと、TypeErrorが発生します。

詳細は次のとおりです。

BaseとDerivedの2つのc++クラスがあります。DerivedはBaseのサブクラスです。3番目のクラスであるContainerがあります。これには、Derivedが含まれており、それにアクセサーを提供します。アクセサは、次のようにDerivedをconst Base&として返します。

class Container {
  public:
    const Base& GetBase() const {
      return derived_;
    }

  private:
    Derived derived_;
};

SWIGを使用してこれらのクラスをPythonでラップしました。私のPythonコードでは、Base参照をDerivedにダウンキャストしたいと思います。これを行うために、ダウンキャストを行うc++のヘルパー関数をswig.iファイルに書き込みました。

%inline %{
  Derived* CastToDerived(Base* base) {
    return static_cast<Derived*>(base);
  }
%}

私のPythonコードでは、次のダウンキャスト関数を呼び出します。

base = container.GetBase()
derived = CastToDerived(base)

これを行うと、次のエラーが発生します。

TypeError: in method 'CastToDerived', argument 1 of type 'Base *'

なぜこれが起こっているのでしょうか?

参考までに、SWIGによって生成された.cxxファイルの関連ビットを次に示します。つまり、元の関数とそのpython-interface-ified doppelganger:

  Derived* CastToDerived(Base* base) {
    return static_cast<Derived*>(base);
  }

//  (lots of other generated code omitted)

SWIGINTERN PyObject *_wrap_CastToDerived(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
  PyObject *resultobj = 0;
  Base *arg1 = (Base *) 0 ;
  void *argp1 = 0 ;
  int res1 = 0 ;
  PyObject * obj0 = 0 ;
  Derived *result = 0 ;

  if (!PyArg_ParseTuple(args,(char *)"O:CastToDerived",&obj0)) SWIG_fail;
  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_Base, 0 |  0 );
  if (!SWIG_IsOK(res1)) {
    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "CastToDerived" "', argument " "1"" of type '" "Base *""'"); 
  }
  arg1 = reinterpret_cast< Base * >(argp1);
  result = (Derived *)CastToDerived(arg1);
  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_Derived, 0 |  0 );
  return resultobj;
fail:
  return NULL;
}

どんな助けでも大歓迎です。

-マット

4

3 に答える 3

3

上でコメントしたように、これはswig1.3.40で問題なく動作するようです。

これが私のファイルです:

ch:

#include <iostream>
class Base {};
class Derived : public Base
{
    public:
        void f() const { std::cout << "In Derived::f()" << std::endl; }
};
class Container {
  public:
    const Base& GetBase() const {
      return derived_;
    }
  private:
    Derived derived_;
};

ci

%module c

%{
#define SWIG_FILE_WITH_INIT
#include "c.h"
%}

%inline %{
  Derived* CastToDerived(Base* base) {
    return static_cast<Derived*>(base);
  }
%}
class Base
{
};

class Derived : public Base
{
    public:
        void f() const;
};

class Container {
  public:
    const Base& GetBase() const;
};

ctest.py

import c

container = c.Container()
b = container.GetBase()
d = c.CastToDerived(b)
d.f()
print "ok"

実行:

$ swig -c++ -python c.i
$ g++ -fPIC -I/usr/include/python2.6 -c -g c_wrap.cxx
$ g++ -shared -o _c.so c_wrap.o
$ python ctest.py 
In Derived::f()
ok
于 2010-10-13T12:56:15.530 に答える
0

あなたのコードで私が気付いた2つのこと1番目のGetBaseはconstへの参照を返し、2番目はCastToDerivedが非constBaseへのポインターを期待していることです。

C ++でも、これを機能させるのに十分な問題があります。他に何が間違っているのかわかりませんが、最初にこれを修正しようとします。

于 2010-10-13T06:45:50.187 に答える
0

Baseクラスを複数回定義している可能性はありますか?2つの異なるモジュールで同じ構造体クラスを無意識のうちに定義したctypesでも同様の問題が発生しました。純粋なPythonでも同様のことが起こりました。ここでは、imp.load_moduleを使用してプラグインクラスをロードし、そのクラスのオブジェクトを作成してから、モジュールをリロードしました--poof!再ロードされたクラスは、同じ名前であっても、IDが異なる別のクラスであったため、作成されたオブジェクトはクラスのisinstanceテストに合格しなくなりました。(このブログエントリのより完全な説明。)

于 2010-10-13T09:51:14.717 に答える