2011-10-09 91 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

相关问题