从基*到派生*

2024-10-03 11:12:47 发布

您现在位置:Python中文网/ 问答频道 /正文

我使用SWIG向Python公开了以下c++类(简化版):

struct Component
{
    virtual void update();
}

struct DerivedComponent : public Component
{
    void update() { cout << "DerivedComponent::update()" << endl; }
    void speak() { cout << "DerivedComponent::speak()" << endl; }
}

class Entity
{
public:
    Component* component(const std::string& class_name)
    {
        return m_components[class_name];
    }

private:
    std::unordered_map<std::string, Component*> m_components;
}

现在,在Python中,我可以成功地在实体实例上调用component("DerivedComponent").update()。但是,我不能调用component("DerivedComponent").speak(),因为component("DerivedComponent")返回的类型被报告为<class 'module.Component'>。在

我显然需要下推component()函数的结果,以便调用DerivedComponent中定义的方法。我原本希望斯威格能像我所相信的那样,执行自动降速Boost.Python做。在

除了在c++中定义一大堆类型转换函数并将它们公开给Python之外,有没有更好的方法来使用Swig或Python进行向下转换呢?我有什么选择?在


Tags: namestringcomponentsupdatepublicstructclasscomponent
2条回答

在Python中,只需做一点工作,就可以完成您想要的事情。它如您所希望的那样工作,因为在Python中,由于函数的返回类型(或通常的类型)不是强类型的,因此我们可以修改您的Entity::component函数以始终返回最派生的类型,而不管它是什么。在

为用C++ + Python绑定实现这项工作,您需要为^ {CD1>}编写一个“OUT”类型映射。我写了一个例子来说明它的工作原理。在这种情况下,我们必须稍微预兆一下,因为知道将它向下转换到什么位置的唯一方法来自函数的参数。(例如,如果基类有一个以字符串/枚举形式返回的方法,则可以进一步简化该方法,而不依赖于输入参数)。在

%module test

%{
#include "test.hh"
%}

%include <std_string.i>

%typemap(out) Component * Entity::component {
    const std::string lookup_typename = *arg2 + " *";
    swig_type_info * const outtype = SWIG_TypeQuery(lookup_typename.c_str());
    $result = SWIG_NewPointerObj(SWIG_as_voidptr($1), outtype, $owner);
}

%include "test.hh"

这使用SWIG_TypeQuery函数要求Python运行时基于arg2查找类型(在您的示例中是字符串)。在

我必须对你的示例标题(名为测试.hh在我的示例中)为了在我将其制作成一个完全正常工作的演示之前解决一些问题,它最终看起来像:

^{pr2}$

然后我用:

^{3}$

有了这一点,我可以运行以下Python:

from test import *

e=Entity()
print(e)

c=e.component("DerivedComponent")
print(c)
print(type(c))

c.update()
c.speak()

正如您所希望的那样:

<test.Entity; proxy of <Swig Object of type 'Entity *' at 0xb7230458> >
Name is: DerivedComponent *, type is: 0xb77661d8
<test.DerivedComponent; proxy of <Swig Object of type 'DerivedComponent *' at 0xb72575d8> >
<class 'test.DerivedComponent'>
DerivedComponent::update()
DerivedComponent::speak()

我想做一些类似的事情,并基于this question提出了一个类似但不同的解决方案。在

如果您提前知道了可能的类型,并且不介意额外的开销,那么您可以让“out”typemap循环通过并对每个类型进行动态转换,以自动返回带有其实际类型的对象。SWIG已经为具有%factory特性的指针实现了此功能:

%factory(Component* /* or add method name. this is just the typemap filter */,
     DerivedComponent1,
     DerivedComponent2);

看着工厂.swg还有boost_-part-ptr。我把这个应用于shared-u-ptr和dynamic-tu-pointer-cast:

^{pr2}$

相关问题 更多 >