Понижение в Boost.Python

РЕДАКТИРОВАТЬ: исправлено «upcast» на «downcast».

Я пытаюсь найти лучший способ сделать понижающее приведение в Python, когда классы, с которыми я работаю, взяты из C++. Если у меня есть два класса, определенные в С++ как:

struct Base
{
    int foo()
    {
        return 7;
    }
};

struct Derived : Base
{
    int bar()
    {
        return 42;
    }
};

И еще одна функция

Base baz()
{
    return Derived();
}

Если я попробую в Python

der = baz()
print der.foo()
print der.bar()

Вызов bar() завершается ошибкой, потому что Python знает только о функциях в Base.

Мое решение состояло в том, чтобы добавить еще одну функцию в Derived:

Derived * fromBase(Base * b)
{
    return reinterpret_cast<Derived *>(b);
}

Если затем я изменю первую строку сценария Python на der = Derived.fromBase(baz()), сценарий будет работать, как и ожидалось.

Однако тот факт, что я использую reinterpret_cast для выполнения этой работы, кажется очень неправильным. Есть ли лучший способ приведения к понижению, который не требует использования чего-то столь же опасного, как reinterpret_cast? Если нет, то какой должна быть политика возврата для fromBase()?

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

РЕДАКТИРОВАТЬ:

Я ищу что-то, что работает как этот код С#:

Base b = new Derived();
Derived d = b as Derived;
if (d != null)
    ...

person Austin Wagner    schedule 31.08.2012    source источник
comment
dynamic_cast вместо reinterpret_cast?   -  person ForEveR    schedule 01.09.2012


Ответы (1)


Base baz()
{
    return Derived();
}

Как видно из возвращаемого типа, он возвращает объект Base, не объект Derived. Так что унывать (и не возвышать) не к чему. Так что сначала нужно это исправить.

Более того, вы правы, reinterpret_cast определенно сомнительно в этом контексте. dynamic_cast на самом деле является инструментом для понижения.

Что еще более важно, вы должны спросить себя, почему вы чувствуете потребность в унынии. Может случиться так, что ваш код примера является синтетическим и не отражает вашу точную проблему, но почему baz не должен возвращать Derived?


Вот эквивалент вашего фрагмента:

Derived d;
Base& b = d;
if(Base* p = dynamic_cast<Derived*>(&b))
    // okay; b is actually an instance of Derived
person Luc Danton    schedule 01.09.2012
comment
Нет, то, что я сказал, верно. Мой пример не совсем репрезентативен для ситуации, но это не должно иметь значения. На самом деле Base — это класс интерфейса (у него есть только виртуальные функции), и это то, что возвращает baz(). У меня такое ощущение, что эти классы, которые я должен использовать, изначально были написаны на C#, поскольку преобразование в них гораздо безопаснее, чем в C++. - person Austin Wagner; 01.09.2012
comment
@Mr.Ambiguous Что вы думаете об этом этом? - person Luc Danton; 01.09.2012
comment
Меня не волнует, что эта функция typeid думает о типе. Я знаю, что указанная память содержит производное, даже если typeid видит его как базу. Тот факт, что reinterpret_cast работает, является доказательством того, что это так. Я просто пытаюсь выяснить, есть ли более безопасный способ. - person Austin Wagner; 02.09.2012
comment
@Mr.Ambiguous typeid не является функцией и отражает фактический динамический тип объекта полиморфного типа. Если ваш код на самом деле включает объект Derived, то ваш пост должен отражать это. Как бы то ни было, baz() не является объектом Derived. Нет необходимости в «доказательстве», таковы правила языка. - person Luc Danton; 02.09.2012
comment
Мои извенения. Вы правы в том, что я пытаюсь унижать. Я предположил, что база будет внизу иерархии, а не (нелогично) наверху. Я думаю, что мое понимание того, как работает C++, полностью отсутствует, потому что, когда я добавил виртуальную функцию к Base, чтобы заставить ее компилироваться с dynamic_cast, приведение вернуло мне значение null. Я изменил его обратно на reinterpret_cast при выходе из виртуальной функции, и это привело к тому, что вызов bar() перестал работать. - person Austin Wagner; 04.09.2012