Pybind11綁定C++抽象類(DLL介面)

来源:https://www.cnblogs.com/liniganma/archive/2023/08/30/17666063.html
-Advertisement-
Play Games

#### 本文為[李你幹嘛](https://www.cnblogs.com/liniganma)原創,轉載請註明出處:[Pybind11綁定C++抽象類(DLL介面)](https://www.cnblogs.com/liniganma/p/17666063.html) # 摘要 假設我們將DLL ...


本文為李你幹嘛原創,轉載請註明出處:Pybind11綁定C++抽象類(DLL介面)

摘要

假設我們將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可以保證

本文為李你幹嘛原創,轉載請註明出處:Pybind11綁定C++抽象類(DLL介面)


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 記憶體泄漏是前端開發中的一個常見問題,可能導致項目變得緩慢、不穩定甚至崩潰。在本文中,我們將深入探討在JavaScript、Vue和React項目中可能導致記憶體泄漏的情況,並提供詳細的代碼示例,以幫助開發人員更好地理解和解決這些問題。 第一 ...
  • 基於傳統認知,前端產品直接觸達消費者,往往具有高度的定製化、需求變更頻繁等特點,要求具有很好的動態性, 能夠滿足不同客戶的需求。那麼能否建設類似的前端中台產品,我們姑且稱之為“前端領域產品”,實現接入團隊端到端能力復用呢?我們在撮合業務線中進行了一系列思考和探索。 ...
  • 1. 使用 defineStore 創建一個 store, 每個 store 要設置一個唯一 id; ```ts import { defineStore } from 'pinia' import { ref } from 'vue' // useStore 可以是 useUser、useCart ...
  • 通過這個示例,你將更深入地瞭解如何在實際業務中應用Flutter,以及如何運用不同的解決方案和技術來構建高效、穩定的應用。 ...
  • # el-autocomplete核心參數 可以實現非同步的數據拉取,從非同步返回的數據中,選擇需要的結果,並回顯到文本框中。 ## fetch-suggestions 回調列表,非同步的方式獲取數據列表,顯示在列表框中 ## @select 當選中某一項時,會觸發這個方法,將數據獲取到,這時,我們可以將 ...
  • # 核心原理 長鏈接轉為短鏈接的核心原理是: 將短鏈接與原始長鏈接做一個映射,訪問短鏈接的時候,通過重定向的方式轉到長鏈接。 # 應用場景 比如分享功能,查看分享信息的原始鏈接通常是很長的,直接發給用戶,體驗不是很好,這時候就可以將其映射為一個短鏈接再發給用戶。 又比如我們熟知的百度網盤分享文件,雖 ...
  • ##一、定義 **講一個複雜對象的構建與它的表示分離,使得同樣的構建過程可以創建不同的表示。建造者模式是一種創建型模式。** ##二、描述 **包含以下四個角色:** ![](https://img2023.cnblogs.com/blog/1780813/202305/1780813-202305 ...
  • 你想成為一名架構師,對嗎?別對我撒謊,我知道你想成為架構師。即使你不想,你還是想成為一名更好的開發者。否則,你就不會花時間閱讀這篇文章。 這種態度值得贊賞。畢竟,我們都希望在自己所從事的領域變得更好,即使不能稱為最好。我在這裡就是為了幫助你實現這一目標。 那麼,你如何成為一名架構師呢?當然是通過學習 ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...