是否可以在不使用动态调度的情况下创建接口



背景

我正在为一个嵌入式项目编写固件,其中有几个"选项"。例如,该设备使用湿度传感器,但它支持多个不同的湿度传感器。

为了很好地实现这一点,我编写了一个(抽象)基类作为表示传感器的接口:

class HumiditySensor {
public:
virtual void readSample() = 0;
virtual double getHumidity() const = 0;
virtual double getTemperature() const = 0;
};

现在,不同的特定传感器可以继承这个基类并实现纯虚拟方法。

class SHTHumiditySensor : public HumiditySensor {
private:
SHTSensor &sht;
public:
explicit SHTHumiditySensor(SHTSensor *sht);
void readSample() override;
double getHumidity() const override;
double getTemperature() const override;
};
class DHTHumiditySensor : public HumiditySensor {
private:
DHT &dht;
public:
explicit DHTHumiditySensor(DHT *dht);
void readSample() override;
double getHumidity() const override;
double getTemperature() const override;
};

在我代码的其他部分中,我可以"请求"一个(指向)HumiditySensor的指针,而不关心它是什么类型的传感器,也不关心它如何实现,因为它们公开了相同的公共接口。例如,在需要湿度传感器的类别中:

class Humidistat {
private:
HumiditySensor &hs;
public:
Humidistat(HumiditySensor *hs);
}

基于配置常量,在main.cpp中,我将实例化两个传感器中的任何一个,并在Humidistat的实例化中向其传递指针。

在我的项目中,我还有一些类似的案例(用于不同显示的多个可能的UI,等等)。

问题/问题

这一切都很好,但据我所知,这一切都需要我的微控制器上相当多宝贵的闪存/RAM,因为这使用了动态调度/运行时多态性。

然而,原则上,我将使用这两个派生类中的哪一个是固定的,并且在编译时是已知的。因此,避免运行时多态性的开销是很好的,但这可能吗?

因此,如果我理解正确的话,我想要的是静态(或编译时)多态性。我发现这可以用奇怪的递归模板模式(CRTP)来实现,但它看起来很复杂/很粗糙,我想知道这是否真的是实现我想要的最简单的方法。

如果您想避免运行时多态性的成本,那么您必须依赖编译时多态性。编译时多态性的工具是模板。

是的,模板可能更难使用;编译时间限制了可以做的事情。您提到的CRTP在某些用例中是一种有用的技术,但我认为在所示的示例中没有必要使用它。

在最简单的情况下,您可以使用这样的模板:

template <class Sensor>
class HumiditySensor {
Sensor &sht;
// ...
};
// If needed:
// using SHTHumiditySensor = HumiditySensor<SHTSensor>;
// using DHTHumiditySensor = HumiditySensor<DHT>;
template <class Sensor>
class Humidistat {
HumiditySensor<Sensor> &hs;
// ...
}

要指定如何定义此类模板中可用的Sensor类,只需指定具有特定成员的类的概念。这在很大程度上是STL的定义方式。以前,这些概念都是编写文档的,但在C++20中,现在有了一种以编程方式定义它们的方法——这在很大程度上是可选的,但也有一些好处。

您只有一个类,因此根据定义不存在多态性。您不需要继承、接口、CRTP或任何此类技巧。

class SHTHumiditySensor /* no ': public HumiditySensor' needed */ {
private:
SHTSensor &sht;
public:
explicit SHTHumiditySensor(SHTSensor *sht);
void readSample() /* no virtual, no override */;
double getHumidity() const /* no virtual, no override */;
double getTemperature() const /* no virtual, no override */;
};
using HumiditySensor = SHTHumiditySensor;

最新更新