我正在尝试在C ++中初始化对C#传递的boost共享指针的引用,同时尝试维护继承树。我希望能够在C#中创建一个变量,然后将其传递给我的DLL,它将在内部实例化它(这样我就可以在同一个上下文中管理所有内存分配)。
这是我的C ++测试用例(在文件SwigTest.h中):
#include <string>
#include <boost/shared_ptr.hpp>
template<class T>
using SRef = boost::shared_ptr<T>;
class FactoryClass
{
public:
FactoryClass() {}
~FactoryClass() {}
//Normally I would only like to use the return value, but SWIG uses polymorphism to simulate templates
//and polymorphism on the return type only is not supported by C#. (I get a Identifier 'getReference' redefined error on SwigTest.i compilation).
//So I thought I’d pass the SRef& as a parameter instead of having no parameters at all.
template <class T>
static SRef<T> getReference( SRef<T>& inout ) { inout = SRef<T>( new T(1) ); return inout; }
void testing( int& toto ) {};
};
class BaseClass
{
public:
BaseClass() { m_flag = -1; };
BaseClass(int i) { m_flag = i; };
virtual ~BaseClass() {};
virtual std::string getName() = 0;
int m_flag;
};
class FirstClass : public BaseClass
{
public:
FirstClass() {};
FirstClass(int i) : BaseClass( i ) {};
virtual ~FirstClass() {};
virtual std::string getName() { return "First Class"; };
};
class SecondClass : public BaseClass
{
public:
SecondClass() {};
SecondClass(int i) : BaseClass( i ) {};
virtual ~SecondClass() {};
virtual std::string getName() { return "Second Class"; };
};
这是我当前的SWIG界面文件:
%module SwigTest
%include "std_string.i"
%include "boost_shared_ptr.i"
%{
#include "../include/SwigTest.h"
%}
%shared_ptr( BaseClass );
%shared_ptr( FirstClass );
%shared_ptr( SecondClass );
%include "../include/SwigTest.h"
%template(BoostBasePtr) boost::shared_ptr<BaseClass>;
%template(SharedBase) SRef<BaseClass>;
%template(BoostFirstPtr) boost::shared_ptr<FirstClass>;
%template(SharedFirst)SRef<FirstClass>;
%template(getReference)FactoryClass::getReference<FirstClass>;
%template(BoostSecondPtr) boost::shared_ptr<SecondClass>;
%template(SharedSecond)SRef<SecondClass>;
%template(getReference)FactoryClass::getReference<SecondClass>;
这是C#中的有效和无效的内容:
public class SwigInterface
{
private FirstClass m_first;
private SecondClass m_second = new SecondClass(-2);
void TestSwig ()
{
m_first = FactoryClass.getReference( m_first ); //The returned reference is copied from C++
FactoryClass.getReference( m_second ); //m_second is never changed
FirstClass anotherFirst = new FirstClass(-1) ;
BaseClass bc = FactoryClass.getReference( anotherFirst); //bc does equal the new instance of FirstClass but anotherFirst is not correctly replaced
//This is the case I would ideally want to use
SecondClass nothing ;
FactoryClass.getReference( nothing ) ; //NullReferenceException (because the SWIG generated interface uses nothing.CPtr() to pass by pointer as it does with all refs).
}
}
我尝试了很多%typename
体操用FactoryClass.getReference( FirstClass )
取代FactoryClass.getReference( out FirstClass )
的签名(甚至是引用FirstClass),但我找不到合适的方法。< / p>
在一个完美的世界中,我只想在C#中的FactoryClass中生成void getReference<T>( ref T inout )
,但即使使用SWIG %extend
关键字添加方法也不会生成它,因为我必须实例化我需要的每个模板。
答案 0 :(得分:0)
如果我理解您的观点,那么您已达到SWIG限制。我遇到了同样的问题。每个指针(智能或非智能)在C#中丢失一次多态性。
您需要使用%pragma(csharp)指令为C#端的 BaseClass 提供特殊工厂。然后你需要用你的csout类型映射映射你的指针:
%typemap(csout, excode=SWIGEXCODE)
BaseClass*, std::shared_ptr<BaseClass>, std::shared_ptr<BaseClass> & {
System.IntPtr cPtr = $imcall;
// The following line is a call to your special factory
BaseClass ret = $imclassname.createBaseClass(cPtr, $owner);$excode
return ret;
}
你的工厂可能是这样的:
%pragma(csharp) imclasscode=%{
public static BaseClass createBaseClass(System.IntPtr cPtr, bool owner)
{
BaseClass ret = null;
if (cPtr == System.IntPtr.Zero) {
return ret;
}
string name = ($imclassname.BaseClass_getName(new System.Runtime.InteropServices.HandleRef(null, cPtr)));
switch (name)
{
case "First Class":
return new FirstClass(cPtr, owner);
case "Second Class":
return new SecondClass(cPtr, owner);
default:
return null;
}
}
%}
我没有对它进行测试,也许有些事情要改变或适应。但它应该有用。