SWIG生成的带有多态C ++智能指针的Python

时间:2019-03-20 14:10:15

标签: python c++ swig

我有一个通过SWIG向Python公开的C ++类层次结构。公开的类由std::shared_ptr包装。

我遇到的问题是Python不会公开作为基础std::shared_ptr返回的派生对象的方法。这令人惊讶,因为运行时似乎能够推断出该对象是派​​生的std::shared_ptr类型。

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

问题here表明,使用带类型映射声明的原始指针可以实现我正在尝试做的事情。

MyProg.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()

shared_ptr是否有限制-我需要使用原始指针吗?还是有一个typemap声明允许我在Python中公开多态行为?

0 个答案:

没有答案