6

按照我之前关于虚拟和多重继承的问题(在跨平台场景中) - 在阅读了一些答案之后,我想到我可以通过保留服务器和客户端类来简化我的模型,并将平台特定的类替换为#ifdefs(这是我最初要做的)。

使用这段代码会更简单吗?这意味着至少会有更少的文件!缺点是它创建了一个有点“丑陋”并且稍微难以阅读Foobar的课程,因为到处#ifdefs都是。#ifdef请注意,我们的 Unix Foobar 源代码将永远不会传递给编译器,因此这与(因为我们还使用#ifdef来决定要调用哪个平台特定的类)具有相同的效果。

class Foobar {
public:
  int someData;

#if WINDOWS
  void someWinFunc1();
  void someWinFunc2();
#elif UNIX
  void someUnixFunc1();
  void someUnixFunc2();
#endif

  void crossPlatformFunc();
};

class FoobarClient : public Foobar;
class FoobarServer : public Foobar;

注意:为了更简单的示例,省略了一些东西(ctor 等)。

更新:

对于那些想要了解更多关于这个问题的背景的人,我真的建议浏览相应的邮件列表线程。事情开始在第 3 篇文章中变得有趣起来。还有一个相关的代码提交,您可以在这里看到有问题的真实代码。

4

5 回答 5

10

最好在方法中包含依赖于平台的操作性质,以便类声明跨平台保持相同。(即,在实现中使用#ifdefs)

如果你不能这样做,那么你的类应该是两个完全独立的类,每个平台一个。

于 2010-01-02T00:28:17.157 回答
5

我个人的偏好是将ifdef魔法加入到 make 文件中,因此源代码尽可能保持干净。然后每个平台都有一个实现文件。这当然意味着您可以为所有受支持的系统提供一个通用接口。

编辑:

为跨平台开发绕过这种低分母设计的一种常见方法是不透明的句柄习语。与逃生路线相同的想法ioctl(2)- 有一个方法返回为每个平台定义不同的不透明前向声明结构(最好在实现文件中),并且仅在通用抽象不成立时使用它。

于 2010-01-02T00:35:44.433 回答
2

如果您完全确定不会在已编译的操作系统上使用来自其他操作系统的函数,那么使用 ifdef 有很多优点:

  1. 未使用的代码和变量不会编译到可执行文件中(但是智能链接在这里有点帮助)
  2. 很容易看到什么代码是实时的
  3. 您将能够轻松地包含平台相关文件。

但是,基于操作系统的分类仍然有它的好处:

  1. 您将能够确保在为某个平台进行更改时代码可以在所有平台上编译
  2. 代码和设计会更干净

后者是通过在类主体本身中定义特定于平台的代码来实现的,或者只是在编译中定义不支持的操作系统实例。

于 2010-01-02T00:26:49.317 回答
2

我的偏好是将特定于平台的问题推送到最模块,并尝试将它们包装到一个通用接口中。将具体的方法、类和函数放入单独的翻译单元中。让链接器和构建过程确定要组合哪些特定的翻译单元。这使得代码更简洁,调试时间更容易。

From experience, I had a project that used #ifdef VERSION2. I spent a week in debugging because one module used #ifdef VERSION_2. A subtlety that would be easier to catch if all the version 2 specific code was in version 2 modules.

于 2010-01-02T00:43:26.980 回答
0

为特定于平台的代码使用#ifdefs 是惯用的;特别是因为如果在另一个平台上启用了一个平台的代码,它甚至不会编译。听起来对我来说是个好方法。

于 2010-01-02T00:26:48.147 回答