boost python: как вызвать виртуальную функцию C++

У меня есть python, встроенный в приложение C++. C++ вызывает python и передает его в качестве аргумента объекту C++. этот объект имеет некоторые виртуальные функции и может быть базовым классом для некоторого производного класса. Как заставить boost::python понять, что это виртуальная функция?

рассмотрите следующее:
в C++:

class Base {
public:
  virtual void func();
}

class Derived {
public:
  virtual void func();
}

BOOST_PYTHON_MODULE(module_api) {
  class_<Base>("Base")
    .def("func", &Base::func);  // ?? what should I put here?
}

int main() {
  //... initialization
  Derived derived;
  main_namespace["pyentry"](&derived);
}

в питоне:

def pyentry(baseref):
  baseref.func()    # here I want Derived::func() to be called

Что я здесь делаю неправильно?


person shoosh    schedule 10.05.2012    source источник
comment
Всегда можно поставить не виртуальную переадресацию: void Base::doFunc() { this->func(); }, .def("func", &Base::doFunc);   -  person Robᵩ    schedule 10.05.2012
comment
Я надеялся избежать этих накладных расходов... Разве не в этом должен заключаться boost::python? избежать накладных расходов...?   -  person shoosh    schedule 10.05.2012
comment
вам нужно обернуть базу - boost.org /doc/libs/1_49_0/libs/python/doc/v2/wrapper.html   -  person babak    schedule 11.05.2012
comment
@barak можно поконкретнее? Я пробовал это в разных формах и не мог заставить его работать. Я не хочу переопределять метод в python, я просто хочу полиморфно вызывать виртуальный.   -  person shoosh    schedule 11.05.2012


Ответы (1)


Проблема здесь в том, что Boost.Python глубоко копирует ваш объект производного класса и нарезает его на базовый объект при преобразовании в Python; нет необходимости сообщать Boost.Python о том, что функция вообще является виртуальной, если только вам не нужно переопределить ее в Python (и похоже, что вы этого не делаете).

Он делает эту копию, чтобы быть в безопасности: он гарантирует, что переданный Python объект не будет удален C++, пока Python все еще имеет ссылку на него. И он разрезает его на Base, я думаю, потому что ничего не знает о Derived.

Я могу придумать два способа исправить это:

  • Предоставьте тривиальную оболочку для Derived. Boost.Python по-прежнему будет копировать его при преобразовании в Python, но при этом он больше не будет нарезать его на Base.

  • Зарегистрируйте преобразование shared_ptr для Base (через register_ptr_to_python< boost::shared_ptr<Base> >()), создайте свой экземпляр Derived в shared_ptr и передайте его в качестве аргумента вашей функции Python. Теперь Boost.Python знает, что объект C++ не может быть удален, пока объект Python существует, потому что оболочка Python содержит ссылку на него shared_ptr.

person jbosch    schedule 12.05.2012