当我使用C ++ / CLI包装C ++ API时,如何保留多态性?

时间:2010-11-05 17:40:51

标签: visual-c++ c++-cli

我有一个大的C ++ API,我需要将它包装在C ++ / CLI皮肤中以便在.NET中使用

在大多数情况下它工作正常,但我遇到了一个导致多态问题的区域。

在纯C ++ API上,我有一个像:

这样的函数
vector<Parent*> getCppObjects()
{
    return myVector;
}

Parent是一个有两个孩子ChildA和ChildB的类型。在CLI方面,我将有一个功能:

List<CLIParent^> getCliObjects()
{
    List<CLIParent^> myList = gcnew List<CLIParent^>();
    vector<Parent*> myVector =  getCppObjects();
    for int i=0; i < myVector.size(); ++i)
    {
        myList->add(gcnew CLIParent(myVector->at(i)));
    }
    return myList;
}

CLI Parent具有接受类型Parent的构造函数,并且子类型也有类似的类。我的问题是在C ++层我可以将对象强制转换为正确的类型,但由于我将它们包装在CLI层的方式(一直是父类型)我不能将它们用作子类型的CLI版本

我是否需要使用typeid和switch / factory之类的东西在CLI API中创建适当的类型,或者是否有更优雅的解决方案?

2 个答案:

答案 0 :(得分:3)

一种选择是让客户在需要查看底层cpp类是否为子时使用方法(而不是dynamic_cast)。如下所示:

public ref class ParentChildUtil
{
   static CLIChild ^ CastParentToChild(CLIParent ^ pParent)
   {
       Parent * pNativeParent = pParent->GetNative();
       Child * pNativeChild = dynamic_cast<Child *>(pNativeParent);
       if (!pNativeChild)
           return nullptr;

       return gcnew CLIChild(pNativeChild);
   }
};

这并不理想,但它至少会将dynamic_cast延迟到实际需要的时候。

另一个选项(如果可以使用/ clr编译本机Parent类)是向Parent类添加一个虚拟类,该类创建自己的对应CLI类型:

class Parent
{
    // ...
    virtual CLIParent ^ CreateManagedWrapper()
    {
       return gcnew CLIParent(this);
    }
};

class Child
{
    // ... 
    virtual CLIChild ^ CreateManagedWrapper()
    {
        return gcnew CLIChild(this);
    }
}

然后您的客户端代码变为:

List<CLIParent^> getCliObjects()             
{             
    List<CLIParent^> ^ myList = gcnew List<CLIParent^>();             
    vector<Parent*> myVector =  getCppObjects();             
    for (int i=0; i < myVector.size(); ++i)             
    {
        Parent * pParent = myVector->at(i);             
        myList->add(pParent->CreateManagedWrapper());             
    }
    return myList;             
 }             

答案 1 :(得分:0)

为什么在CLI层需要多种类型?包裹CLIParent的{​​{1}}将是多态的,其行为与实际指向的对象类似,在CLI包装器中不需要虚函数(这实际上很像公共非模式 - 调用受保护或私有虚函数的虚函数)。我想子类会在公共API中引入一些额外的方法,你试着调用它们吗?

使用动态向下转换的设计是代码气味,我想你刚刚发现了原因。