说明用 C++ 编写抽象层的简单示例
Posted
技术标签:
【中文标题】说明用 C++ 编写抽象层的简单示例【英文标题】:Simple example to illustrate writing an abstraction layer in C++ 【发布时间】:2012-10-03 01:50:42 【问题描述】:我只有 C++ 的基本知识。我正在尝试在 C++ 中实现硬件抽象层(HAL)。假设我想实现这个名为 Data 的类。基于平台,数据可以通过有线或无线方式发送。
class Data()
public Data()
//create random data
public sendData()
// send data
public platform_action1()
// do some platform specific action
// My HAL
int HAL()
Data myData;
myData.platform_action1();
myData.sendData();
return 0;
现在,如果我有有线和无线两个平台,我该如何扩展这个类并组织我的文件,以使HAL()
保持不变。
我也不想要动态绑定,即使用关键字“虚拟”。 在我的例子中,平台在编译时是已知的。
// 我不想这样做 :) ...
int HAL()
Data* data = new WiredData();
data.sendData();
data = new WirelessData();
data.sendData();
在我的例子中,平台在编译时是已知的。
来自 C 世界,这就像填写平台特定的函数指针一样简单。
以 Boost C++ API 中的“线程”类为例。该类通过调用基于平台的 Windows 线程 API 或 Linux 线程 API 来自动生成线程。这样,我的 HAL 就真正独立于平台了。
谢谢 克里斯【问题讨论】:
你应该尝试一些东西,如果它不起作用,问为什么。不要只要求人们填写空白。 【参考方案1】:这更像是一个设计问题,而不是一个实际的 C++ 问题,但您要查找的术语是 polymorphism
。您可以使用您的 Data
类并创建两个继承自它的类 WiredData
和 `WirelessData,这将使您能够执行以下操作:
Data data1 = new WiredData();
Data data2 = new WirelessData();
data1.sendData();
data2.sendData();
当您在 data1 和 data2 对象上调用 sendData()
时,多态性开始发挥作用,编译器将为每个特定子类型调用 sendData()
方法,即使它们被声明为 Data
类型
【讨论】:
猎人,我真的不想这样做:Data data1 = new WiredData();数据数据2 =新的无线数据();我只想在 sendData() 调用期间弄清楚数据连接。以 Boost C++ API 中的“线程”类为例。该类通过调用基于平台的 Windows 线程 API 或 Linux 线程 API 来自动生成线程。这样我的 HAL 就真正独立于平台了。【参考方案2】:来自 C 世界,这就像填写平台特定的函数指针一样简单。
在 C++ 中几乎相同。您可以使 Data 类的 sendData() 函数 virtual
(在签名前加上 virtual
关键字),然后派生指定适当的 sendData()
功能的有线和无线实现类。然后,您可以使用某种 if 语句来决定使用哪一个,并根据需要为 Wired
或 Wireless
对象保留一个 Data*
变量...当您调用 pointer->sendData()
时,它将调用相应的执行。这都是非常基础的——你应该在网上做一些介绍性的 C++ 教程,或者拿一本书。还有其他列出推荐培训材料的 *** 问题。
编辑:根据您在下面评论中的要求提供大纲。
class Wrapper
Data* p_;
public:
void sendData()
if (not p_)
p_ = ... ? new Wired() : new Wireless();
p_->sendData();
【讨论】:
托尼,感谢您的回复。想过做你提到的同样的事情。但是在 main() 调用中,我不想知道我下面是否有有线或无线平台。后期可以pointer->sendData()选择平台吗?virtual
函数的正确(大多数派生)版本在运行时解析,因此您无需知道main
中的实际类型是什么。这是一个核心语言特性;你应该按照 Tony 的建议找到一本书或教程。
请看Hunter回复的帖子。
@user1715819:当然——您可以将 Wires 与 Wireless 的决定移动到包装器类中,因此它会选择在方便的时候实例化哪一个。为此,您需要四个类:main()
直接使用的包装器、两个实现以及一个具有描述其共享 API 的虚函数的基类。
托尼...你能不能给我提供一下包装器的代码大纲。这个包装器是宏吗?知道 Boost C++ 中的“线程”类是如何实现的吗?【参考方案3】:
为什么不将更改的成员的定义放入名为的文件中:-
Data_Windows.cpp
和 Data_Unix.cpp
(例如)然后使用您的构建系统仅在该平台上的构建中包含相关文件?还是我在这里遗漏了什么……?
【讨论】:
【参考方案4】:Can we do this using PIMPL(Private Implementation) approach? This is what I am thinking ...
// In Data.h
class PlatformDataProcess; // forward declaration of Pimpl
class Data
public:
Data (const IPC& ipc); // process IPC
~Data();
Data( const Data &rhs ); // undefined for simplicity
Data& operator=( Data );
void process_ipc();
private:
PlatformDataProcess *pimpl_; // the Pimpl
;
// In Wired.cpp
#include "Data.h"
class PlatformDataProcess
public:
void SendData() // send data on wired
;
// In Data.cpp
Data::Data() : pimpl_( new PlatformDataProcess() )
Data::~Data()
delete pimpl_;
void Data::SendData()
pimpl_->SendData(); // do some private work
int HAL()
// receive IPC
Data* data = new Data(ipc);
data->SendData();
So all the user needs to do is supply the platform specific file like wired.cpp .
【讨论】:
您对 pimpl_ (pimpl_( new PlatformDataProcess() )
) 的初始化与有线与无线的选择有何关系?对于 OO 解决方案,需要在某个地方做出选择,new
用于有线或无线。当您添加该因素时,它就变成了一个状态模式。 pImpl 有相似之处,但其意图不是在运行时改变实现,而是隐藏实现(在 C++ 中,避免在客户端可见的类/头文件中添加/删除/更改私有成员时需要重新编译)。
托尼,实际上我选择了不好的例子,即有线和无线。在我的情况下,电路板有数据芯片 1 或芯片 2。 PlatformDataProcess 的编译时间定义很好,因为我不想在我的构建中包含所有芯片的代码。以上是关于说明用 C++ 编写抽象层的简单示例的主要内容,如果未能解决你的问题,请参考以下文章