共享指针与SIP4构建(原:SWIG/python中的动态类型转换?)

3 投票
1 回答
720 浏览
提问于 2025-04-16 01:04

我正在玩Python、C++0x和SWIG 2.0。我的头文件长这样:

#include <string>
#include <iostream>
#include <memory>
using namespace std;

struct Base {
  virtual string name();
  int foo;
  shared_ptr<Base> mine;
  Base(int);  
  virtual ~Base() {}
  virtual void doit(shared_ptr<Base> b) {
    cout << name() << " doing it to " << b->name() << endl;
    mine = b;
  }
  virtual shared_ptr<Base> getit() {
    return mine;
  }
};

struct Derived : Base {
  virtual string name();
  int bar;
  Derived(int, int);
};

与此同时,接口文件看起来是这样的:

%module(directors="1") foo
%feature("director");

%include <std_string.i>

%include <std_shared_ptr.i>
%shared_ptr(Base)
%shared_ptr(Derived)

%{
#define SWIG_FILE_WITH_INIT
#include "foo.hpp"
%}

%include "foo.hpp"

我的Python会话是这样的:

>>> import foo
>>> b = foo.Base(42)
>>> d = foo.Derived(23,64)
>>> b.doit(d)
Base doing it to Derived 
>>> g = b.getit()
>>> g
<foo.Base; proxy of <Swig Object of type 'std::shared_ptr< Base > *' at 0x7f7bd1391930> >
>>> d
<foo.Derived; proxy of <Swig Object of type 'std::shared_ptr< Derived > *' at 0x7f7bd137ce10> >
>>> d == g
False
>>> d is g
False
>>> d.foo == g.foo
True
>>> d.bar
64
>>> g.bar
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Base' object has no attribute 'bar'

我似乎无法找到如何获取“原始”的代理对象。我是否必须为每一个基类都写一个函数来执行dynamic_pointer_cast? 如果是这样,那么在Python中实现的Director子类该怎么办呢?

我感觉这里有一个开关或功能可以打开,让SWIG进行必要的表查找并生成我想要的对象,但我还没有找到。

(注意:如果我使用原始指针而不是共享指针,行为是类似的,我也搞不清楚如何让SWIG对这些进行dynamic_cast

更新

如果在SWIG中无法实现这种行为(特别是从一个持有基类指针的C++容器类中获取最派生的代理),那么使用SIP或其他Python的包装生成器怎么样?

更新 #2

由于SIP4在获取包装对象方面似乎表现得更好,我会再次修改问题。请查看我下面的自我回答,了解我当前的问题。我仍然会接受关于原始SWIG问题的好答案,因为我总体上更喜欢它,但我现在的新问题基本上是:

  • 我如何合理地处理围绕shared_ptr的包装,而不是原始指针?如果有帮助,我所有的类都从它们的通用基类继承enable_shared_from_this,并暴露一个合适的函数来获取共享指针。

  • 我如何使用SIP4的构建系统(Makefile生成器或distutils扩展),在不需要先生成和安装共享库或手动编辑生成的Makefile的情况下,构建我的小示例项目?

1 个回答

0

为了部分回答我自己的问题,SIP似乎在处理C++的“派生”类和Python的子类时都表现得不错——至少在我使用原始指针的时候是这样。

看起来我需要弄清楚如何让它与shared_ptr一起工作(这似乎没有在SWIG中使用%include <std_shared_ptr.i>那么简单)。

另外,SIP的两个“构建系统”选项(Makefile生成器和distutils扩展)看起来也有点奇怪。他们手册中的示例没有一个是“直接就能用”的——他们似乎认为你应该很清楚地知道需要在你的库/包含路径中编译和安装一个共享库和头文件,以便为你想要包装的小Hello World库使用。也许我错过了一个“我只想在这里构建和运行这个自包含的东西”的选项,但即使是python setup.py build_ext --inplace也失败了,因为它找不到我放在当前目录中的被包装头文件,显然这个地方对它来说是个困惑的选择,我知道。

撰写回答