我有一个通过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中公开多态行为?