Pybind11绑定C++抽象类(DLL接口)

这篇具有很好参考价值的文章主要介绍了Pybind11绑定C++抽象类(DLL接口)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

本文为李你干嘛原创,转载请注明出处:Pybind11绑定C++抽象类(DLL接口)文章来源地址https://www.toymoban.com/news/detail-680439.html

摘要

假设我们将DLL中的接口封装成了C++抽象类,并将该类和DLL文件提供给用户,类似于抽象类导出DLL中描述的办法,如果这个时候我们想使用pybind11绑定这个C++抽象类,会遇到报错,如抽象类无法实例化等等,此时Pybind11给出了辅助类的办法overriding-virtual-functions-in-python,但是如果只想转换C++抽象类的一部分的话,这个方案是不适用的。Pybind11有个很强大的功能,如果我们将C++类使用py::class绑定后,那么C++暴露给python的这个类会自动转换成Python的类。如果我们要大量的在Python中使用到这个C++抽象类且接触不到其基类时,就没有办法完成这个抽象类的绑定。

在这里我们给出一个解决思路,即用Wrapper类将C++的抽象类封装,并对这个类使用pybind绑定,这样我们就有了一个Python端的Wrapper类。再根据官网给出的办法Custom Type Casters实现从Python端Wrapper类到C++抽象类和从C++抽象类到Python端Wrapper类的自动转换。这样当C++暴露给Python这个抽象类时,pybind会自动调用转换器将抽象类转换成Wrapper类的Python对象,当Python的Wrapper类传递给C++时,会将Wrapper类变成C++抽象类。

问题描述

假设我们将C++抽象类AbstractDLLInterface作为DLL接口,ConcreteDLLInterface1类作为具体实现,但是并不把它暴露给用户。

#ifdef MYDLL_EXPORTS
#define MYDLL_API __declspec(dllexport)
#else
#define MYDLL_API __declspec(dllimport)
#endif

// 抽象类接口
class MYDLL_API AbstractDLLInterface {
public:
    virtual ~AbstractDLLInterface() {}
    virtual void dllFunction() = 0;
    virtual AbstractDLLInterface* createInstance() const = 0;
};

// 具体的实现类1
class ConcreteDLLInterface1 : public AbstractDLLInterface {
public:
    void dllFunction() override;
    AbstractDLLInterface* createInstance() const override;
};

// 在实现文件中提供具体实现
void ConcreteDLLInterface1::dllFunction() {
    // DLL 接口函数的具体实现
    // ...
}

AbstractDLLInterface* ConcreteDLLInterface1::createInstance() const {
    return new ConcreteDLLInterface1();
}

现在我们只有AbstractDLLInterface类的声明和一个DLL文件,我们的C++代码中需要经常使用AbstractDLLInterface类作为返回值或者函数参数,而我们需要把这一部分用Pybind绑定。下面给出解决方案。

解决方案

创建Wrapper类

class Wrapper {
public:
    Wrapper(AbstractDLLInterface* instance) : instance_(instance) {}

    void dllFunction() {
        instance_->dllFunction();
    }

    AbstractDLLInterface* instance_;
};

定义AbstractDLLInterface类的type_caster

namespace PYBIND11_NAMESPACE {
    namespace detail {
        template <> struct type_caster<AbstractDLLInterface> {
        public:

            PYBIND11_TYPE_CASTER(AbstractDLLInterface, const_name("AbstractDLLInterface"));

            /**
             * Conversion part 1 (Python -> C++): convert a PyObject into an AbstractDLLInterface
 			 */
            bool load(handle src, bool) {
                Wrapper wrapper = py::cast<Wrapper>(src);
                value = *(wrapper.instance_);
                return true;
            }

            /**
             * Conversion part 2 (C++ -> Python): convert an AbstractDLLInterface into a PyObject
             */
            static handle cast(AbstractDLLInterface src, return_value_policy policy, handle parent) {
                std::shared_ptr<Wrapper> wrapper_ptr = std::make_shared<Wrapper>(&src);
                return type_caster<std::shared_ptr<Wrapper>>::cast(wrapper_ptr, py::return_value_policy::take_ownership, parent);
            }
        };
    }
} // namespace PYBIND11_NAMESPACE::detail

Pybind中的处理思路无非是在绑定好的类、函数上,在python遇到定义过的类或者类型等就将其从C++的类包装成python的类,在python端有参数要传递给C++就将参数从Python类转换成C++类。上面的代码就实现了这个过程,我们将Python中的Wrapper类与C++中的AbstractDLLInterface类视为等效的,那么如果有Python中的Wrapper类需要传入到C++中时,会调用load将AbstractDLLInterface类实例从Wrapper类中提取出来,如果C++中有AbstractDLLInterface类实例要传入到Python中时,会调用cast新建一个Wrapper实例,再将这个Wrapper实例转换成Python对象传入到Python空间中。

实际操作用大多数不会用到AbstractDLLInterface而是AbstractDLLInterface的智能指针,此处是对AbstractDLLInterface进行转换,但是处于安全性考虑最好对std::shared_ptr<AbstractDLLInterface>类型进行转换。

绑定Pybind

// 绑定代码
PYBIND11_MODULE(my_module, m) {
    py::class_<Wrapper, std::shared_ptr<Wrapper>>(m, "Wrapper")
        .def(py::init<AbstractDLLInterface*>())
        .def("dllFunction", &Wrapper::dllFunction);
}

注意此时我们不需要绑定AbstractDLLInterface类,绑定AbstractDLLInterface类编译时会报错。py::class_传入参数Wrapper, std::shared_ptr<Wrapper>可以保证Python可以识别Wrapper和Wrapper的指针。

本文为李你干嘛原创,转载请注明出处:Pybind11绑定C++抽象类(DLL接口)

到了这里,关于Pybind11绑定C++抽象类(DLL接口)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • .lib 文件,.dll 文件,.sln 文件都是干嘛的,他们各自都哪些内容,是如何生成这些文件的

    .lib 文件、 .dll 文件和 .sln 文件都是与 Microsoft Visual Studio 开发工具相关的文件。 .lib 文件(静态库文件): .lib 文件是静态库文件,包含一组对象文件的二进制代码和符号信息,可以被编译器链接到可执行文件中。当编译器编译程序时,它将 .a 文件(Linux)或 .lib 文件(Win

    2024年02月15日
    浏览(39)
  • Win11新建不了文本文档?Win11右键无法新建文本文档的解决方法

    ​Win11系统具有稳定、速度快、系统干净等特点,深受用户的喜爱,但是在使用中难免会出现一些问题,就比如右键无法新建文本文档的情况,出现这一情况的原因很有可能是由于系统文件缺失问题,对此我们一起来看看小编是如何解决的吧。 还有详细的一键重装系统方法

    2024年02月08日
    浏览(63)
  • onnxruntime.capi.onnxruntime_pybind11_state.Fail: [ONNXRuntimeError] : 1 : FAIL : Load model from mn

    树莓派4B在使用onnxruntime1.6.0对model.onnx模型进行加载的时候出现以下的报错: 原因: 由于导出的ONNX模型文件不兼容ONNX Runtime当前版本所导致的,一开始我导出模型的方式如下: 然后会得到一个文件夹: 接着我在上面生成的文件夹的那个路径中打开树莓派的黑窗口,然后输入

    2024年02月11日
    浏览(31)
  • 功能测试,接口测试,自动化测试,压力测试,性能测试,渗透测试,安全测试,具体是干嘛的?

    软件测试是一个广义的概念,他包括了多领域的测试内容,比如,很多新手可能都听说:功能测试,接口测试,自动化测试,压力测试,性能测试,渗透测试,安全测试等,这些专业名词,但是绝大多数人都对这些名词一知半解,所以,今天我们就来给大家做个逐一的解释:

    2024年02月03日
    浏览(60)
  • 本文整理了Debian 11在国内的几个软件源。

      1.使用说明  一般情况下,将/etc/apt/sources.list文件中Debian默认的软件仓库地址和安全更新仓库地址修改为国内的镜像地址即可,比如将deb.debian.org和security.debian.org改为mirrors.xxx.com,并使用https访问,可使用如下命令: 修改之后再运行apt update更新索引。 2.国内常见镜像站点

    2024年02月07日
    浏览(30)
  • 【JAVASE】抽象类和接口及其抽象类和接口的区别

    ✅作者简介:大家好,我是橘橙黄又青,一个想要与大家共同进步的男人😉😉 🍎个人主页:再无B~U~G-CSDN博客 目标: 1. 抽象类 2. 接口 3. Object 类 在面向对象的概念中,所有的对象都是通过类来描绘的,但是反过来,并不是所有的类都是用来描绘对象的, 如果 一个类中

    2024年04月13日
    浏览(52)
  • 做网络那么多年,连以太网接口和串口都分不清?本文值得一看!

    路由器是一种网络设备,它的主要功能是在不同的网络之间转发数据包,实现网络互联。路由器根据数据包的目的地址,选择最佳的路径,将数据包发送到下一跳。路由器可以连接不同的网络类型,如以太网、帧中继、PPP等。 路由器上有多种不同的接口,用于连接不同的网络

    2024年02月11日
    浏览(43)
  • 【javaSE】抽象类和接口(2)(接口部分)

    hellohello~,大家好💕💕,这里是E绵绵呀✋✋ ,如果觉得这篇文章还不错的话还请点赞❤️❤️收藏💞 💞 关注💥💥,如果发现这篇文章有问题的话,欢迎各位评论留言指正,大家一起加油!一起chin up!👍👍  💥 个人主页 :E绵绵的博客 💥 所属专栏 :JAVASE题目练习

    2024年04月28日
    浏览(36)
  • Java的抽象类 & 接口

    如果自下而上在类的继承层次结构中上移,位于上层的类更具有通用性,甚至可能更加抽象。从某种角度看,祖先类更加通用,人们只将它作为派生其他类的基类,而不作为想使用的特定的实例类。例如,考虑一下对 Employee 类层次的扩展。一名雇员是一个人,一名学生也是一

    2024年02月03日
    浏览(30)
  • 面向对象——多态、抽象类、接口

    学习资料来自:黑马程序员,内容仅为学习记录,侵删 多态 多态:事务存在的多种形态 多态的前提:1、有继承关系;2、重写父类方法;3、父类引用指向子类对象 面向对象 面向对象多态中成员访问特点 1.成员方法(动态绑定):编译看左边(父类),运行看右边(子类)

    2024年02月08日
    浏览(84)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包