2010-10-13 35 views
5

問題:我使用SWIG在python中包裝了一些C++代碼。在python方面,我想要一個包裝的C++指針,並將其向下轉換成一個指向子類的指針。我已經向SWIG.i文件添加了一個新的C++函數來執行這種向下轉換,但是當我從python調用它時,我得到一個TypeError。如何從Python SWIG包裝中下載C++對象?

下面是詳細信息:

我有兩個C++類,基類和派生。派生是Base的一個子類。我有第三個類Container,它包含Derived,併爲其提供訪問者。存取器返回導出一個const基地&,如圖所示:

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

    private: 
    Derived derived_; 
}; 

我使用包裹在SWIG蟒這些類。在我的python代碼中,我想將Base參考向下放到Derived。要做到這一點,我已經寫進痛飲.i文件在C++中它執行下鑄造的輔助功能:

%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文件的相關位;即原有的功能,它的蟒蛇接口,指明分數分身:

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; 
} 

任何幫助將不勝感激。

- 馬特

+0

什麼是對GetBase生成的代碼()是什麼樣子?該錯誤意味着傳遞給CastToDerived的對象不是正確的類型 - 它是什麼類型? – 2010-10-13 12:28:35

+0

爲什麼它的價值,我只是試圖創建一個基於上述的例子,使用swig 1.3.40,我沒有得到這個錯誤。 – 2010-10-13 12:45:20

+0

很奇怪......我試着寫一些類似你的例子的東西,克里斯,而且確實有效。正如你所預料的那樣,我實際遇到的代碼並不是玩具問題,我只是玩弄它,以使它足夠短以適應一個問題。我當前的解決方法是在我的C++庫中定義CastToDerived函數,而不是在.i文件中的%inline%{...%}塊中。這解決了這個問題。也許這個細節可能是對正確人物的暗示?我仍然希望我可以不用將SWIG助手添加到我的C++庫中。 – SuperElectric 2010-10-13 22:33:08

回答

3

正如我上面評論的那樣,這似乎與swig 1.3.40一致。

這裏是我的文件:

c.h:

#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_; 
}; 

C.I

%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 
0

2的事情,我在你的代碼1 GetBase注意到返回引用爲const和第二的是CastToDerived需要一個指向非const基地。

即使在C++中,您也有足夠的麻煩來完成這項工作。我不知道還有什麼應該是錯誤的,但我會試着首先得到這個fxied。

+0

這不是問題,我想。原來的CastToDerived接受了一個const引用,並返回了一個const指針,正如您所想的那樣。即使那樣,我也有同樣的錯誤。 SWIG獲取所有引用並將它們轉換爲指針,並刪除常量。這就是爲什麼我的CastToDerived現在接受並返回非const指針。回覆:swig docs here:http://www.swig.org/Doc2.0/SWIGPlus.html#SWIGPlus_nn18和這裏:http://www.swig.org/Doc2.0/SWIGPlus.html#SWIGPlus_const – SuperElectric 2010-10-13 07:08:59

0

是否有可能多次定義Base類?我遇到過類似ctypes的問題,我無意中在兩個不同的模塊中定義了相同的結構類。我在純Python中也發生過類似的事情,我使用imp.load_module加載插件類,創建該類的對象,然後重新加載模塊 - poof!創建的對象將不再通過該類的isinstance測試,因爲重新加載的類即使具有相同的名稱也是不同的類,具有不同的id。 (在this blog entry中有更完整的描述。)