【发布时间】: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;
};
我的目标是满足以下要求:
- 统一使用两种类型的模拟输入
- 有机会创建 UnipolarAnalogInput 或 BipolarAnalogInput 的实例 基于用户在编译时已知的 Adc 配置
- 有机会在 for 循环迭代中创建实例
- 有适合嵌入式系统的实现
这是我的想法
就要求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