我需要维护一个支持在Linux和Windows上运行的项目。使用像这样的预处理器指令的一些代码很好。
#ifdef _WIN32 // _WIN32 is defined by Windows 32 compilers
#include <windows.h>
#else
#include <unistd.h>
#endif
但有些是实际的实现,我想阻止使用预处理器指令。
void Foo()
{
#ifdef _WIN32 // _WIN32 is defined by Windows 32 compilers
code for windows
#else
code for Linux
#endif
some common code...
#ifdef _WIN32 // _WIN32 is defined by Windows 32 compilers
code for windows again
#else
code for Linux again
#endif
}
所以事情变得复杂,难以维持。还有更好的办法吗?
答案 0 :(得分:8)
传统的方法是“隐藏”特定于包装函数中任何操作系统的所有代码 - 您可以在执行更高级别功能的完整函数中执行此操作 - 例如,具有基于给定路径作为输入返回所有目录条目的功能,或者实现各个基本功能,例如, start_read_directory(path)
,read_dir_entry()
,end_read_directory()
- 这只是一个示例功能,几乎所有系统特定功能都可以应用相同的原则。包好它,你就无法分辨出你的编程。
从本质上讲,如果代码本身有很多#ifdef,那么你做错了。
答案 1 :(得分:8)
处理构建系统中的操作系统细节,而不是代码。例如,有两个版本的Foo.cpp:一个在Linux上编译,另一个在Windows上编译。理想情况下,头文件将是通用的,并且所有函数签名都相同。
答案 2 :(得分:5)
您可以使用工厂模式的简化版本。
有一个通用界面
class MyClass
{
public:
virtual void Foo() = 0;
};
对于每个平台,您都可以创建一个特定的类
#import <windows.h>
class MyClassWindows : MyClass
{
public:
virtual void Foo() { /* Do something */ }
};
#import <linux.h>
class MyClassLinux : MyClass
{
public:
virtual void Foo() { /* Do something */ }
};
然后当你需要这个课程时,你可以使用你的工厂:
class MyClassFactory
{
public:
static MyClass* create()
{
#if defined _WIN32
return new MyClassWindows();
#elif defined _LINUX
return new MyClassLinux();
#endif
}
}
此方法有许多变体,包括在每个特定于平台的类的.cpp中定义MyClassFactory :: create方法,并仅为相应的平台编译.cpp。这避免了所有预处理指令,通过选择正确的实现文件进行切换。
答案 3 :(得分:4)
常见的模式是提供系统独立的头文件和特定于平台的实现文件。
标题中没有特定的平台:
class Foo
{
...
};
在两个不同的实现文件中,foo_linux.cpp
Foo::Foo() { .. linux code }
foo_windows.cpp
Foo::Foo() { .. windows code }
并且可能在foo.cpp中独立于平台
void Foo::plat_independent_function()
您的平台构建然后链接到foo.cpp和foo_platform.cpp
答案 4 :(得分:0)
实现这一点的可能性是使用PIMPL习惯用法,你的类只发布“接口”并声明一个无意义的指向实现类的指针(在它的黑暗,隐藏和私有角落),构建系统需要注意为包含PIMPL实现的类提供正确的平台相关代码。