第13回 解答例

センサを配列でまとめて更新する

演習の解答例。まず自分で書いてから読むこと。

解答

#include <Arduino.h>

#include "GPS.hpp"
#include "IMU.hpp"
#include "Sensor.hpp"
#include "ToF.hpp"

IMU imu;
GPS gps;
ToF tof(6);

Sensor* sensors[] = {&imu, &gps, &tof};
const int SENSOR_COUNT = sizeof(sensors) / sizeof(sensors[0]);

void setup() {
    Serial.begin(115200);
}

void loop() {
    for (int i = 0; i < SENSOR_COUNT; i++) {
        sensors[i]->update();
        sensors[i]->print();
    }

    delay(1000);
}

センサを1種類追加したとき

ToFを追加するために変更が必要だったのは、次の2行だけである。

ToF tof(6);                                  // 追加
Sensor* sensors[] = {&imu, &gps, &tof};       // 1要素追加

loop()の中は1文字も変えていない。これがポリモーフィズムの効果である。

        loop()                ← Sensorの種類を知らない
          │
          ↓
      Sensor*                 ← 共通の約束ごと
          │
   ┌──────┼──────┐
   ↓      ↓      ↓
  IMU    GPS    ToF           ← 増えても loop() は無関係

もしポリモーフィズムを使わなかったら

// 良くない例
void loop() {
    imu.update();
    imu.print();

    gps.update();
    gps.print();

    tof.update();    // センサを増やすたびに loop() を直す
    tof.print();
}

センサが増えるたびにloop()が伸びていく。種類ごとにifで分岐するコードも同じ問題を抱える。

組み込みでの注意

仮想関数を使うと、次のコストがかかる。

  • 各オブジェクトに仮想関数テーブルへのポインタ(多くの環境で4バイト)が付く
  • 呼び出しが1段階間接的になる
  • コンパイラがインライン展開しにくくなる

センサ数個の制御では問題にならない。ただし「割り込みの中で何万回も呼ぶ」ような場所では測定してから判断する。

→ 第13回の本文に戻る