I have a tale of 6 classes: 3 managed and 3 native. The 3 managed classes are ManagedChildA
, ManagedChildB
and ManagedParent
.
ManagedChildA
, ManagedChildB
both inherit from ManagedParentA
.
The 3 nativeclasses are NativeChildA
, NativeChildB
and NativeParent
.
NativeChildA
, NativeChildB
both inherit from NativeParentA
.
Moreover, ManagedChildA
wraps NativeChildB
, ManagedChildB
wraps ManagedChildB
and ManagedParentA
wraps NativeParentA
.
Now here the tale gows awry:
ManagedParentA has a method called ManagedExecute() that wraps NativeParentA's NativeExecute(). When this method is called, everything runs smoothly.
NativeChildB, ManagedChildB override ManagedExecute() to provide their own implementations, with ManagedChildA::ManagedExecute() wrapping NativeChildA::NativeExecute() and ManagedChildB::ManagedExecute() wrapping NativeChildB::NativeExecute().
When for example the overriden ManagedExecute() of ManagedChildA is called, NativeChildA::NativeExecute() gets called albeit with a System.AccessViolation error. That is, the pointer to the original parent of NativeChildA cannot be located.
I guess the pointer has been moved from its original address. I read on the internet, I have to pin pointers to prevent the Garbage Collector (GC) from moving memory around but I don't know what to pin, since the exception gets thrown at the native level. Any useful hints?
Example:
//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
{
publi开发者_如何转开发c:
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
}
The snippet is very low quality, it is littered with uncompilable code. No repro once I fixed all the mistakes.
#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
}
精彩评论