【问题标题】:How to exploit polymorphism on embedded systems?如何在嵌入式系统上利用多态性?
【发布时间】:2021-04-29 11:31:25
【问题描述】:

我一直在为 MCU 的 adc 外设开发 C++ 软件驱动程序。

连接到 adc 的各个模拟输入可以配置为在单极或双极模式下运行。为了在我的设计中反映这一事实,我决定通过 AnalogInput 抽象类对模拟输入进行建模,然后定义两个派生类。 UnipolarAnalogInput 用于单极模拟输入,BipolarAnalogInput 用于双极模拟输入。这两个类仅在getValue() 方法的实现上有所不同。

enum class Type
{
Unipolar,
Bipolar
};

class AnalogInput
{
public:

virtual float getValue() = 0; 

};

class UnipolarAnalogInput : public AnalogInput
{
public:

UnipolarAnalogInput(uint8_t _id, bool _enabled, Type _type);
bool isEnabled();
bool isReady();
float getValue(); 

private:

uint8_t id;
Type type;
bool enabled;
bool ready;
uint16_t raw_value;

};

class BipolarAnalogInput : public AnalogInput
{
public:

BipolarAnalogInput(uint8_t _id, bool _enabled, Type _type);
bool isEnabled();
bool isReady();
float getValue(); 

private:

uint8_t id;
Type type;
bool enabled;
bool ready;
uint16_t raw_value;

};

我的目标是满足以下要求:

  1. 统一使用两种类型的模拟输入
  2. 有机会创建 UnipolarAnalogInput 或 BipolarAnalogInput 的实例 基于用户在编译时已知的 Adc 配置
  3. 有机会在 for 循环迭代中创建实例
  4. 有适合嵌入式系统的实现

这是我的想法

就要求1而言。

理想状态是拥有AnalogInput analog_inputs[NO_ANALOG_INPUTS]。据我所理解 正确地,这在 C++ 中是不可能的。而不是我需要定义AnalogInput *analog_inputs[NO_ANALOG_INPUTS]

就要求2而言。

在我看来,除了嵌入式系统之外,其他系统的最佳解决方案是使用工厂方法设计模式,即在 AnalogInput 定义中

static AnalogInput* getInstance(Type type) {
    if(type == Unipolar) {
        // create instance of the UnipolarAnalogInput
    } else if(type == Bipolar) {
        // create instance of the BipolarAnalogInput
    }
}

在这里,我可能需要在某处为 UnipolarAnalogInput 实例和 BipolarAnalogInput 实例定义辅助数组,其中实例将由工厂方法分配,指向这些数组的指针将由 getInstance() 返回。由于存在辅助数组,这个解决方案在我看来非常麻烦。

就要求 3.

for(uint8_t input = 0; input < NO_ANALOG_INPUTS; input++) {
    analog_inputs[input] = AnalogInput::getInstance(AdcConfig->getInputType(input));
}

就要求 4.

在这里我想说我上面的建议也适用于嵌入式系统 因为该解决方案避免使用标准的new 运算符。问号是虚拟的 方法getValue()

我的问题是辅助数组的存在是否不可避免?

【问题讨论】:

  • 您可能有兴趣查找static polymorphism。 HAL 配置应该在编译时进行,通常不需要虚拟多态性。也在这里:stackoverflow.com/questions/4173254/…
  • "你觉得...怎么样?" 正在征求意见(就像问题的其余部分一样),所以离题了。 Q3 可能有一些优点,但你可以用一个更短的问题来问这个问题(我可能会费心去阅读,因为我没有免费工作那么努力 ;-))。我认为“利用”可能是错误的词;它建议以一种被认为不是其预期用途的方式使用某些东西 - 你没有这样做,它只是多态性。
  • 我没有(还)发布答案,因为它目前太宽泛 IMO,征求意见并且缺乏重点。 w.r,t.Q3。但是,您可以拥有一个内存块并使用placement new 实例化其中的任何对象,而不是每个变体的两个单独的池(数组或其他)。
  • 您要解决的实际问题是什么?对我来说,问题不是“我如何实现我的驱动程序的两种不同行为”,而是“我如何创建适合我的工厂模式的东西”。首先,您需要问自己工厂模式在低级硬件驱动程序中的意义。例如,您如何处理 ADC 读取和调用者之间的重新进入。 ADC 是轮询、基于中断还是 DMA?这是非常基本的东西,这段代码甚至没有解决。
  • 通常应该避免使用 C++(尤其是嵌入式)的众多原因之一是,它往往会经常将您送入元编程地狱的陷阱门。如果您发现自己在编写各种“适配器”或接口以适应代码中的其他接口,那么您可能已经到了那里。摆脱它的唯一方法是剥离所有抽象层,直到只剩下一个对应用程序真正有意义的抽象层。这些设计方面不容易做到正确,这是非常合格的工作。如果你弄错了,C++ 往往会把你的整条腿都炸掉。

标签: c++ oop design-patterns polymorphism embedded


【解决方案1】:

您所说的“辅助数组”主要用于内存管理,即您需要选择存储对象的内存。它也是一个接口 - 数组是您访问 ADC 的方式。

您可以将对象存储在堆或(全局)数据段中 - 对象数组实现后者(您也可以创建全局变量,每个 ADC 一个,这是一个更糟糕的解决方案)。如果编译器具有在编译期间分配内存所需的所有信息,则通常是首选方法。但是 - 正如您所注意到的 - 使用静态分配的对象实现多态性变得相当烦人。

另一种方法是将它们保存在堆中。如果您在启动时分配堆内存并永久保留它,这在嵌入式系统中通常是完全可以接受的(即永远不要尝试释放或重新使用这部分堆,这会带来碎片风险)。这确实是做多态事物的唯一人道方式,尤其是对象实例化。

如果您不喜欢数组,请使用其他一些存储方法 - 链表、全局变量等。但是您需要通过指针(或引用,它也是指针)访问对象才能使多态性起作用。而数组是一个简单的概念,为什么不用呢?

【讨论】:

    猜你喜欢
    • 2015-03-11
    • 1970-01-01
    • 2010-09-15
    • 1970-01-01
    • 2014-01-28
    • 1970-01-01
    • 1970-01-01
    • 2011-04-15
    • 2014-10-23
    相关资源
    最近更新 更多