C++使用纯虚函数和单例模式导出接口的动态库的写法

要写一个C++的动态库,里面每个函数都要共用到一个变量。我觉得这样最好写成类的形式,该变量就可以作为类的成员变量来封装。

但我不希望将整个类都导出,希望只导出特定的接口函数。

于是我想到了继承,

让子类继承父类(纯虚函数类)。

另外,使用了单例模式。

最后只导出获取单例的函数即可。

父类接口函数头文件:

#pragma once

#define DLL_API _declspec(dllexport)
const int OPER_SUCCESS = 0;
const int DEV_NOT_CONN = -1;
const int INPT_WRONG = -2;

class  CFluke5500aOperInterface
{
public:
    virtual int open_fluke5500a_conn(const char* const rsrc_name) = 0;

    virtual int close_fluke5500a_conn() = 0;

    virtual int cmd_oper() = 0;

    virtual int cmd_rst() = 0;

    virtual int cmd_out_ma(int ma) = 0;

    virtual int send_cmd(const char* const str_cmd) = 0;

    virtual int cmd_stby() = 0;

    virtual int cmd_clear_all_stat() = 0;
};

子类头文件:

#pragma once

#include "fluke5500a_gpib_interface.h"
#include "includevisa.h"
#include "includevisatype.h"

class  CFluke5500aOper : public CFluke5500aOperInterface
{
public:
    ~CFluke5500aOper(void);

    CFluke5500aOper(const CFluke5500aOper&) = delete;

    CFluke5500aOper& operator=(const CFluke5500aOper&) = delete;

    static CFluke5500aOper& get_inst();

    int open_fluke5500a_conn(const char* const rsrc_name);

    int close_fluke5500a_conn();

    int cmd_oper();

    int cmd_rst();

    int cmd_out_ma(int ma);

    int send_cmd(const char* const str_cmd);

    int cmd_stby();

    int cmd_clear_all_stat();

private:
    CFluke5500aOper();

    ViSession m_vi_session_rm;
    ViSession m_vi_session;
    /** 同步互斥,临界区保护 */
    CRITICAL_SECTION   m_cs_communication_sync;
};

类的实现文件(注意只在获取单例的函数这里添加了导出:extern "C" DLL_API  CFluke5500aOperInterface& get_fluke5500a_oper()):

#include "pch.h"
#include "fluke5500a_gbip_com.h"

#include <stdio.h>  
#include <stdlib.h>
#include <string>
#pragma comment(lib, "lib\visa32.lib")

extern "C" DLL_API  CFluke5500aOperInterface& get_fluke5500a_oper()
{
    return CFluke5500aOper::get_inst();
}

CFluke5500aOper& CFluke5500aOper::get_inst()
{
    static CFluke5500aOper instance;
    return instance;
}

CFluke5500aOper::CFluke5500aOper()
{
    InitializeCriticalSection(&m_cs_communication_sync);
    m_vi_session_rm = NULL;
    m_vi_session = NULL;
}

CFluke5500aOper::~CFluke5500aOper(void)
{
    DeleteCriticalSection(&m_cs_communication_sync);
}

int CFluke5500aOper::open_fluke5500a_conn(const char* const rsrc_name)
{
    /*进入临界段*/
    EnterCriticalSection(&m_cs_communication_sync);
    ViStatus ret = viOpenDefaultRM(&m_vi_session_rm);
    if (ret != VI_SUCCESS)
    {
        viClose(m_vi_session_rm);
        /*离开临界段*/
        LeaveCriticalSection(&m_cs_communication_sync);
        return ret;
    }
    ret = viOpen(m_vi_session_rm, rsrc_name, VI_EXCLUSIVE_LOCK, VI_NULL, &m_vi_session);
    if (ret != VI_SUCCESS)
    {
        viClose(m_vi_session);
        viClose(m_vi_session_rm);
        /*离开临界段*/
        LeaveCriticalSection(&m_cs_communication_sync);
        return ret;
    }
    /*离开临界段*/
    LeaveCriticalSection(&m_cs_communication_sync);
    return OPER_SUCCESS;
}

int CFluke5500aOper::close_fluke5500a_conn()
{
    /*进入临界段*/
    EnterCriticalSection(&m_cs_communication_sync);
    ViStatus ret = viClose(m_vi_session);
    if (ret != VI_SUCCESS)
    {
        /*离开临界段*/
        LeaveCriticalSection(&m_cs_communication_sync);
        return ret;
    }
    ret = viClose(m_vi_session_rm);
    if (ret != VI_SUCCESS)
    {
        /*离开临界段*/
        LeaveCriticalSection(&m_cs_communication_sync);
        return ret;
    }
    /*离开临界段*/
    LeaveCriticalSection(&m_cs_communication_sync);
    return OPER_SUCCESS;
}

int CFluke5500aOper::cmd_oper()
{
    return send_cmd("OPER
");
}

int CFluke5500aOper::cmd_rst()
{
    return send_cmd("*RST
");
}

int CFluke5500aOper::cmd_clear_all_stat()
{
    return send_cmd("*CLS
");
}

int CFluke5500aOper::cmd_stby()
{
    return send_cmd("STBY
");
}

int CFluke5500aOper::cmd_out_ma(int ma)
{
    if (ma < 0)
    {
        return INPT_WRONG;
    }
    char str_ma[36];
    sprintf_s(str_ma, "%d", ma);
    std::string str_cmd = "OUT ";
    str_cmd.append(str_ma);
    str_cmd.append("MA
");
    return send_cmd(str_cmd.c_str());
}

int CFluke5500aOper::send_cmd(const char* const str_cmd)
{
    /*进入临界段*/
    EnterCriticalSection(&m_cs_communication_sync);
    if (m_vi_session == NULL) {
        /*离开临界段*/
        LeaveCriticalSection(&m_cs_communication_sync);
        return DEV_NOT_CONN;
    }
    ViStatus ret = viPrintf(m_vi_session, str_cmd);
    if (ret != VI_SUCCESS)
    {
        /*离开临界段*/
        LeaveCriticalSection(&m_cs_communication_sync);
        return ret;
    }
    /*离开临界段*/
    LeaveCriticalSection(&m_cs_communication_sync);
    return OPER_SUCCESS;
}

在调用的exe程序那边,

添加父类纯虚函数接口的头文件,

然后引入获取单例接口的函数。

使用获取单例接口的函数 获取单例的类,然后使用父类接口类声明。

这样便达成了我的目的。

只导出特定的接口函数(实际上,只导出了一个获取单例的函数)

原文地址:https://www.cnblogs.com/rixiang/p/14576707.html