У меня сказка о 6 классах: 3 управляемых и 3 родных. 3 управляемых класса: ManagedChildA
, ManagedChildB
и ManagedParent
.
ManagedChildA
, ManagedChildB
оба наследуются от ManagedParentA
.
3 нативных класса: NativeChildA
, NativeChildB
и NativeParent
.
NativeChildA
, NativeChildB
оба наследуются от NativeParentA
.
Более того, ManagedChildA
обертывания NativeChildB
, ManagedChildB
обертывания ManagedChildB
и ManagedParentA
обертывания NativeParentA
.
Теперь здесь сказка кричит:
ManagedParentA имеет метод ManagedExecute (), который оборачивает NativeExecute () в NativeParentA. Когда вызывается этот метод, все работает гладко.
NativeChildB, ManagedChildB переопределяют ManagedExecute () для предоставления своих собственных реализаций, с помощью обертки ManagedChildA :: ManagedExecute (), NativeChildA :: NativeExecute () и ManagedChildB :: ManagedExecute (), обертывания NativeChildB :: NativeExecute ().
Когда, например, вызывается переопределенный ManagedExecute () ManagedChildA, NativeChildA :: NativeExecute () вызывается, хотя и с ошибкой System.AccessViolation. То есть указатель на исходный родительский объект 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
}