C++ 在C+中包装多个库的策略+;
我有一个类C++ 在C+中包装多个库的策略+;,c++,wrapper,abstraction,C++,Wrapper,Abstraction,我有一个类Foo,它不是直接实现的,而是包装外部库(例如footexternal1或footexternal2) 我看到的一种方法是使用预处理器指令作为 #include "config.h" #include "foo.h" #ifdef _FOOXTERNAL1_WRAPPER_ //implementation of class Foo using FooXternal1 #endif #ifdef _FOOXTERNAL2_WRAPPER_ //implementation of cl
Foo
,它不是直接实现的,而是包装外部库(例如footexternal1
或footexternal2
)
我看到的一种方法是使用预处理器指令作为
#include "config.h"
#include "foo.h"
#ifdef _FOOXTERNAL1_WRAPPER_
//implementation of class Foo using FooXternal1
#endif
#ifdef _FOOXTERNAL2_WRAPPER_
//implementation of class Foo using FooXternal2
#endif
使用config.h
定义这些预处理器标志(\u footexternal1\u WRAPPER\u
和\u footexternal2\u WRAPPER\u
)。
我认为C++程序员社区对此感到不快,因为它使用预处理器指令,调试困难等。此外,它不允许并行实现两种实现。
我考虑将Foo
作为一个基类,并从中继承,以允许两个实现并行存在。但我遇到了两个问题:
无法恢复“Foo”类型的对象
,这是我在使用过程中需要的我在一个资源有限的嵌入式系统上工作,我决定使用
模板
,模板专门化。便于后期用户理解;至少我是这么认为的我唯一不赞成的是在同一个源文件中包含这两个实现。这可能会让人困惑。否则,这是预处理器标志擅长的事情之一,特别是如果您没有同时链接两个库。这就像支持多个操作系统一样。在所有情况下提供一致的接口,并将实现细节隐藏在其他地方
typeFoo
是否需要保存每个库的特定信息?如果没有,您可能可以通过以下方式逃脱:
#include "Foo.h"
#if defined _FOOXTERNAL1_WRAPPER_
#include "Foo_impl1.cpp"
#elif defined _FOOXTERNAL2_WRAPPER_
#include "Foo_impl2.cpp"
#else
#error "Warn about a missing define here"
#endif
这样,您就不必为虚拟函数或继承而烦恼,而且仍然可以防止任何成员函数无法实现。保持
Foo
抽象。提供工厂方法
分配类型为FooImpl1
或FooImpl2
的新对象,并返回其地址
.如果外部实现的所有方法名称都相似,则可以使用模板。让外部实现看起来像:
class FooX1
{
公众:
void Met1()
{
std::cout如果您希望这两个实现在运行时共存,那么接口就是一种方法(例如,您可以使用工厂方法设计模式来实例化具体对象,如@n.m.所建议的)
如果您可以在编译时决定需要什么样的实现,那么有几个选项:
- 仍然使用接口。如果将来您在运行时需要这两种实现,这将允许轻松的转换
>P>使用预处理器指令。这里考虑到C++没有什么错误。这是一个纯粹的设计问题。
- 将实现放在不同的文件中,并根据设置将编译器配置为编译其中任何一个-这实际上类似于使用预处理器指令,但它更干净,不会向代码中添加垃圾(因为标志位于解决方案/makefile/编译器使用的任何内容中)
只要您链接两个外部库,提供一个虚拟类和两个具体类就是一个很好的解决方案——特别是在运行时您可以确定应该使用哪个库的情况下。如果您没有在两个库中进行链接(或者它们的名称空间冲突禁止链接)那么这就行不通了。#define/#ifdef并不总是友好的,但有时它是最好的解决方案。要添加到mah,如果使用包装器Foo,只需声明任何必须重写为纯虚拟的函数。一旦您尝试实例化具体子类,编译器将强制您在具体子类中提供实现。ex这正是我的意图,但我无法安装Foo,因为它是abstract类。我是否遗漏了什么?好吧,听起来你想为抽象库提供一个工厂,以选择在运行时动态提供哪个Foo实现?@mah,没有名称空间冲突,我可以链接两个库。我需要实例化Foo Thought,但你仍然需要有一个地方,让您决定是使用FooX1
还是FooX2
实例化模板-这会带回#ifdef或类似的东西。使用模板的想法很好,though@Sergey我花了一些时间思考发生了什么,但这就是我要做的
Foo* MakeFoo();
template<typename FooX>
class FooVariant1
{
public:
FooVariant1()
{
impl=new FooX();
}
void Met1Wrapper()
{
impl->Met1();
}
private:
FooX *impl;
};
FooVariant1<FooX1> bar;
bar.Met1Wrapper();
template<typename FooX>
class FooVariant2 : public FooX
{
};
FooVariant2<FooX1> bar;
bar.Met1();