是否可以在不使用动态调度的情况下创建接口?
Is it possible to create an interface without using dynamic dispatch?
背景
我正在用几个 'choices' 为嵌入式项目编写固件。例如,设备使用湿度传感器,但它支持多种不同的湿度传感器。
为了很好地实现这一点,我编写了一个(抽象的)基础 class 作为表示传感器的接口:
class HumiditySensor {
public:
virtual void readSample() = 0;
virtual double getHumidity() const = 0;
virtual double getTemperature() const = 0;
};
现在,不同的特定传感器可以继承这个基础class并实现纯虚拟方法。
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;
};
在我代码的其他部分,我可以只'ask for'一个(指向)HumiditySensor
的(指针)而不关心它是什么类型的传感器,或者它是如何实现的,因为它们公开相同的公共接口。例如。在需要湿度传感器的 class 中:
class Humidistat {
private:
HumiditySensor &hs;
public:
Humidistat(HumiditySensor *hs);
}
基于配置常量,在 main.cpp
中,我将实例化两个传感器中的任何一个,并在 Humidistat
.
的实例化中传递指向它的指针
我的项目中还有几个这样的案例(不同显示器的多个可能的 UI 等)。
Problem/question
这一切都很好,但据我所知,这一切都在我的微控制器上占用了相当多的宝贵时间 flash/RAM,因为它使用了动态调度/运行-time 多态性。
但是,我要使用的两个派生 classes 中的哪一个原则上是固定的并且在编译时已知。因此,最好避免 运行 时间多态性的开销,但这可能吗?
因此,如果我理解正确的话,我想要的是静态(或编译时)多态性。我发现这可以通过 Curiously Recurring Template Pattern (CRTP) 来完成,但它看起来相当 convoluted/hacky 我想知道这是否真的是实现我想要的最简单的方法。
如果你想避免运行时多态性的代价,那么你必须依赖编译时多态性。编译时多态的工具是模板。
是的,模板可能更难使用;编译时间限制了可以做什么。您提到的 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
class,您只需指定具有 class 的 概念 某些成员。这主要是 STL 的定义方式。以前,此类概念已写入文档,但在 C++20 中,现在有一种以编程方式定义它们的方法——这在很大程度上是可选的,但可以带来一些好处。
你只有一个class,所以不存在定义上的多态性。您不需要继承、接口、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;
背景
我正在用几个 'choices' 为嵌入式项目编写固件。例如,设备使用湿度传感器,但它支持多种不同的湿度传感器。
为了很好地实现这一点,我编写了一个(抽象的)基础 class 作为表示传感器的接口:
class HumiditySensor {
public:
virtual void readSample() = 0;
virtual double getHumidity() const = 0;
virtual double getTemperature() const = 0;
};
现在,不同的特定传感器可以继承这个基础class并实现纯虚拟方法。
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;
};
在我代码的其他部分,我可以只'ask for'一个(指向)HumiditySensor
的(指针)而不关心它是什么类型的传感器,或者它是如何实现的,因为它们公开相同的公共接口。例如。在需要湿度传感器的 class 中:
class Humidistat {
private:
HumiditySensor &hs;
public:
Humidistat(HumiditySensor *hs);
}
基于配置常量,在 main.cpp
中,我将实例化两个传感器中的任何一个,并在 Humidistat
.
我的项目中还有几个这样的案例(不同显示器的多个可能的 UI 等)。
Problem/question
这一切都很好,但据我所知,这一切都在我的微控制器上占用了相当多的宝贵时间 flash/RAM,因为它使用了动态调度/运行-time 多态性。
但是,我要使用的两个派生 classes 中的哪一个原则上是固定的并且在编译时已知。因此,最好避免 运行 时间多态性的开销,但这可能吗?
因此,如果我理解正确的话,我想要的是静态(或编译时)多态性。我发现这可以通过 Curiously Recurring Template Pattern (CRTP) 来完成,但它看起来相当 convoluted/hacky 我想知道这是否真的是实现我想要的最简单的方法。
如果你想避免运行时多态性的代价,那么你必须依赖编译时多态性。编译时多态的工具是模板。
是的,模板可能更难使用;编译时间限制了可以做什么。您提到的 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
class,您只需指定具有 class 的 概念 某些成员。这主要是 STL 的定义方式。以前,此类概念已写入文档,但在 C++20 中,现在有一种以编程方式定义它们的方法——这在很大程度上是可选的,但可以带来一些好处。
你只有一个class,所以不存在定义上的多态性。您不需要继承、接口、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;