我正在开发一个微处理器(Arduino)项目。我的库Foo
继承自现有库Basic
。后来我将Basic
的功能扩展到了另一个类Advanced
。但是,Advanced
使硬件更难延伸,使得已经制作的一个演示无法使用。
我在想的是:
class Foo:
#ifndef USE_BASIC
public Advanced
#else
public Basic
#endif
{
...
}
并将#define USE_BASIC
放入我的演示代码中:
#define USE_BASIC
#include <Foo.h>
然而,Foo不是从Basic继承的。我在这做错了吗?或者,如果有其他方法可以解决这个问题?
答案 0 :(得分:16)
更简洁的解决方案是使用模板:让编译器根据模板参数选择基类。
以下是一个例子:
#include <type_traits> //for std::conditional
//here you go with your own class
template<bool UseAdvanced>
class Foo : public std::conditional<UseAdvanced, Advanced, Basic>::type
{
//your code
};
以下是您将如何使用此课程:
Foo<true> fooWithAdvanced; //it uses Advanced as base class
Foo<false> fooWithBasic; //it uses Basic as base class!
那是一种方法。但有更好的方法。特别是,我将按以下方式设计类模板,其中模板参数将充当 base 类。这将是更灵活的设计。
template<typename Base>
class Foo : public Base
{
//your code
};
所以你可以使用Basic
,Advanced
或任何其他类作为基类,只要它支持Foo
及其所需的功能。用法:
Foo<Advanced> fooWithAdvanced;
Foo<Basic> fooWithBasic;
Foo<OtherBase> fooWithOtherBase;
希望有所帮助。
答案 1 :(得分:2)
这是库供应商不断面临的基本配置问题。对于小型项目,只需在#define
标题中USE_BASIC
foo.h
。对于具有大量配置选项的大型项目,您可能希望转到在每个库头中获取#include
d的配置文件,并在那里定义适当的内容。在这种情况下,我会在配置标题中进行所有选择:
// uncomment to use `Basic` throughout:
// #define USE_BASIC
#ifdef USE_BASIC
typedef Basic FooBase;
#else
typedef Advanced FooBase;
#endif
答案 2 :(得分:1)
另一个解决方案是避免继承并使用Strategy等提供更多灵活性的模式。因此,您可以在运行时将Foo的行为从Basic
更改为Advanced
。
答案 3 :(得分:1)
有些人提出了模式策略。 如果您的选择是在编译期间,则应该更好地使用基于策略的设计: http://en.wikipedia.org/wiki/Policy-based_design
这与您的设计大致相同,但您使用模板:
template <class Base> class YourClass : public base {
...
};
使用时:
#ifdef BASIC
typedef YourFinalClass Yourclass<Basic>;
#else
typedef YourFinalClass Yourclass<Advanced>;
#endif