如何在嵌入式系统上利用多态性?
How to exploit polymorphism on embedded systems?
一直在开发MCU的adc外设的C++软件驱动。
连接到 adc 的各个模拟输入可以配置为在单极或双极模式下运行。为了在我的设计中反映这一事实,我决定通过 AnalogInput
抽象 class 对模拟输入建模,然后定义两个派生的 classes。 UnipolarAnalogInput
用于单极模拟输入,BipolarAnalogInput
用于双极模拟输入。这两个 class 仅在 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
define
中
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()
.
我的问题是辅助阵列的存在是否不可避免?
你所说的“辅助数组”主要用于内存管理,即你需要选择内存来存储你的对象。它也是一个接口 - 数组是你访问 ADC 的方式。
您可以将对象存储在堆或(全局)数据段中 - 对象数组实现后者(您还可以创建全局变量,每个 ADC 一个,这是一个更糟糕的解决方案)。如果编译器拥有在编译期间分配内存所需的所有信息,则它通常是首选方法。然而 - 正如您所注意到的 - 使用静态分配的对象来实现多态性变得相当烦人。
另一种方法是将它们保存在堆中。这在嵌入式系统中通常是完全可以接受的,如果您在启动时分配堆内存并永久保留它(即永远不要尝试释放或重新使用这部分堆,这会有碎片化的风险)。这真的是唯一人道的方式来做多态的东西,尤其是对象实例化。
如果您不喜欢数组,请使用其他一些存储方法 - 链表、全局变量等等。但是您需要通过指针(或引用,也是指针)访问对象,多态性才能发挥作用。数组是一个简单的概念,为什么不使用它们呢?
一直在开发MCU的adc外设的C++软件驱动。
连接到 adc 的各个模拟输入可以配置为在单极或双极模式下运行。为了在我的设计中反映这一事实,我决定通过 AnalogInput
抽象 class 对模拟输入建模,然后定义两个派生的 classes。 UnipolarAnalogInput
用于单极模拟输入,BipolarAnalogInput
用于双极模拟输入。这两个 class 仅在 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
define
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()
.
我的问题是辅助阵列的存在是否不可避免?
你所说的“辅助数组”主要用于内存管理,即你需要选择内存来存储你的对象。它也是一个接口 - 数组是你访问 ADC 的方式。
您可以将对象存储在堆或(全局)数据段中 - 对象数组实现后者(您还可以创建全局变量,每个 ADC 一个,这是一个更糟糕的解决方案)。如果编译器拥有在编译期间分配内存所需的所有信息,则它通常是首选方法。然而 - 正如您所注意到的 - 使用静态分配的对象来实现多态性变得相当烦人。
另一种方法是将它们保存在堆中。这在嵌入式系统中通常是完全可以接受的,如果您在启动时分配堆内存并永久保留它(即永远不要尝试释放或重新使用这部分堆,这会有碎片化的风险)。这真的是唯一人道的方式来做多态的东西,尤其是对象实例化。
如果您不喜欢数组,请使用其他一些存储方法 - 链表、全局变量等等。但是您需要通过指针(或引用,也是指针)访问对象,多态性才能发挥作用。数组是一个简单的概念,为什么不使用它们呢?