与c++ /CLI和模板的协方差

Covariance with C++/CLI and Templates

本文关键字:方差 c++ CLI      更新时间:2023-10-16

我正在尝试在我的本地库和我的c#客户端代码之间建立一座桥梁。

为此,我有一个名为"IHasManagedWrapper"的接口:

#ifndef IHASMANAGEDWRAPPER_H_
#define IHASMANAGEDWRAPPER_H_
template <typename T>
class IHasManagedWrapper
{
public:
    virtual T^ CreateManagedWrapper() = 0;
};
#endif
然后,为了测试返回的CLI类型的多态性,我创建了两个本机类,Parent和Child,其中Child继承自Parent: 父:

#ifndef PARENT_H_
#define PARENT_H_
#include "IHasManagedWrapper.h"
ref class CLIParent;
class Parent : public IHasManagedWrapper<CLIParent>
{
public:
    Parent();
    ~Parent();
    virtual char* GetName();
    virtual CLIParent^ CreateManagedWrapper();
};
#endif

孩子:

#ifndef CHILD_H_
#define CHILD_H_
#include "Parent.h"
#include "IHasManagedWrapper.h"
ref class CLIChild;
class Child : public Parent, IHasManagedWrapper<CLIChild> // uh-oh...
{
public:
    char* GetName();
    CLIChild^ CreateManagedWrapper();
}; // error C2555: 'Child::CreateManagedWrapper': overriding virtual function return type differs and is not covariant from 'Parent::CreateManagedWrapper'

#endif

我通过将"CLIChild"更改为"CLIParent"并从IHasManagedWrapper中删除CLIChild的继承来工作,但这意味着每次我调用Child->CreateManagedWrapper()时,我都会得到一个CLIParent对象,然后我需要手动转换为一个CLIChild对象。

CLIChild^ child = safe_cast<CLIChild^>(pChild->GetManagedWrapper()); // pChild->GetManagedWrapper() returns a CLIParent^ object

虽然这不是坏,有一种方法,使它使CLIChild->CreateManagedWrapper()将返回一个CLIChild对象,同时保留IHasManagedWrapper接口?

谢谢!

您可以通过将重载虚方法的主体转移到特定方法(例如Child::CreateManagedWrapperChild)中,然后在知道正在处理Child时调用该特定方法来解决此问题。重载的虚方法只需调用特定的方法并将其结果上推到CLIParent以匹配正确的方法签名。

class Child : public Parent {
public:
    char* GetName();
    CLIParent^ CreateManagedWrapper() { return CreateManagedWrapperChild(); }
    CLIChild^ CreateManagedWrapperChild(); // actual code in this method
};

这看起来不像你希望写的那样干净,但它被编译器接受,并且在实践中应该只适用于一级继承。对于不止一个,您也必须使CreateManagedWrapperChild虚,以同样的方式在GrandChild中重载它,并且还要重载原始的虚拟方法以直接调用CreateManagedWrapperGrandChild方法,以避免嵌套的虚拟调用。

然而,对于一个大的继承树,这种技术不是很实用,因为特定的虚拟方法爆炸了。