如何将c++类转换为托管类并在其中调用纯虚函数?



看起来是这样的

#include <stdio.h>
#define __dllexport extern "C" __declspec(dllexport) 
class PureVirtual
{
public:
    virtual void Foo() = 0;
};
class ImplPureVirtual : public PureVirtual
{
public:
    void Foo()
    {
        printf("Moo");
    }
};
__dllexport PureVirtual* GetPV();
在实现:

#include "ManagedClass.h"
PureVirtual* impl = new ImplPureVirtual;
__dllexport PureVirtual* GetPV()
{
    return impl;
}

编译为TestFoo.dll,然后在c#中

class Program
{
    [DllImport("kernel32.dll")]
    public static extern IntPtr LoadLibrary(string strFileName);
    [DllImport("kernel32.dll")]
    public static extern IntPtr GetProcAddress(IntPtr hModule, string strProcName);
    static void Main(string[] args)
    {
        var ptrLib = LoadLibrary("TestFoo.dll");
        if (ptrLib != IntPtr.Zero)
        {
            var ptrAddr = GetProcAddress(ptrLib, "GetPV");
            if (ptrAddr != IntPtr.Zero)
                // Now we have the pointer object, what should I do next?
        }
        Console.ReadLine();
    }
}

我认为这是一个相当好的问题,如果一个软件公司向公众发布他们的非托管API(只有纯虚拟方法),如果我们可以控制c++抽象和多态性的智慧,那么我们可以把它变成托管的,并有几个好处!例如垃圾控制,泛型,以及广泛的引用和库选择。

还需要为每个虚成员定义一个extern "C"函数;由于c++名称混淆,托管代码不能以一种简单或可移植的方式调用非托管c++导出。例如:

__dllexport void PureVirtual_Foo(PureVirtual * pv)
{
    pv->Foo();
}

另外,考虑到您需要在extern "C"包装器中捕获c++异常,因为未捕获的异常可能跳过托管堆栈帧,导致CLR进入坏状态。

我强烈建议您考虑使用SWIG。它能够自动为您生成这些包装器。


注意,你不需要使用LoadLibrary()等,你可以只p/调用函数:

[DllImport("TestFoo")]
public static extern IntPtr GetPV();
同样地,调用我的示例包装器中的虚方法:
[DllImport("TestFoo")]
public static extern void PureVirtual_Foo(IntPtr pv);

那么你可以像这样调用虚方法:

PureVirtual_Foo(GetPV());

最新更新