سؤال

المشكلة: لقد قمت بلف بعض كود C ++ في Python باستخدام SWIG. على جانب Python ، أريد أن آخذ مؤشر C ++ ملفوف وأسفله ليكون مؤشرًا إلى فئة فرعية. لقد أضفت وظيفة C ++ جديدة إلى ملف SWIG .I الذي يقوم بهذا الصب ، لكن عندما أسميها من Python ، أحصل على نوع من النوع.

التفاصيل هنا:

لدي فئتان C ++ ، قاعدة ومشتقة. المشتقة هي فئة فرعية من القاعدة. لدي فئة ثالثة وحاوية تحتوي على مشتقة وتوفر ملحقًا لها. يرجع الملحق المشتق كقاعدة const و ، كما هو موضح:

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

  private:
    Derived derived_;
};

لقد لفت هذه الفصول في Python باستخدام Swig. في رمز Python الخاص بي ، أود أن أؤدي إلى أسفل المرجع الأساسي لأسفل إلى أحد المشتقة. للقيام بذلك ، لقد كتبت في Swig .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 *'

لماذا يمكن أن يحدث هذا؟

للرجوع إليها ، إليك البتات ذات الصلة من ملف .cxx الذي تم إنشاؤه بواسطة SWIG ؛ وهي الوظيفة الأصلية ، و python-interface 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;
}

أي مساعدة سيكون موضع تقدير كبير.

-- غير لامع

هل كانت مفيدة؟

المحلول

كما علقت أعلاه ، يبدو أن هذا يعمل بشكل جيد مع SWIG 1.3.40.

ها هي ملفاتي:

الفصل:

#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

نصائح أخرى

2 أشياء لاحظتها في الكود الأول getBase إرجاع إشارة إلى const والثاني الذي يتوقع CastToderived مؤشر إلى قاعدة غير محصنة.

حتى في C ++ سيكون لديك مشكلة كافية في عمل هذا العمل. لا أستطيع أن أقول ما الذي يجب أن يكون الخطأ ، لكنني سأحاول الحصول على هذا FXIED أولاً.

هل من الممكن أن تحدد الفئة الأساسية عدة مرات؟ لقد واجهت مشاكل مماثلة مع Ctypes حيث قمت بتعريف فئة الهيكل نفسها عن غير قصد في وحدتين مختلفتين. لقد حدث أيضًا شيء مشابه في Python Pure ، حيث استخدمت IMP.LOAD_MODULE لتحميل فئة مكون الإضافي ، أنشأت كائنًا من تلك الفئة ، ثم أعد تحميل الوحدة النمطية - POOF! لم يعد الكائن الذي تم إنشاؤه اجتياز اختبار Isinstance للفصل ، نظرًا لأن الفئة المعاد تحميلها ، على الرغم من أنها كانت ذات نفس الاسم ، كانت فئة مختلفة ، مع معرف مختلف. (وصف أكثر اكتمالا في إدخال المدونة هذا.)

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top