如何在C ++ / CLI中使用boost :: bind绑定托管类的成员
时间:2020-03-06 15:02:28 来源:igfitidea点击:
我在本机C ++类中使用boost :: signal,现在我在C ++ / CLI中编写.NET包装器,以便可以将本机C ++回调公开为.NET事件。当我尝试使用boost :: bind来获取托管类的成员函数的地址时,出现编译器错误3374,表示除非获得委托实例,否则无法获取成员函数的地址。有谁知道如何使用boost :: bind绑定托管类的成员函数?
为了澄清起见,以下示例代码会导致编译器错误3374:
#include <boost/bind.hpp> public ref class Managed { public: Managed() { boost::bind(&Managed::OnSomeEvent, this); } void OnSomeEvent(void) { } };
解决方案
经过更多搜索之后,我终于找到了一篇不错的博客文章,介绍了如何执行此操作。那篇文章中的代码比我需要的多了一点,但是主要的要点是使用全局自由函数,该函数接受包装在gcroot <>模板中的托管指针的参数。有关示例,请参见下面的代码中的SomeEventProxy(...)。然后,此函数转过来并调用我尝试绑定的受管成员。我的解决方案显示在下面,以供将来参考。
#include <msclr/marshal.h> #include <boost/bind.hpp> #include <boost/signal.hpp> #include <iostream> #using <mscorlib.dll> using namespace System; using namespace msclr::interop; typedef boost::signal<void (void)> ChangedSignal; typedef boost::signal<void (void)>::slot_function_type ChangedSignalCB; typedef boost::signals::connection Callback; class Native { public: void ChangeIt() { changed(); } Callback RegisterCallback(ChangedSignalCB Subscriber) { return changed.connect(Subscriber); } void UnregisterCallback(Callback CB) { changed.disconnect(CB); } private: ChangedSignal changed; }; delegate void ChangeHandler(void); public ref class Managed { public: Managed(Native* Nat); ~Managed(); void OnSomeEvent(void); event ChangeHandler^ OnChange; private: Native* native; Callback* callback; }; void SomeEventProxy(gcroot<Managed^> This) { This->OnSomeEvent(); } Managed::Managed(Native* Nat) : native(Nat) { native = Nat; callback = new Callback; *callback = native->RegisterCallback(boost::bind( SomeEventProxy, gcroot<Managed^>(this) ) ); } Managed::~Managed() { native->UnregisterCallback(*callback); delete callback; } void Managed::OnSomeEvent(void) { OnChange(); } void OnChanged(void) { Console::WriteLine("Got it!"); } int main(array<System::String ^> ^args) { Native* native = new Native; Managed^ managed = gcnew Managed(native); managed->OnChange += gcnew ChangeHandler(OnChanged); native->ChangeIt(); delete native; return 0; }
当答案起作用时,它将向世界展示某些实现(Managed :: OnSomeEvent)。如果我们不希望人们通过调用OnSomeEvent()随意引发OnChange事件,则可以如下更新Managed类(基于此建议):
public delegate void ChangeHandler(void); typedef void (__stdcall *ChangeCallback)(void); public ref class Managed { public: Managed(Native* Nat); ~Managed(); event ChangeHandler^ OnChange; private: void OnSomeEvent(void); Native* native; Callback* callback; GCHandle gch; }; Managed::Managed(Native* Nat) : native(Nat) { callback = new Callback; ChangeHandler^ handler = gcnew ChangeHandler( this, &Managed::OnSomeEvent ); gch = GCHandle::Alloc( handler ); System::IntPtr ip = Marshal::GetFunctionPointerForDelegate( handler ); ChangeCallback cbFunc = static_cast<ChangeCallback>( ip.ToPointer() ); *callback = native->RegisterCallback(boost::bind<void>( cbFunc ) ); } Managed::~Managed() { native->UnregisterCallback(*callback); delete callback; if ( gch.IsAllocated ) { gch.Free(); } } void Managed::OnSomeEvent(void) { OnChange(); }
请注意,使用了另一种bind <R>()
形式。