C++ dll動態程式庫建置架構筆記(CMake build) -4 如何使用class架構

其實這部分我還沒研究的很深入,只先將我所知道的部分記錄下來。

我主要會針對在 class 裡需要儲存變數的做法說明,最常見的情況就是 class 裡面會暫時儲存一些資料給多個 funciton 使用,他們的資料型態可能是 C++ 原有的,也可能是自己定義的 struct,再來考慮到這些資料型態是僅內部使用還是要傳出給外部使用等各種可能的情況。

一、使用情況

第1種情況暫存變數是 C++ 資料型態,可在 class 內部及外部使用。

只要使用的人也有這些資料型態的定義就可以,假如其中有一個型態使用的人無法知道,就要附加上,如果無法附加上那只能用以下方法將它隱藏在內部,自己寫一個轉譯的 function 傳送出去。

第2種情況暫存變數非 C++ 資料型態,僅在class內部使用。

第3種情況暫存變數非 C++ 資料型態,需將資料傳出使用。


之後我使用以下的架構,struct newNumber 在2、3種方法裡當作非 C++ 變數
struct newNumber
{
    int i;
    int j;
};

class math_class
{
public:
    newNumber a;
    math_class(int val) { a.i=val; a.j=val*10; }
    void Add(int b) { a.i+=b; a.j+=b; }
};

二、做法及範例

第1種情況

可以用比較簡單作法,相似於第一篇文章的寫法,因為 struct 本身及 struct 內部都使用 C++ 資料型態,使用的人都知道這些資料型態,只要這個 struct 使用的人也有定義就好。以下用第2種實作範例:

最外層的header.h,編譯完能給使用者匯入的
Dll_class_c\math_class\include\my_math_class_c.h
#ifndef my_math_H_
#define my_math_H_
#include "SVdef.h"

struct newNumber
{
    int i;
    int j;
};

class SV_EXPORTS math_class
{
public:    
    newNumber a;
    math_class(int value);
    void input_a(int value);
    void get_a(newNumber &a_);
    void Add(int b);
};
#endif //my_math_H_
Dll_class_c\math_class\include\my_math_class_c.cpp
#include "my_math_class_c.h"

math_class::math_class(int value)
{
    input_a(value);
}
void math_class::input_a(int value)
{
    a.i = value;
    a.j = value*10;
}
void math_class::get_a(newNumber &a_)
{
    a_ = a;
}
void math_class::Add(int b)
{
    a.i+=b;
    a.j+=b;
}
測試 dll
Dll_class_c\main\test.cpp
#include "my_math_class_c.h"

int main()
{
    int a = 10;
    int b = 20;
    newNumber a_val;

    math_class math_cls = math_class(a);
    printf("a.i, a.j %d, %d\n", math_cls.a.i, math_cls.a.j);

    math_cls.get_a(a_val);
    printf("get_a %d, %d\n", a_val.i, a_val.j);

    math_cls.Add(b);
    math_cls.get_a(a_val);
    printf("Add(b) %d, %d\n", a_val.i, a_val.j);

    printf("\n");
    return 0;
}
output
a.i, a.j 10, 100
get_a 10, 100
Add(b) 30, 120

第2、3種情況

假設 struct newNumber 當作非 C++ 變數,不能讓使用的人知道。
這裡使用虛擬函數的架構,要將 class 以指標的方式使用。
第3種情況要將 newNumber 的內容用 function 的方式傳出,像以下 void get_a(int &i, int &j) 的做法。

最外層的 header.h,編譯完能給使用者匯入的
Dll_class\math_class\include\my_math_API.hpp
#ifndef math_API_H_
#define math_API_H_

#include <memory>
#include "SVdef.h"

class SV_EXPORTS math_class
{
public:
    virtual void input_a(int value) = 0;
    virtual void get_a(int &i, int &j) = 0;
    virtual void Add(int b) = 0;
};

// math_class 以指標方式建立
SV_EXPORTS std::shared_ptr<math_class> createMathClass(int a);
SV_EXPORTS math_class* createMathClass_pointer(int a);
#endif //math_API_H_
真正實作 class 的 header.h
Dll_class\math_class\include\my_math_class.h
#ifndef math_H_
#define math_H_
#include "my_math_API.hpp"

// 假設newNumber這個資料型態不能或無法讓其他人知道
struct newNumber
{
    int i;
    int j;
};

class math_classImpl final : public math_class
{
private:
    newNumber a;
public:
    math_classImpl(int value);

    virtual void input_a(int value) override;
    virtual void get_a(int &i, int &j) override;
    virtual void Add(int b) override;
};

// math_class 以指標方式建立
std::shared_ptr<math_class> createMathClass(int a);
math_class* createMathClass_pointer(int a);
#endif //math_H_
Dll_class\math_class\src\my_math_class.cpp
#include "my_math_class.h"

math_classImpl::math_classImpl(int value)
{
    input_a(value);
}
void math_classImpl::input_a(int value)
{
    a.i = value;
    a.j = value*10;
}
void math_classImpl::get_a(int &i, int &j)
{
    i = a.i;
    j = a.j;
}
void math_classImpl::Add(int b)
{
    a.i+=b;
    a.j+=b;
}

// math_class 以指標方式建立
std::shared_ptr<math_class> createMathClass(int a)
{
    return std::make_shared<math_classImpl>(a);
}
math_class* createMathClass_pointer(int a)
{
    return new math_classImpl(a);
}
測試 dll
Dll_class\main\test.cpp
#include <stdio.h>
#include "my_math_class.h"

int main()
{
    int a = 10;
    int b = 20;
    int i,j;

    // ============  use std::shared_ptr  =============================================
    printf("====  use std::shared_ptr\n");
    std::shared_ptr<math_class> math_cls = createMathClass(a);
    math_cls->get_a(i, j);
    printf("get_a %d %d\n", i, j);

    math_cls->Add(b);
    math_cls->get_a(i, j);
    printf("Add(b) %d %d\n", i, j);

    math_cls.reset();
    printf("\n");

    // ============  use c pointer  =============================================
    printf("====  use c pointer\n");
    math_class *p_math_cls = createMathClass_pointer(a);
    p_math_cls->get_a(i, j);
    printf("get_a %d %d\n", i, j);

    p_math_cls->Add(b);
    p_math_cls->get_a(i, j);
    printf("Add(b) %d %d\n", i, j);

    delete p_math_cls;
    printf("\n");
    return 0;
}
output
====  use std::shared_ptr
get_a 10 100
Add(b) 30 120

====  use c pointer
get_a 10 100
Add(b) 30 120

留言

這個網誌中的熱門文章

C# 模擬鍵盤滑鼠控制電腦

python nn 聲音辨識 -1 傅立葉轉換

android 定時通知(永久長期的) 本篇只講AlarmManager使用

python opencv 基本讀取、轉換、顯示、儲存等

python pyautogui 簡介