利用Pimpl实现细节隐藏

发布于:2022-12-30 ⋅ 阅读:(533) ⋅ 点赞:(0)

       利用C++开发运动控制卡的动态链接库,在类的定义有包括了一些WINDOWS的信号量操作,但有些用户在使用QT环境调用时就发生了问题,如下图所示 。

        该动态链接库的部分原始代码(头文件)如下所示:

class myNetSocket;
class CSerialPort;

class EXPORTS_DEMO MoCtrCard
{
public:
	MoCtrCard();
	~MoCtrCard();

	// RS232 接口
	McCard_UINT16 MoCtrCard_Initial(McCard_UINT8 ComPort);
	McCard_UINT16 MoCtrCard_Unload();

	// 四轴的接口
	McCard_UINT16 MoCtrCard_MCrlAxisMove(McCard_UINT8 AxisId, McCard_INT8 SpdDir);
	McCard_UINT16 MoCtrCard_MCrlAxisRelMove(McCard_UINT8 AxisId, McCard_FP32 DistCmnd, McCard_FP32 VCmnd, McCard_FP32 ACmnd);

private:
	CRITICAL_SECTION   mSemCommSync;    ///< 互斥通讯操作 
	McCard_UINT8 nCmndCnt;				///< 指令计数器,每下发指令自增1
	enum ePortLinkType nPortType;		///< 物理链路类型
	myNetSocket* cTCPSocket;			///< 网络接口对像
	CSerialPort* cRSPort;				///< RS232接口

};

        为了实现对 private 部分进行隐藏,达到对用户不可见的目的,上网调研后发现有两种方法可以实现: 1)利用pimpl技术,2)纯虚函数形成接口类

        通过对这两种方式的研究,决定使用pimpl方法进行对现有的DLL进行改造;那什么是pimp技术呢?参考MSDN

pimpl idiom 是一种新式 C++ 技术,用于隐藏实现、最小化耦合和分离接口。 Pimpl 是“指向实现的指针”的缩写。细节就不介绍了,而是直接套用实现。impl的实现有固定格式,如下所示:

// my_class.h
class my_class {
   //  ... all public and protected stuff goes here ...
private:
   class impl; unique_ptr<impl> pimpl; // opaque type here
};

// my_class.cpp
class my_class::impl {  // defined privately here
  // ... all private data and functions: all of these
  //     can now change without recompiling callers ...
};
my_class::my_class(): pimpl( new impl )
{
  // ... set impl values ...
}

在标头实现时,采用了c++的智能指针,因此在头文件中要加入

#include "memory"

在我们的DLL库中,具体实现方式为:

#ifndef _MYCODE_H_
#define _MYCODE_H_

#include "memory"

#ifdef MCC4DLL_EXPORTS
#define EXPORTS_DEMO _declspec( dllexport )
#else
#define EXPORTS_DEMO _declspec(dllimport)
#endif

class EXPORTS_DEMO MoCtrCard
{
public:
	MoCtrCard();
	~MoCtrCard();

	// RS232 接口
	McCard_UINT16 MoCtrCard_Initial(McCard_UINT8 ComPort);
	McCard_UINT16 MoCtrCard_Unload();

	McCard_UINT16 MoCtrCard_MCrlAxisMove(McCard_UINT8 AxisId, McCard_INT8 SpdDir);
	McCard_UINT16 MoCtrCard_MCrlAxisRelMove(McCard_UINT8 AxisId, McCard_FP32 DistCmnd, McCard_FP32 VCmnd, McCard_FP32 ACmnd);

private:
	class MoCtrCardImpl;
	std::unique_ptr<MoCtrCardImpl> m_pImpl;
};

#endif

        在CPP源文件中实现的Impl如下:

class myNetSocket;
class CSerialPort;
class MoCtrCard::MoCtrCardImpl
{
public:
	MoCtrCardImpl() {};

	CRITICAL_SECTION   mSemCommSync;    ///< 互斥通讯操作 
	McCard_UINT8 nCmndCnt;				///< 指令计数器,每下发指令自增1
	enum ePortLinkType nPortType;		///< 物理链路类型
	myNetSocket* cTCPSocket;			///< 网络接口对像
	CSerialPort* cRSPort;				///< RS232接口
};

MoCtrCard::MoCtrCard():pimpl(new MoCtrCardImpl())
{
	pimpl->nCmndCnt = 0x00;
	pimpl->nPortType = ePortNone;					///< 物理链路类型
	pimpl->cTCPSocket = new myNetSocket();		///< 网络接口对像
	pimpl->cRSPort = new CSerialPort();			///< RS232接口
	InitializeCriticalSection(&pimpl->mSemCommSync);	///< 收发信号量
}

        经过以上改造后,DLL可以直接用在现有的应用程序中,在现有的DEMO程序上进行测试,原始程序不做任何修改,测试成功。

 

本文含有隐藏内容,请 开通VIP 后查看

网站公告

今日签到

点亮在社区的每一天
去签到