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
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...