基于多态C++智能指针的SWIGH生成Python

2024-10-02 22:28:31 发布

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

我有一个C++类层次结构,我通过SWIG暴露给Python。公开的类由std::shared_ptr包装。你知道吗

我遇到的问题是Python没有公开作为基std::shared_ptr返回的派生对象上的方法。这是令人惊讶的,因为运行时似乎能够推断出对象的类型是派生的std::shared_ptr。你知道吗

当显式返回派生的std::shared_ptr时,我可以看到派生的方法。你知道吗

问题here表明,我所要做的事情可以通过使用带有typemap声明的原始指针来实现。你知道吗

我的项目h:

#pragma once

#include <memory>
#include <vector>
#include <exception>

namespace MyProg
{
    enum SubTypes
    {
        BaseType,
        DerivedAType,
        DerivedBType
    };

    class Base
    {
    public:
        virtual SubTypes SubType()
        {
            return BaseType;
        }

        virtual ~Base() {}

    protected:
        Base() {}
    };

    class DerivedA : public Base
    {
    public:
        friend class MyProg;

        int CallDerivedA()
        {
            return 1;
        }

        SubTypes SubType()
        {
            return DerivedAType;
        }

    private:
        DerivedA() : Base() {}
    };

    class DerivedB : public Base
    {
    public:

        friend class MyProg;

        int CallDerivedB()
        {
            return 2;
        }

        SubTypes SubType()
        {
            return DerivedBType;
        }

    private:
        DerivedB() : Base()
        {}
    };

    typedef std::shared_ptr<Base> BasePtr;
    typedef std::shared_ptr<DerivedA> DerivedAPtr;
    typedef std::shared_ptr<DerivedB> DerivedBPtr;

    class MyProg
    {
    public:

        MyProg()
        {
            // Create instances
            m_derivedA = std::shared_ptr<Base>(new DerivedA());
            m_derivedB = std::shared_ptr<Base>(new DerivedB());
        }

        DerivedAPtr GetDerivedA()
        {
            return std::dynamic_pointer_cast<DerivedA>(m_derivedA);
        }

        DerivedBPtr GetDerivedB()
        {
            return std::dynamic_pointer_cast<DerivedB>(m_derivedB);
        }

        BasePtr GetDerived(const SubTypes subType)
        {
            if (subType == DerivedAType)
            {
                return m_derivedA;
            }
            else if (subType == DerivedBType)
            {
                return m_derivedB;
            }
            throw std::exception("Unsupported type requested");
        }

    private:
        BasePtr m_derivedB;
        BasePtr m_derivedA;
    };
}

SWIG接口:

%module MyProg_Python

%include "typemaps.i"
%include <cpointer.i>
%include <std_shared_ptr.i>

%shared_ptr(MyProg::Base);
%shared_ptr(MyProg::DerivedA);
%shared_ptr(MyProg::DerivedB);

// I created this typemap based on the code generated for the GetDerivedA and GetDerivedB functions
%typemap(out) MyProg::Base {

    if (($1)->SubType() == MyProg::DerivedAType)
    {
        std::shared_ptr< MyProg::DerivedA > myptr = std::dynamic_pointer_cast< MyProg::DerivedA >(result);
        std::shared_ptr< MyProg::DerivedA > *smartresult = result ? &myptr : 0;
        $result = SWIG_NewPointerObj(SWIG_as_voidptr(smartresult), SWIGTYPE_p_std__shared_ptrT_MyProg__DerivedA_t, SWIG_POINTER_OWN);
    }
    else if (($1)->SubType() == MyProg::DerivedBType)
    {
        std::shared_ptr< MyProg::DerivedB > myptr = std::dynamic_pointer_cast< MyProg::DerivedB >(result);
        std::shared_ptr< MyProg::DerivedB > *smartresult = result ? &myptr : 0;
        $result = SWIG_NewPointerObj(SWIG_as_voidptr(smartresult), SWIGTYPE_p_std__shared_ptrT_MyProg__DerivedB_t, SWIG_POINTER_OWN);
    }
    else
    {
      // error
    }
}

%{
#include "MyProg.h"

using namespace std;
using namespace MyProg;
%}

%include "..\MyProg\MyProg.h"

namespace MyProg
{
    typedef std::shared_ptr<Base> BasePtr;
    typedef std::shared_ptr<DerivedA> DerivedAPtr;
    typedef std::shared_ptr<DerivedB> DerivedBPtr;
}

Python客户端:

from MyProg_Python import *
prog = MyProg()
a = prog.GetDerivedA()
result = a.CallDerivedA() # returns 1
b = prog.GetDerivedB()
result = b.CallDerivedB() # returns 2
afrombase = prog.GetDerived(DerivedAType)

# The following line doesn't resolve, even though runtime indicates afrombase  is of type MyProg_Python.DerivedA (proxy of <Swig Object of type 'std::shared_ptr<MyProg::DerivedA> * ' at 0x...>)
afrombase.CallDerivedA()

这是对共享指针的限制吗-我需要使用原始指针吗?或者是否有一个typemap声明允许我在Python中公开多态行为?你知道吗


Tags: basereturnincluderesultpublicclassswigshared