我听说编写跨平台c ++代码的方法是按如下方式定义类(例如,一个Window类):
window.h
window_win32.cpp
window_linux.cpp
window_osx.cpp
然后相应地选择实现文件。
但是,如果我有那个类的成员相对于操作系统呢?就像Win32实现的HWND
成员一样。我不能把它放在window.h
中,或者当我试图在Linux上编译它时,它会产生编译错误。
我需要#ifdef
吗?我已经问了一个类似的问题,但是这个问题更关注这个问题。
答案 0 :(得分:22)
有更多方法可以解决这个问题 - 每个方法都有它的优点和缺点。
1。)使用宏#ifdef,#endif
// Note: not sure if "WINDOWS" or "WIN32" or something else is defined on Windows
#ifdef WINDOWS
#include <window.h>
#else
// etc.
#endif
class MyClass
{
public:
// Public interface...
private:
#ifdef WINDOWS
HWND m_myHandle;
#else
// etc.
#endif
};
优点:
缺点:
2。)正如已经写过的那样,你可以使用多态:
// IMyClass.h for user of your class:
class IMyClass
{
public:
virtual ~IMyClass() {}
virtual void doSomething() = 0;
};
// MyClassWindows.h is implementation for one platform
#include <windows.h>
#include "IMyClass.h"
class MyClassWindows : public IMyClass
{
public:
MyClassWindows();
virtual void doSomething();
private:
HWND m_myHandle;
};
// MyClassWindows.cpp implements methods for MyClassWindows
优点:
缺点:
3。)PIMPL习语。
// MyClass.h
class MyClass
{
public:
MyClass();
void doSomething();
private:
struct MyClassImplementation;
MyClassImplementation *m_impl;
}
// MyClassWindows.h
#include <windows.h>
#include "MyClass.h"
struct MyClassImplementation
{
HWND m_myHandle;
void doSomething();
}
在这种情况下,MyClassImplementation保留所有需要的(至少是特定于平台的)数据并实现所需(同样,特定于平台)。在MyClass.cpp中,您可以在构造函数中包含特定于平台的实现(方法可以是内联的)(或者稍后如果您需要 - 请小心)您分配实现,并且在析构函数中您将销毁它。
优点:
缺点:
4.。)定义一个中性类型,它足以保存您的数据。例如long long int。
// MyClass.h
class MyClass
{
public:
MyClass();
void doSomething();
private:
typedef unsigned long long int MyData;
MyData m_data;
};
在实现中(例如MyClassWindows.cpp),您总是需要在MyClass :: MyData和存储的实际数据之间进行转换(重新解释转换)。
优点:
缺点:
所以使用最适合你问题的那个......以及你的个性:3因为今天的力量在速度和空间方面都差不多相对平等。
答案 1 :(得分:3)
这种方法的关键是,您将OS特定数据封装在特定于os的文件中。如果你必须通过HWND,那么你可能会重新考虑你的对象设计。这样的strcuture是否有意义取决于你的os特定代码有多大。你真的不想将所有可能的类压缩到一个文件中。
另一方面,有一些GUI正在执行此操作 - 将操作系统特定部分封装在库中,如QT或wxWidgets或其他。如果您正确地将GUI与主代码分开,那么您甚至可能不需要这种方法。
我在我的项目中使用这样的结构来支持不同版本的xerces,而不会使主代码与#ifdefs
混乱。但在我的情况下,受影响的代码相当小。我可以想象GUI框架需要更多的空间。
答案 2 :(得分:2)
我只会在@ Laethnes&#39;中添加一个子弹。答案
5)编写一个空头,在编译时包含平台头,并在typedef下隐藏特定于平台的类
// MyClass.hpp
#if defined(WINDOWS)
# include "WINMyClass.hpp"
typedef WINMyClass MyClass
#elif defined(OSX)
# include "OSXMyClass.hpp"
typedef OSXMyClass MyClass
... // keep going
#endif
优点:
缺点:
答案 3 :(得分:0)
执行此操作的常用方法是使用多态。您提供了一个界面,可以在不考虑特定平台的情况下抽象您的功能:
class thread
{
virtual ~thread() {}
virtual void run() = 0;
/* whatever */
};
然后您可以使用特定于平台的功能继承此类:
class posix_thread : thread;
在编译时,您使用#ifdef
选择包含的类并进行实例化。
答案 4 :(得分:0)
大多数情况下,你会在标题中避免这样的事情。那里 但是,当你想要公开它们时。在这样的 例如,我的解决方案一直是使用类似的东西:
#include dependentInclude(syst,MyInclude.lhh)
dependentInclude是一个扩展到路径的宏 我需要的文件,取决于syst的值(已设置) 在命令行上)。