首頁 > 軟體

Qt動態庫呼叫宿主程序中的物件方法純虛擬函式使用

2022-08-12 22:01:37

引言

可執行程式載入動態庫並呼叫動態庫匯出的函數是比較容易的:

匯入庫對應的標頭檔案

在CPP檔案中呼叫函數

在連結程式時加上動態庫作為引數

假設demo.cpp中需要用到動態庫libadd.so中的某個函數,可能是int add(int x, int y),那麼我們編譯時就需要連結上libadd.so, gcc引數中-L./libs指定了當前目錄下的libs目錄為庫的目錄,-ladd指定了libadd.so動態庫檔案,注意這裡並未使用全稱,讓編譯器自動適配即可。

// 該方式為靜態匯入方式(在程式未執行時完成匯入)
gcc demo.cpp -o demo -L./libs -ladd

在執行時載入動態庫並獲取物件指標(QLibrary)

// 匯入動態庫
QLibrary m_library;
m_library.setFileName("./libs/libadd.so");
assert(m_library.load());
// 獲取函數指標
typedef int (*FUNC_ADD)(int, int);
FUNC_ADD add = (FUNC_ADD)m_library.resolve("add");
assert(add);
// 愉快的使用add函數
int a = add(125, 125);
qDebug() << a;

本貼重點:在動態庫中呼叫宿主程序的物件方法

先複習下兩個概念:純虛擬函式虛擬函式表

  • 純虛擬函式在類中定義後是可以不用實現的,子類如繼承含有純虛擬函式的類必須實現該類所有的純虛擬函式。純虛擬函式可作介面使用。
  • C++擁有虛擬函式表(V-Table),儲存著虛擬函式地址的表。

假設動態庫需要呼叫宿主程序的物件方法,在動態庫編譯時時無法獲取到宿主程式該物件的實現的,所以按照正常邏輯是無法編譯通過的。

但是通過上邊有效的複習可以知道純虛擬函式在呼叫時可無需實現(在執行時通過查詢虛擬函式表後獲取實際地址),這樣就可以順利的完成了編譯,當動態庫被載入進宿主程序後就可以正常呼叫物件的方法了。

還是以add方法為例寫一個Demo

宿主程式:

#ifndef __MATH_H__
#define __MATH_H__
// 介面定義
class IMath
{
public:
    virtual int add(int x, int y) = 0;
};
typedef void (*FUNC_SET_OBJ)(void*);
class Math: public IMath
{
public:
    Test() {
        m_library.setFileName("./libs/libtest.so");
        assert(m_library.load());
        FUNC_SET_OBJ setObj= (FUNC_SET_OBJ)m_library.resolve("setObj");
        assert(setObj);
        // 將Math範例傳遞給動態庫
        setObj(this);
    }
    int add(int x, int y) ovdrride {
        return x + y;
    }
private:
    QLibrary m_library;
}
#endif

然後將介面做成一個獨立的標頭檔案imath.h,用來給動態庫呼叫

#ifndef __IMATH_H__
#define __IMATH_H__
class IMath
{
public:
    virtual int add(int x, int y) = 0;
};
#endif

動態庫程式(libtest.cpp):

void setObj(void* obj) {
    IMath* math = static_cast<IMath*>(obj);
    qDebug() << math->add(125, 125);
}

將動態庫程式編譯後放入libs目錄下給宿主程式呼叫,在宿主程式中範例化Math類,並呼叫其Test方法,在Test方法中會載入動態庫,並將Math範例的指標傳遞給動態庫,動態庫將Math範例強轉為介面型別並呼叫其中的純虛擬函式add()

以上就是Qt動態庫呼叫宿主程序中的物件方法純虛擬函式使用的詳細內容,更多關於Qt動態庫呼叫宿主程序純虛擬函式的資料請關注it145.com其它相關文章!


IT145.com E-mail:sddin#qq.com