C++:条件继承是否可能?

13

我正在进行一个微处理器(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继承。我在这里做错了吗?还是有其他解决这个问题的方法?


5
在包含“Foo.h”的每个翻译单元(.cpp + 包含的头文件)中定义“USE_BASIC”,然后才能使用“#include <Foo.h>”指令。考虑使用编译器开关(自动在每个翻译单元中声明“USE_BASIC”)或将“#define”放在头文件中。 - dyp
1
@Named 我不同意。头文件没什么特别的,楼主展示了在包含头文件之前定义 USE_BASIC 的例子。编译器在cpp上运行,因此预处理器首先看到定义,然后再包含头文件(在楼主的例子中)。 - dyp
我无法理解-1。 - Ian Medeiros
4个回答

29

一个更加简洁的解决方案是使用模板:让编译器根据模板参数选择基类。

这里有一个例子:

 #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!

那是一种实现的方式。但有更好的方法。特别是,我会按照以下方式设计类模板,其中模板参数将作为基类。这将是更灵活的设计。

 template<typename Base>
 class Foo : public Base
 {
      //your code
 };

只要BasicAdvanced任何其他类都支持Foo及其使用所需的功能,您可以将其用作基类:

 Foo<Advanced>  fooWithAdvanced;
 Foo<Basic>     fooWithBasic;
 Foo<OtherBase> fooWithOtherBase;

希望这有所帮助。


3
谢谢!了解这些方法很不错,虽然可能不适合我的情况,不确定将模板添加到微处理器中是否会带来更多好处还是坏处... - Xun Yang
@XunYang:你说的“微处理器”是指什么?你是不是想说预处理器?如果是,那么在使用模板时就不需要使用预处理器。 - Nawaz
不,它是在Arduino上运行的,所以这算是一种嵌入式系统。 - Xun Yang
1
@XunYang:我认为在Arduino中使用模板不会引起任何问题,因为一旦类模板被实例化,它就变成了像任何其他普通类一样。 - Nawaz
4
模板(templates)不是Arduino编译器的默认语言特性,所以我需要引入另一个第三方库来使用模板,这将占用更多已经达到极限的存储空间...不过也许在下一个项目中值得一试 :) - Xun Yang

2

这是图书馆供应商经常面临的基本配置问题。 对于小型项目,只需在foo.h头文件中适当地#define USE_BASIC即可。 对于具有许多配置选项的大型项目,您可能需要转到配置文件,并将其#include在每个库头文件中,并在其中定义适当的内容。 在这种情况下,我会在配置标题中完成所有选择:

// uncomment to use `Basic` throughout:
// #define USE_BASIC
#ifdef USE_BASIC
typedef Basic FooBase;
#else
typedef Advanced FooBase;
#endif

1
我确定你是想要 typedef Basic FooBase; 而不是 typedef FooBase Basic; 另一个 typedef 也是一样。 - Nawaz
@Nawaz - 是的,谢谢。不知道我怎么会做出那么愚蠢的事情。已修复。 - Pete Becker

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

1
另一种解决方案是避免继承,使用像 策略 这样提供更大灵活性的模式。这样,在运行时可以将 Foo 的行为从 Basic 更改为 Advanced

如果内存有限或间接引用影响性能太大,那可能是不可能的。 - dyp

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接