C++ C+中的跨平台OOP+;
当然,我知道最好的答案是“不要写你自己的跨平台代码,有人已经做了你需要的”,但我这样做是作为一种爱好/学习练习,而不是以任何付费的身份。基本上,我在C++中编写了一个小的控制台应用程序,我想让它跨平台,处理文件、套接字和线程之类的东西。OOP似乎是处理这个问题的一个很好的方法,但是我还没有找到一个好的模式来编写跨平台共享相同接口的类 简单的方法是规划一些元接口,在程序的其余部分使用它,根据平台的不同使用不同的文件编译同一个类,但我觉得必须有一种更好的方法,更优雅;至少,一些不会混淆IntelliSense及其同类的东西会很好 我查看了wxWidgets源代码中的一些较小的类,它们使用一种方法,使用一个私有成员来保存类的数据,例如C++ C+中的跨平台OOP+;,c++,oop,cross-platform,C++,Oop,Cross Platform,当然,我知道最好的答案是“不要写你自己的跨平台代码,有人已经做了你需要的”,但我这样做是作为一种爱好/学习练习,而不是以任何付费的身份。基本上,我在C++中编写了一个小的控制台应用程序,我想让它跨平台,处理文件、套接字和线程之类的东西。OOP似乎是处理这个问题的一个很好的方法,但是我还没有找到一个好的模式来编写跨平台共享相同接口的类 简单的方法是规划一些元接口,在程序的其余部分使用它,根据平台的不同使用不同的文件编译同一个类,但我觉得必须有一种更好的方法,更优雅;至少,一些不会混淆Intelli
class Foo
{
public:
Foo();
void Bar();
private:
FooData data;
};
然后,您可以通过根据平台选择不同的实现文件来编译它。这种方法在我看来相当笨拙
我考虑的另一种方法是编写一个接口,并根据平台交换从该接口继承的类。大概是这样的:
class Foo
{
public:
virtual ~Foo() {};
virtual void Bar() = 0;
};
class Win32Foo
{
public:
Win32Foo();
~Win32Foo();
void Bar();
};
当然,这种情况会破坏实际的实例化,因为您不知道要为哪个实现创建对象,但是可以通过使用函数来解决
Foo* CreateFoo();
并根据您运行的平台改变功能的实现。我也不是一个超级粉丝,因为它仍然用一堆实例化方法乱扔代码(这也与创建非跨平台对象的方法不一致)
这两种方法中哪一种更好?有更好的办法吗
<> > >编辑:,我的问题不是“如何编写跨平台C++”,而是“用C++中的类抽象跨平台代码的最佳方法是什么,同时尽可能保留类型系统的好处?”< P>实际需要实现需要OS支持的跨平台功能,(比如sockets)您将不得不编写无法在特定平台上编译的代码。这意味着您的面向对象设计将需要使用预处理器指令进行补充
但由于您无论如何都必须使用预处理器,因此像
win32socket
(例如)这样的东西是否从套接字继承而来的
基类甚至是必要的或有用的。当运行时以多态方式选择不同的函数时,OO通常很有用。但跨平台功能通常更像是编译时的问题。(例如,如果该函数甚至没有在Linux上编译,则以多态方式调用win32socket::connect
是没有用的!)因此,最好只创建一个socket
类,该类根据使用预处理器指令的平台的不同而实现不同。第二种方法更好,因为它允许您创建仅存在于其中一个平台上的成员函数。然后,您可以在平台中使用抽象类orm独立代码,以及平台特定代码中的具体类
例如:
class Foo
{
public:
virtual ~Foo() {};
virtual void Bar() = 0;
};
class Win32Foo : public Foo
{
public:
void Bar();
void CloseWindow(); // Win32-specific function
};
class Abc
{
public:
virtual ~Abc() {};
virtual void Xyz() = 0;
};
class Win32Abc : public Abc
{
public:
void Xyz()
{
// do something
// and Close the window
Win32Foo foo;
foo.CloseWindow();
}
};
理想情况下,您可以将差异集中在尽可能低的级别。
因此,顶级代码调用Foo(),只有Foo()需要在内部关注它调用的操作系统
注意:看看“boost”,它包含了很多处理跨平台网络文件系统等的东西,定义您的接口,它转发到
详细信息调用:
#include "detail/foo.hpp"
struct foo
{
void some_thing(void)
{
detail::some_thing();
}
}
其中“detail/foo.hpp”类似于:
namespace detail
{
void some_thing(void);
}
然后,您将在detail/win32/foo.cpp
或detail/posix/foo.cpp
中实现这一点,并根据编译所针对的平台,编译一个或另一个
公共接口只是将调用转发到特定于实现的实现。这与boost的方式类似。您需要查看boost以获得完整的详细信息。在您的第一个示例中或GMan的授权工作得非常好,特别是当特定于平台的部分需要许多特定于平台的成员时(例如,只存在于一个平台中的类型的成员)。缺点是您必须维护两个类
如果类变得更简单,没有很多特定于平台的成员,那么您可以只使用一个公共类声明,并在两个不同的.cc文件中编写两个实现(对于独立于平台的方法实现,可能还有第三个.cc)。对于少数平台特定的成员或具有平台特定类型的成员,您可能需要在头文件中添加一些IFDEF。这种方式更像是一种黑客行为,但可以更容易地开始使用。如果代理失控,您可以随时切换到代理。跨平台不需要执行OOP。跨平台更像是一种架构结构与设计范式
我建议将所有特定于平台的代码与标准代码(如sockets GUI)隔离。跨不同平台比较这些代码,并编写通用层或包装器。在代码中使用此层。创建库函数以实现通用层的特定于平台的实现
特定于平台的函数应位于单独的库或文件中。您的生成过程应为特定平台使用正确的库。您的“标准”不应更改代码。正如其他人所指出的,继承对于作业来说是一个错误的工具。在您的案例中使用的具体类型的决定是在构建时做出的,而经典的多态性使该决定能够在运行时做出(即,作为用户操作的结果)。您可以使用模板专门化来分离c
enum platform {mac, lin, w32};
template<platform p = mac>
struct MyClass
{
// Platform dependent stuff for whatever platform you want to build for default here...
};
template<>
struct MyClass<lin>
{
// Platform dependent stuff for Linux...
};
template<>
struct MyClass<w32>
{
// Platform dependent stuff for Win32...
};
int main (void)
{
MyClass<> formac;
MyClass<lin> forlin
MyClass<w32> forw32;
return 0;
}