Python 类可以从 SWIG 包装的 C++ 类派生吗?

问题描述 投票:0回答:1

我在 Windows Linux 子系统 (WSL) Ubuntu 发行版中使用 SWIG 版本 4.0.2。 我可以包装一个 C++ 类 (

EventProcessor
),在 Python 中创建该类的实例,并将该实例提供给包装的全局 C++ 函数 (
registerEventProcessor()
)。 但是,我可以在 Python 中定义一个派生自
EventProcessor
基类的类吗?

要包装的简单 C++ 类和全局函数由以下头文件表示。

示例4.h
#pragma once

class EventProcessor
{
private:
  int m_value;

public:
  EventProcessor( void )
  : m_value( 42 )
  {
  }

  int getValue( void ) const
  {
    return m_value;
  }

  void setValue( int value )
  {
    m_value = value;
  }
};

void registerEventProcessor( int packetId, EventProcessor * pProc )
{
  if ( pProc )
  {
    // Something simple to demonstrate that the function is successful:
    // Store the given packet ID.
    pProc->setValue( packetId );
  }
}

我用来包装 C++ 代码的 SWIG 接口文件如下。

示例4.swg
%module example4

%{
  #define SWIG_FILE_WITH_INIT

  #include "example4.h"
%}

%include "example4.h"

我用来生成 C++ 包装器代码然后构建 Python 扩展模块的命令行如下。

finch@laptop:~/work/swig_example$ swig -c++ -python example4.swg
finch@laptop:~/work/swig_example$ python3 example4_setup.py build_ext --inplace
running build_ext
building '_example4' extension
... a lot of output, no errors ...

在 Python 中使用 C++ 基类 - 成功

以下演示了我可以成功创建 C++ 基类的实例并将该实例提供给全局函数。 全局函数将给定的数据包 ID 存储在实例中,我可以稍后获取。

finch@laptop:~/work/swig_example$ python3
Python 3.10.12 (main, Nov 20 2023, 15:14:05) [GCC 11.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import example4
>>> b = example4.EventProcessor()
>>> b.getValue()
42
>>> b.setValue( 20 )
>>> b.getValue()
20
>>> example4.registerEventProcessor( 30, b )
>>> b.getValue()
30

使用派生的 Python 类 - 失败

派生的 Python 类由以下文件表示。

衍生4.py
import example4

class SOFProcessor( example4.EventProcessor ):
  def __init__( self ):
    print( "SOFProcessor.ctor" )

以下是我可以创建派生Python类的实例的演示。

finch@laptop:~/work/swig_example$ python3
Python 3.10.12 (main, Nov 20 2023, 15:14:05) [GCC 11.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import example4
>>> import derived4
>>> d = derived4.SOFProcessor()
SOFProcessor.ctor

但是,我什至无法获取该实例中存储的值。

>>> d.getValue()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/finch/work/swig_example/example4.py", line 72, in getValue
    return _example4.EventProcessor_getValue(self)
TypeError: in method 'EventProcessor_getValue', argument 1 of type 'EventProcessor const *'

我也无法将该实例提供给全局函数。

>>> example4.registerEventProcessor( 100, d )
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/finch/work/swig_example/example4.py", line 83, in registerEventProcessor
    return _example4.registerEventProcessor(packetId, pProc)
TypeError: in method 'registerEventProcessor', argument 2 of type 'EventProcessor *'

一个 typedef 来覆盖......某些东西?

是否可以在 SWIG 接口文件中定义 typedef,以便可以正确包装派生 Python 类的实例并将其提供给 C++ 端?

python c++ linux swig
1个回答
0
投票

按照@MarkTolonen 的出色建议,我阅读了有关董事的文档。 在查看该文档中的示例 Python 代码时,我意识到我错过了重要的事情。

C++基类和全局函数是相同的。 SWIG 接口文件是相同的。 我用来生成 C++ 包装器代码和构建 Python 扩展模块的命令行是相同的。

解决问题的关键在于派生的Python类。 在它的

__init__()
方法中,我必须记住调用基础
__init__()
方法。

派生.py
import example4

class SOFProcessor( example4.EventProcessor ):
  def __init__( self ):
  super().__init__()
  print( "SOFProcessor.ctor" )

调用基本

__init__()
方法至关重要,因为这是调用重要的 SWIG 生成的魔术包装修复代码的地方。

  1. example4.EventProcessor.__init__()
    ,在 SWIG 自动生成的
    example4.py
    文件中定义,调用...
  2. _example4.EventProcessor_swiginit()
    ,在 SWIG 自动生成的
    example4_wrap.cxx
    文件中定义,调用...
  3. SWIG_Python_InitShadowInstance()
    ,也定义于
    example4_wrap.cxx
    ,是魔法发生的地方。 如果我领会了这一切,那就不是魔法了,不是吗?

下面是一个演示,在创建派生的 Python 类的实例后,我可以获取该实例中存储的值,并将该实例提供给全局函数。

finch@laptop:~/work/swig_example$ python3
Python 3.10.12 (main, Nov 20 2023, 15:14:05) [GCC 11.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import example4
>>> import derived4
>>> d = derived4.SOFProcessor()
SOFProcessor.ctor
>>> d.getValue()
42
>>> example4.registerEventProcessor( 100, d )
>>> d.getValue()
100
© www.soinside.com 2019 - 2024. All rights reserved.