簡體   English   中英

使用SWIG初始化對C ++中C#共享指針的引用

[英]Initialize a reference to a C# shared pointer from C++ using SWIG

我試圖在C ++中初始化對從C#傳遞的boost共享指針的引用,同時嘗試維護繼承樹。 我希望能夠在C#中創建一個變量,然后將其傳遞給我的DLL,該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),但我找不到正確的方法。

在理想情況下,我只想在C#的FactoryClass中生成一個void getReference<T>( ref T inout ) ,但是即使使用SWIG %extend關鍵字添加該方法也不會生成它,因為我必須實例化每個我需要的模板。

如果我理解您的觀點,那么您已經達到了上限。 我也遇到過同樣的問題。 每個指針(無論是否智能)都在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;
        }
    }
%}

我沒有測試過,也許有些事情需要改變或適應。 但它應該起作用。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM