在C ++ / CLI中通过包装器(派生的托管类)调用派生本机类的重写方法

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在C ++ / CLI中通过包装器(派生的托管类)调用派生本机类的重写方法相关的知识,希望对你有一定的参考价值。

我有6个班级的故事:3个托管和3个原生。 3个管理类是ManagedChildAManagedChildBManagedParent

ManagedChildAManagedChildB都继承自ManagedParentA

3个本地课程是NativeChildANativeChildBNativeParent

NativeChildANativeChildB都继承自NativeParentA

此外,ManagedChildA包裹NativeChildBManagedChildB包裹ManagedChildBManagedParentA包裹NativeParentA

现在这个故事发出了错误:

ManagedParentA有一个名为ManagedExecute()的方法,它包装了NativeParentA的NativeExecute()。调用此方法时,一切都顺利进行。

NativeChildB,ManagedChildB重写ManagedExecute()以提供自己的实现,ManagedChildA :: ManagedExecute()包装NativeChildA :: NativeExecute()和ManagedChildB :: ManagedExecute()包装NativeChildB :: NativeExecute()。

例如,当调用ManagedChildA的重写ManagedExecute()时,尽管出现System.AccessViolation错误,但仍会调用NativeChildA :: NativeExecute()。也就是说,无法找到指向NativeChildA原始父级的指针。

我猜指针已从其原始地址移开。我在互联网上阅读,我必须指针防止垃圾收集器(GC)移动内存,但我不知道要固定什么,因为异常会在本机级别抛出。任何有用的提示?

例:

//C++ -native classes
class NativeFoo
{
  public:
  NativeFoo(): tested(true){}
  virtual void execute()
  {
     std::cout << "Native Foo" << std::endl;
  }

  protected:
  bool tested;

 };


 class NativeBarA :NativeFoo
 {
  public:
  NativeBarA(): NativeFoo(){}
  void execute()
  {
     std::cout << "Native Bar A" << std::endl;
  }
 };

 class NativeBarB : public NativeFoo
 {
  public:
  NativeBarB() :NativeFoo(){}
  void execute()
  {
     std::cout << "Native Bar B" << std::endl;
  }
 };

//CLI interface
 public interface class IExecutable
 {
     public:
       Execute();
 }

//C++-CLI classes 
public ref class ManagedFoo: public IExecutable
{

  private:
  NativeFoo* impl;

  public:

 ManagedFoo(): impl(NULL)
 {
  impl = new NativeFoo();
 }

 void __clrcall Execute()
 {
  impl->execute(); 
 }
};

public ref class ManagedBarA: public ManagedFoo
{

  private:
  NativeBarA* impl;

  public:

 ManagedBarA(): ManagedFoo(), impl(NULL)
 {
  impl = new NativeBarA();
 }

 void __clrcall Execute() override
 {
  impl->execute(); 
 }
};

public ref class ManagedBarB: public ManagedFoo
{

  private:
  NativeBarB* impl;

  public:

 ManagedBarB(): ManagedFoo(), impl(NULL)
 {
  impl = new NativeBarB();
 }

 void __clrcall Execute() override
 {
  impl->execute(); 
 }
};


//Calling code
[STAThread]
static void Main()
{
   ManagedFoo^ mfoo = gcnew ManagedFoo();
   ManagedBarA  mbarA = gcnew ManagedBarA();
   ManagedBarB  mbarB = gcnew ManagedBarB();
   mfoo->Execute(); //OK
   mbarA->Execute(); //Error. Debugger sees value of tested as false
   mBarB->Execute(); //Error
}
答案

该代码片段质量非常低,充斥着无法编译的代码。一旦我解决了所有的错误,就没有责任了。

#include "stdafx.h"
#include <iostream>
using namespace System;

//C++ -native classes
class NativeFoo
{
public:
    NativeFoo(): tested(true){}
    virtual void execute()
    {
        std::cout << "Native Foo" << std::endl;
    }

protected:
    bool tested;

};


class NativeBarA :NativeFoo
{
public:
    NativeBarA(): NativeFoo(){}
    void execute()
    {
        std::cout << "Native Bar A" << std::endl;
    }
};

class NativeBarB : public NativeFoo
{
public:
    NativeBarB() :NativeFoo(){}
    void execute()
    {
        std::cout << "Native Bar B" << std::endl;
    }
};

//CLI interface
public interface class IExecutable
{
public:
    void Execute();
};

//C++-CLI classes 
public ref class ManagedFoo: public IExecutable
{

private:
    NativeFoo* impl;

public:

    ManagedFoo(): impl(NULL)
    {
        impl = new NativeFoo();
    }

    virtual void Execute()
    {
        impl->execute(); 
    }
};

public ref class ManagedBarA: public ManagedFoo
{

private:
    NativeBarA* impl;

public:

    ManagedBarA(): ManagedFoo(), impl(NULL)
    {
        impl = new NativeBarA();
    }

    virtual void __clrcall Execute() override
    {
        impl->execute(); 
    }
};

public ref class ManagedBarB: public ManagedFoo
{

private:
    NativeBarB* impl;

public:

    ManagedBarB(): ManagedFoo(), impl(NULL)
    {
        impl = new NativeBarB();
    }

    virtual void __clrcall Execute() override
    {
        impl->execute(); 
    }
};


//Calling code
[STAThread]
int main(array<System::String ^> ^args)
{
    ManagedFoo^ mfoo = gcnew ManagedFoo();
    ManagedBarA^  mbarA = gcnew ManagedBarA();
    ManagedBarB^  mbarB = gcnew ManagedBarB();
    mfoo->Execute(); //OK
    mbarA->Execute(); //Fine
    mbarB->Execute(); //Fine
}

以上是关于在C ++ / CLI中通过包装器(派生的托管类)调用派生本机类的重写方法的主要内容,如果未能解决你的问题,请参考以下文章

通过 CLI 包装器在非托管 C++ 中使用 C#.NET Winform - 需要线程?

在Visual Studio 2010中将Native / C ++ DLL链接到托管C ++ / CLI包装器

使用 C++/CLI 包装器将二维数组从 C# 传递到非托管 C++

C# 使用 CLI 包装器调用非托管 C++

从 .NET 代码中销毁非托管对象

用 C++/CLI 包装非托管 C++ - 一种正确的方法