C++中的跨平台OOP

ShZ*_*ShZ 11 c++ oop cross-platform

当然,我知道最好的答案是"不要编写自己的跨平台代码,有人已经完成了你需要的东西",但我这样做是为了一个业余爱好/学习练习而不是任何付费容量.基本上,我正在用C++编写一个小型的控制台应用程序,我想让它跨平台,处理文件,套接字和线程等事情.OOP似乎是处理这个问题的一种很好的方法,但我还没有找到一个很好的模式来编写共享相同界面跨平台的类.

简单的方法是只计划一些元接口,在整个程序的其余部分使用它,然后根据平台编译不同文件的同一个类,但我觉得必须有一个更优雅的更好的方法; 至少,一些不会混淆IntelliSense及其同类产品的东西会很好.

我已经看了wxWidgets源代码中的一些较小的类,他们使用的方法使用保存类的私有成员,例如

class Foo
{
    public:
        Foo();

        void Bar();
    private:
        FooData data;
};
Run Code Online (Sandbox Code Playgroud)

然后,您可以通过根据平台选择不同的实现文件来编译它.这种方法对我来说似乎很笨重.

我考虑的另一种方法是编写一个接口,并根据平台交换从该接口继承的类.像这样的东西:

class Foo
{
    public:
        virtual ~Foo() {};
        virtual void Bar() = 0;
};

class Win32Foo
{
    public:
        Win32Foo();
        ~Win32Foo();
        void Bar();
};
Run Code Online (Sandbox Code Playgroud)

当然这种搞砸了实际的实例化,因为你不知道创建一个对象的实现,但是可以通过使用一个函数来解决

Foo* CreateFoo();
Run Code Online (Sandbox Code Playgroud)

并根据您正在运行的平台改变功能的实现.我也不是这方面的忠实粉丝,因为它仍然看起来很笨拙,用一堆实例化方法乱丢代码(这也与创建非跨平台对象的方法不一致).

这两种方法中的哪一种更好?有没有更好的办法?

编辑:为了澄清,我的问题不是"你如何编写跨平台的C++?" 相反,它是"使用C++中的类抽象跨平台代码的最佳方法是什么,同时尽可能保留类型系统的好处?"

Cha*_*via 15

要实际实现需要OS支持的跨平台功能(如套接字),您将不得不编写无法在某些平台上编译的代码.这意味着您的面向对象设计需要使用预处理程序指令进行补充.

但是,既然你必须使用预处理器,那么继承自基类的东西win32socket(例如)socket是否必要或有用是值得怀疑的.当在运行时多态选择不同的函数时,OO通常是有用的.但跨平台功能通常更多是编译时问题.(例如,win32socket::connect如果该函数甚至不能在Linux上编译,那么在多态调用中没有用!)因此,简单地创建一个socket根据平台使用预处理器指令实现不同的类可能更好.

  • 没有必要使用预处理器条件来丢弃代码 - 只需将特定于平台的代码放入单独的文件中,然后在makefile/build脚本中进行选择. (9认同)
  • @ShZ,我理解,但我所说的是虚拟函数和OO通常是一种运行时机制,因此对于设计跨平台代码而言并非真正有用或必要. (2认同)

GMa*_*ckG 12

定义您的界面,转发到detail呼叫:

#include "detail/foo.hpp"

struct foo
{
    void some_thing(void)
    {
        detail::some_thing();
    }
}
Run Code Online (Sandbox Code Playgroud)

"detail/foo.hpp"是这样的:

namespace detail
{
    void some_thing(void);
}
Run Code Online (Sandbox Code Playgroud)

然后,您将在detail/win32/foo.cpp或中实现此功能detail/posix/foo.cpp,并根据您编译的平台,编译其中一个.

通用接口只是将调用转发给特定于实现的实现.这类似于增强它的方式.你会想看看提升以获得完整的细节.

  • 你创建一个`file_handle`类,通常把句柄填充到`void*`中.实现可以将其转换回它所需要的.标准保证这是安全的.如果你动态加载实现,这个方法也很有效,因为你只需用库中加载的`some_function_pointer`替换`detail :: whatever`. (2认同)