5

我们在我们的大项目中有中心类和函数来从实际的平台类型中抽象出来,例如互斥体、文件、线程等,而不是在代码中到处都有“fopen”。虽然这很好,但我想更进一步,头文件中不包含任何系统(如#include <windows.h>),这将是真正的平台抽象和更快的编译。不利的一面是,您不能只将类型定义为系统类型(例如 Windows HANDLE)。

选项1:PImpl-idiom

class RwMutex
{
    // .....
private:
   struct Impl;
   Impl*   m_Impl;
}
  • 优点:实现和平台类型很好地隐藏在 Cpp 中。
  • 缺点:涉及可能失败的两阶段建设(“新”,我们没有例外)。做事费劲。

选项 2:命名空间函数

class RwMutex {
public:
    bool LockRead() {return RwMutexLockRead( this );}
private:
    char m_AnonymousMember[ 16 ];
}
bool RwMutexLockRead( RwMutex* p );
  • 优点:实现可以只链接到它,非常适合将其单独放入库中。
  • 缺点:涉及包含成员的空间的 reinterpret_cast。在调试器中不好。还有很多工作。

也许我很渴望它,但如果大量项目代码将清除任何依赖于平台的包含,那将是很酷的,可能由-nostdinc选项强制执行。

4

2 回答 2

4

使用指针的选项 1 是个坏主意。使用其中一个boost::scoped_ptr,或者,如果可以,使用std::unique_ptr.

选项 2 在您实施时不应使用。请参阅GotW #28:快速 Pimpl 成语。然而,在 C++11 中,这可以使用std::aligned_storage<>. 我曾经写过一个pimpl_ptr<T, Size, Align=default>为你执行强制转换、复制、析构函数的调用,并检查你是否选择了正确的Size.

一般来说,使用 pimpl 除非您已经分析并表明这是瓶颈。

但一如既往,不要重新发明轮子。Mutex 和 Threads 是新 C++11 标准的一部分,因此要么升级编译器,要么改用 Boost。对于文件,请使用 Boost。原因是,新的 C++11 库的许多部分都取自 Boost。

于 2012-12-06T13:05:12.677 回答
2

为什么还要有一个实现对象?您的代码不仅会在同一个平台上更改,而且您将在您当前使用的平台上使用相同的实现。在标头中定义接口,并为您所针对的每个平台的实现提供各种 *.cpp 文件。使用#ifndef、#else 等。

例如,您的文件系统可能如下所示:

include/
    RwMutex.hpp
    // etc...
src/
    RwMutex/
       RwMutexWin32.cpp
       RwMutexUnix.cpp
       // etc... 

以下是 RwMutexWin32.cpp 的样子:

#ifdef MYLIBPREFIX_PLATFORM_WIN32
#include "RwMutex.hpp"

#include <Windows.h>

// implement the Windows version of the RwMutex class

另一个例子可能是查看 SDL,或其他一些用 C 或 C++ 编写的跨平台库。他们主要使用预处理器系统。您不太可能想要更改 Impl 对象指向的内容(即 Windows 机器上的 Unix 实现没有意义,也不会编译)。

当然,如果您真的想这样做,我建议您使用CMake。但是正如其他人建议的那样,您应该尝试使用其他库,例如boost标准库,它已经为您编写了。

于 2012-12-06T13:30:37.027 回答