多平台类设计C++

Multiplatform class design C++

本文关键字:C++ 平台      更新时间:2023-10-16

我有一个关于在C++中处理多平台接口的非标准方法的想法,并想知道这通常是否是一个坏主意以及为什么。

目前我只能想到一个缺点:对这样的事情非常(?)不常见,也许乍一看它是如何工作的并不明显:

我有一个将在不同平台上使用的类,例如 CMat4x4f32(使用 32 位浮点数的 4x4 矩阵类)。我的平台独立界面如下所示:

class CMat4x4f32
{
public:
    //Some methods
    #include "Mat4x4f32.platform.inl"
};

Mat4x4f32.platform.inl 看起来像这样:

public:
    // Fills the matrix from a DirectX11 SSE matrix
    void FromXMMatrix(const XMMatrix& _Matrix);

它只是向矩阵类添加一个依赖于接口的平台。

.cpp和 Mat4x4f32.platform.inl 位于"win32"或"posix"等子文件夹中,因此在 win32 中我实现了 FromXMMatrix 函数。我的构建系统根据我构建的平台将这些子文件夹添加到包含路径。

我甚至可以更进一步,实现一个 .platform.cpp它位于 win32 内部,只包含我添加到该平台界面的功能。

我个人认为这是一个好主意,因为它使编写和使用界面变得非常容易和干净。特别是在我的渲染器库中大量使用我的基本库中的矩阵类中,我现在可以在 DirectX 部分中使用依赖于平台的函数 (FromXMMatrix),就好像我没有任何其他平台需要担心一样。

在基础库本身中,我仍然可以使用公共矩阵接口编写独立于平台的代码。

我还有其他有用的类:例如,一个 Error 类,它收集错误并自动将它们转换为可读消息并提供一些调试选项。对于win32,我可以从糟糕的DirectX和Win32 HResults创建错误实例,而在Linux上,我可以从返回的errno创建它们。在基本库中,我有一个使用公共错误接口管理这些错误的类。

它大大减少了所需的代码,并防止了依赖于实用程序类的丑陋平台。

那么这是坏设计还是好设计,还有什么替代方案?

听起来你在谈论使用桥接模式:http://c2.com/cgi/wiki?BridgePattern

根据我的个人经验,我开发了很多独立于平台的接口,使用这种模式的特定实现并且效果很好,我经常将其与 Pimpl 习语一起使用:http://c2.com/cgi/wiki?PimplIdiom

与替代方案一样,我发现这个网站总体上非常适合解释各种模式和范式的优缺点:http://c2.com/cgi/wiki

我建议你改用"pimpl":

class CMat4x4f32
{
public:
    CMat4x4f32();
    void Foo();
    void Bar();
private:
    std::unique_ptr<CMat4x4f32Impl> m_impl;
};

然后在构建文件配置中拉入特定于平台的.cpp文件,例如,您可以在其中定义特定于平台的功能:

class CMat4x4f32::CMat4x4f32Impl
{
public:
    void Foo() { /* Actual impl */ }
    void Bar() { /* Actual impl */ }
    // Fills the matrix from a DirectX11 SSE matrix
    void FromXMMatrix(const XMMatrix& _Matrix);
};
CMat4x4f32::CMat4x4f32() : m_impl(new CMat4x4f32Impl()) {}
CMat4x4f32::Foo() { m_impl->Foo(); }
CMat4x4f32::Bar() { m_impl->Bar(); }