【问题标题】:Calling the same function in many different classes在许多不同的类中调用相同的函数
【发布时间】:2017-10-24 10:36:34
【问题描述】:

为了简化我的代码,我希望使用可以存储多个对象的数组,然后可以调用这些对象中的函数。

我创建了许多具有(部分)相同成员函数的类。当然,这些功能有不同的实现。我希望将这些对象放在一个数组中,然后我可以遍历它来调用这些函数。

我有许多传感器,我们称它们为 Sensor1、Sensor2 和 Sensor3。它们都有一个名为 readSensor() 的函数和一个名为 sensorData() 的函数。 (第一个读取传感器,第二个返回一行 html - 在我的实际软件中,大约有 10-12 个传感器和 4 个这样的功能,因此我希望简化代码并使添加传感器更容易)。

所以我想做的是这样的:

Sensor1 sensor1;
Sensor2 sensor2;
Sensor3 sensor3;
byte nSensors = 3;

(type?) *sensorList[nSensors] // list of pointers to the sensors - don't know how to declare this.

void setup() { // yes, this is for Arduino.
  sensorList[0] = &sensor1; // store the pointers to the class objects.
  sensorList[1] = &sensor2;
  sensorList[2] = &sensor3;
}

void readSensors () {
  for (int i=1, i<nSnesors, i++) {
    sensorList[i]->readSensor();
  }
}

这样我就可以读取所有传感器,而不必写出所有传感器,并且希望我不会忘记任何一个。使代码更短,我可以在一个地方添加传感器。该数组仅用于所有传感器具有的功能(尽管在不同的实现中名称相同——毕竟这是不同的传感器)。这些对象也有一些特定于传感器的函数,需要时直接调用。

这可能吗?如果有,怎么做?

【问题讨论】:

  • 可能是传感器接口(基类)?

标签: c++ arrays class pointers arduino


【解决方案1】:

您可以简单地使用运行时多态性来完成这项工作。

例子:

class SensorBase
{   
    public:
    virtual void readSensor() = 0;
    virtual void getData(char*) = 0;
};  

class Sensor1: public SensorBase
{   
    void readSensor() { std::cout << "read for Sensor1 called" << std::endl; }
    void getData(char* ptr) { std::cout << "get for Sensor1 called" << std::endl; }
};  

class Sensor2: public SensorBase
{   
    void readSensor() { std::cout << "read for Sensor2 called" << std::endl; }
    void getData(char* ptr) { std::cout << "get for Sensor2 called" << std::endl; }
};  

// Static allocate objects, new is not a good idea for small embedded devices 
// cause of significant overhead. Global objects are typically a design problem,
// but small embedded systems have different requirements ;)

Sensor1 sensor1;
Sensor2 sensor2;

// lets have array to objects, statically allocated
SensorBase* arr[] = { &sensor1, &sensor2 };


int main()
{   
    char htmlString[256];

    for ( auto ptr: arr )
    {   
        ptr->readSensor();
        ptr->getData( htmlString );
    }   
}

您必须根据需要删除示例函数的内容。 std::cout 在这里仅用于让应用程序以可见的输出运行,作为事情如何工作的示例。

您在代码中使用了setup 方法。这在更大的系统上可能是一个好主意,但在 avr 上却不是!如果您像我给定的示例中那样使用静态分配,您的代码将更小更快。如果您给编译器一些提示以将您的一些数据字段或类存储在闪存中,您可以更快地加速它。对于该主题,请考虑#include &lt;avr/pgmspace.h&gt;

也许您必须使用constexpr 构造函数编写您的类才能将数据存储在闪存中。使用虚方法必须注意:gcc 不能将它们存储在闪存中。这是一个非常古老的错误/设计问题,浪费了您小型设备的大量内存。切换到 arm 设备的原因之一!见https://gcc.gnu.org/bugzilla/show_bug.cgi?id=43745。如果您的代码中需要大量多态类,这会使 avr gcc 无法使用。这个错误不会被修复!

【讨论】:

  • setup() 和 loop() 是我使用的 Arduino IDE 的默认方式 - 代码在 ESP8266 上运行,因此大小不是什么大问题。这个解决方案看起来像我需要的 - 尝试了解正在发生的事情然后尝试一下(也因为这实际上是库类,使其再次变得更加复杂)。感谢您的快速回复!
  • @Wouter:如果您在某处定义了一个数组并填充了 setup 方法中的值,那么您的程序大小将增加闪存和内存使用量。所以我更喜欢小型嵌入式系统使用完全静态的全局定义。所有数据都将在 main 启动之前被复制,并且不需要编写额外的代码。这与 arduino 无关,而是变量中的数据如何以及何时有效。 c 库启动代码已经提供了必要的代码。因此,您无需为此编写自己的复制代码,如我的示例所示。
  • 已实施 - 完美运行,谢谢!在此过程中,它似乎从我的代码中减少了大约 10-20kB,这很好,尽管我有空间:我大约 370 kB,很高兴能达到 500 kB 以上(可以达到 1 MB,但随后很容易OTA 更新不再可能)。
【解决方案2】:

是的,这可以通过使用Polymorphism 来实现。

你可以定义一个基类(即Sensor)和子类(即Sensor1Sensor2Sensor3),其中Sensor声明了一个方法readSensor(),所有的3个子类类实现了这个方法,但是它们可以用不同的方式来实现。这样,您可以创建一个包含 Sensor 类型元素的数组,并在每个元素上调用此方法,然后调用子类的已实现方法。

仅供参考:如果您愿意,您也可以从子类方法中调用基类方法,以实现常见行为。

也可以查看此链接:tutorial

【讨论】:

    猜你喜欢
    • 2022-07-30
    • 1970-01-01
    • 2019-07-14
    • 2018-05-25
    • 1970-01-01
    • 2019-04-08
    • 1970-01-01
    • 2020-03-05
    • 1970-01-01
    相关资源
    最近更新 更多