Как мне сохранить полиморфизм, когда я использую C ++ / CLI, чтобы обернуть C ++ API? - PullRequest
0 голосов
/ 05 ноября 2010

У меня есть большой C ++ API, который мне нужно обернуть в оболочку C ++ / CLI, чтобы сделать доступным в .NET

По большей части это работает нормально, но я столкнулся с одной областью, которая вызывает проблему полиморфизма.

На чистом C ++ API у меня есть такая функция:

vector<Parent*> getCppObjects()
{
    return myVector;
}

Родитель - это тип с двумя детьми 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 ]

3 голосов
/ 08 ноября 2010

Один из вариантов - клиенты используют метод (а не dynamic_cast), когда им нужно проверить, является ли базовый класс cpp дочерним. Примерно так:

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) - добавить виртуальный класс к родительскому, который создает свой собственный соответствующий тип 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;             
 }             
0 голосов
/ 07 ноября 2010

Зачем вам нужно несколько типов на уровне CLI?CLIParent обтекание Parent* будет полиморфным и будет вести себя так, как на самом деле указывает объект, вам не нужны виртуальные функции в оболочке CLI (это на самом деле очень похоже на шаблон вызова не-виртуальных функций общего назначениязащищенные или частные виртуальные функции).Я полагаю, что подклассы вводят некоторые дополнительные методы в общедоступный API, и вы пытаетесь вызывать их?

Дизайн с использованием динамических понижений - это запах кода, и я думаю, вы только что узнали, почему.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...