2011-10-09 44 views
1

我有6個類的故事:3個託管和3個本機。在C++/CLI中通過包裝器(派生託管類)調用派生本機類的重寫方法

3個託管類是ManagedChildA,ManagedChildB和ManagedParent。

ManagedChildA,ManagedChildB都從ManagedParentA繼承。

3個本地類是NativeChildA,NativeChildB和NativeParent。

NativeChildA,NativeChildB都從NativeParentA繼承。

此外,ManagedChildA包裝NativeChildB,ManagedChildB包裝ManagedChildB和ManagedParentA包裝NativeParentA。

現在,這裏的故事gows歪:

ManagedParentA有包裝NativeParentA的NativeExecute)稱爲ManagedExecute的方法(()。當這個方法被調用時,一切都運行平穩。 ()包裝NativeChildA :: NativeExecute()和ManagedChildB :: ManagedExecute()包裝NativeChildB :: NativeExecute(),NativeChildB,ManagedChildB重寫ManagedExecute()以提供它們自己的實現。

例如,當調用ManagedChildA的重寫ManagedExecute()時,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 
} 
+0

指向本機類的指針不會移動,這不是問題。你能告訴我們短代碼展示這個問題嗎? – svick

+0

通過在派生類中添加具有相同名稱的成員變量來隱藏基類成員變量是一個可怕的想法。你可能想要的是一個getter函數,它將基類成員轉換爲派生類型。 –

+0

真正的本,但如果我只想通過接口工作呢?也就是,而不是:mbarA-> Execute(),我想使用iexec-> Execute(),其中iexec是任何實現IExecutable類的實例變量? – reexmonkey

回答

1

該片段是非常低的質量,它充滿了不可編譯的代碼。一旦我修正了所有的錯誤,我無法重現。

#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 
} 
+0

感謝您的更正....雖然代碼起作用,但它不能解決我的問題,因爲上面的代碼片段都在一個程序集中。嘗試構建3個dll文件:主應用程序運行在一個文件夾中,然後其他dll用於託管類,而最後一個dll應該保存本機類。您會注意到一個奇怪的行爲,即派生的本機類在調用重寫的方法時失去了繼承的成員。 – reexmonkey

+1

嗯,所以代碼片段不只是充滿了錯誤,它甚至沒有證明這個問題?我只能猜測你忘了在#including頭文件之前使用#pragma管理。你必須學會​​如何提出更好的問題。祝你好運。 –

+0

c'mon hans ...不要對所管理的#pragma進行挑剔......在所有情況下都沒有必要......而且就我的片段而言,我並沒有編寫測試代碼。這僅僅是爲了展示問題的本質......當然,在一些測試後,問題定義會變得更加清晰。有時候事情不像他們看起來那樣! – reexmonkey

相關問題