我有一个大的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中创建适当的类型,或者是否有更优雅的解决方案?
答案 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中引入一些额外的方法,你试着调用它们吗?
使用动态向下转换的设计是代码气味,我想你刚刚发现了原因。