使用C ++实现平台独立性。检测和编译

时间:2011-10-15 18:22:07

标签: c++ cross-platform

所以我想将我的应用程序构建为独立于平台,以便它可以在Windows,OSX,Linux等上运行。

例如,平台上不同的主要“部分”之一是Window。在Windows上,它将使用Win32 API,在OSX,Linux上,我想它会使用其他东西。

我有一个IWindow.h类,它是一个与Window和MSWindow类交互的接口,它封装了所有Win32函数并扩展了IWindow接口。

将来我会创建一个OSXWindow类等等

所以我的两个问题点是:

  1. 在某些时候,我需要检测我正在运行的平台并实例化正确的类。我想我将不得不为包含一些ifdef块,然后还有实例化本身?
  2. 
        #ifdef RUNNING_WINDOWS
        #include 
        #elif RUNNING_OSX
        #include 
        #endif
    
    
    
        //m_window is declared as IWindow* m_window;
        #ifdef RUNNING_WINDOWS
        m_window = new MSWindow();
        #elif RUNNING_OSX
        m_window = new OSXWindow();
        #endif
    
    

    显然RUNNING_WINDOWS和RUNNING_OSX组成了,如果有人知道我可以查找的实际标记,那将是值得赞赏的。

    1. 我的main.cpp入口点目前在Windows上。
    2. 
          //Main Entry point to windows application
          int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
      
      

      并且必须将hInstance传递给MSWindow类。这提出了一个问题,因为我的IWindow接口无法接受HINSTANCE,因为HINSTANCE是Windows的一部分,在OSX或Linux上不存在。我的main.cpp中是否有单独的入口点函数被ifdefs阻塞?

      IWindow会有一个Init函数,它也会根据ifdef接受不同的参数吗?

      #ifdef RUNNING_WINDOWS
      bool Init(HINSTANCE* hInstance);
      #elif RUNNING_OSX
      bool Init(Whatever OSX needs);
      #endif
      

      我可能会认为这一切都是错的,所以希望你可以进来让我走上正确的道路。

      谢谢!

      编辑:

      根据以下评论,我将添加更多有关我的目标的信息。

      基本上我有一个核心类是我的应用程序。我的main.cpp实例化了这个Core类的一个实例,而且几乎就是它。

      Core类将具有Window类的实例。核心不应该关心它是什么类型的窗口,它只需要与它进行交互。

      然后,我收集的Window本身(从下面的评论中)将内部处理平台独立性方面。因此,由于#ifdef块,Window可能会变得混乱,但应用程序的其余部分以及与Window交互的任何内容都不会关心。

      我采用的另一个选项和第一个方向是,每个“Type”的Window实现都有一个单独的类,它们来自一个常见的IWindow接口。然后#ifdefs将在Core中发生,以实例化和包含哪种类型。虽然这将OS的实现分开,但我同意它会使Core混乱,如果Application的任何其他未来部分需要引用Window,那么它还需要#ifdef块,这只会导致整个代码更加混乱。

2 个答案:

答案 0 :(得分:2)

实际上,最好的方法是通过创建一个包装Window的类来封装Window的整个概念。然后,这个类可以通过非API特定的函数提供所需的接口,因此使用它的东西甚至不需要知道你将要使用的Win32 API,GTK或其他任何窗口系统如何工作。简而言之,您不希望每次需要启动窗口时都使用#ifdef,但希望将它们隐藏在其他类中。我已经使用Qt Framework作为一个非常强大的跨平台框架来实现这一点,并允许在Windows,Mac,Linux和其他平台上编译相同的C ++。它提供对Windowing系统的跨平台标准化访问,网络连接,线程,媒体播放,文件系统访问等等。

如果你真的想重新发明轮子并编写自己的包装类,你应该查看定义的编译器特定宏,以确保你想要支持的平台到位。这是一个寻找macros are defined on what platforms by what compilers的好地方。一些常见的宏是_WIN32用于Visual Studio编译,而__unix__用于基于Unix的平台。

答案 1 :(得分:2)

我做过类似的事情,所以我可以提供一些建议。

  • 虽然可以调用你的Window类MSWindow,OSXWindow等,但这真的不方便,因为需要与Window交互的代码的每个部分都需要知道哪一个使用。你应该只调用这些类Window。由于您只会在给定平台中编译其中一个,因此不会发生冲突。

  • 检查给定操作系统的宏:

    • _WIN32 for Windows
    • __APPLE__用于OSX和iOS(我在pch文件中设置了自己的常量来区分这两个)
    • __linux__ for Linux
  • 我建议您不要在上面添加#define。如果您将跨平台特定代码放在尽可能少的位置,您将拥有更多可移植代码。

  • 您将在每个平台上拥有不同的主要功能。 Windows上为WinMain(),其他人为main()。我建议您将它们放在不同的文件中,并且只引用与makefile或项目文件中的正确平台对应的文件。

  • 您提出的HINSTANCE问题很容易解决。在WinMain()函数中,您将HINSTACE赋予Window类。 Windows上的Window类将有一个静态方法,比方说setHinstance(),它将HINSTACE存储在类变量中。然后,当创建一个Window实例时,HINSTACE将可用而无需更改此类的常用方法。

  • 作为最后的评论,您应该记住,有几个跨平台的GUI框架可能对您有用。如果你想要一个功能齐全的,请看Qt。如果你想要一个非常简单的(有一些不错的功能,但没有Qt那么多),那么看看FLTK。 Qt和FLTK都是开源的。